问题:我有一个数据库,在varbinary(max)列中有文件。 我知道文件的类型,因为有一个扩展字段。 我需要将数据提取出来,并将文件保存到文件系统中。 我没有很多关于数据如何存储的信息。 它在DB中看起来是这样的。
我试过几种不同的方法来提取这个值并保存成文件 我可以很容易地从数据中创建文件,但它们总是被损坏。 当打开一个PDF时,我得到了这个消息。
如果是excel文件,我也会得到类似的消息。(xls)我试过以下方法来访问数据,前2种使用SQL阅读器,不管有没有命令Behaviour.sequentialAccess。 第三种使用SQL Substring。
byte[] data = (byte[])reader["Data"];
// OR
int ordinal = reader.GetOrdinal("Data");
long bufferSize = reader.GetBytes(ordinal, 0, null, 0, 0);
byte[] outbyte = new byte[bufferSize];
reader.GetBytes(ordinal, 0, outbyte, 0, (int)bufferSize);
// OR
public System.IO.Stream GetStream(AttachmentModel info)
{
var attachment = (AttachmentModel)info;
int start = 0;
int packetSize = 65535;
int length = packetSize;
byte[] data = new byte[info.length];
while (start < info.length)
{
length = Math.Min(packetSize, ((int)info.length - start));
byte[] buffer = repo.ReadAttachmentData(attachment.id, start, length);
buffer.CopyTo(data, start);
start += length;
}
return new MemoryStream(data);
}
// ReadAttachmentData method
public byte[] ReadAttachmentData(Guid attachmentID, int start, int length)
{
using (SqlConnection connection = GetOpenSqlConnection())
{
using (SqlCommand cmd = connection.CreateCommand())
{
byte[] buffer = null;
cmd.CommandText = @"SELECT SUBSTRING([Data], @start, @length) FROM myBlobTable WHERE [Attachment] = @attachmentID";
cmd.CommandType = CommandType.Text;
AddParamWithValue(cmd, "@start", DbType.Int32, start + 1); // index starts at 1
AddParamWithValue(cmd, "@length", DbType.Int32, length);
AddParamWithValue(cmd, "@attachmentID", DbType.Guid, attachmentID);
buffer = (byte[])cmd.ExecuteScalar();
return buffer;
}
}
}
private IDataParameter AddParamWithValue(SqlCommand cmd, string name, DbType type, object value)
{
IDbDataParameter param = cmd.CreateParameter();
param.ParameterName = name;
param.DbType = type;
param.Value = (value ?? DBNull.Value);
param.Size = 0;
param.Direction = ParameterDirection.Input;
cmd.Parameters.Add(param);
return param;
}
为了将数据保存到文件中,我试过。
System.IO.File.WriteAllBytes(fileName, byteArray);
// OR
using (Stream st = GetStream(att))
{
using (FileStream fs = new FileStream(att.filePath + "File1" + att.extension, FileMode.Create, FileAccess.Write))
{
st.CopyTo(fs);
st.Flush();
fs.Flush();
st.Close();
fs.Close();
}
};
// I tried using the deflate stream thinking maybe it was compressed.
using (Stream st = GetStream(attachment))
using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write))
{
st.CopyTo(fs);
st.Flush();
fs.Flush();
st.Close();
fs.Close();
}
我还试过在FileStream上使用缓冲区大小的选项。 我几乎试过了上述数据访问和数据保存方法的所有组合,但没有任何运气。
还有一个线索--如果我用记事本打开文件,数据看起来是这样的。
data:;base64,JVBERi0xLjQKJcfsj6IKNSAwIG9iago8PC9MZW5ndGg...等等,等等。
希望得到任何帮助,谢谢!
我想明白了 - 基本上是通过粗暴的试验和错误.基于数据,我发现在文件内,当我打开记事本,我提取base64字符串,并转换为一个文件。 所以我的过程是,从DB中获取字节,提取base64字符串,转换回字节,写入文件。
这样访问varbinary(max)文件。
using (SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
{
List<AttachmentModel> attachments = new List<AttachmentModel>();
while (reader.Read())
{
AttachmentModel att = new AttachmentModel();
int ordinal = reader.GetOrdinal("Data");
long bufferSize = reader.GetBytes(ordinal, 0, null, 0, 0);
byte[] outbyte = new byte[bufferSize];
reader.GetBytes(ordinal, 0, outbyte, 0, (int)bufferSize);
att.data = outbyte;
attachments.Add(att);
}
return attachments;
}
然后这样转换为文件
using (MemoryStream ms = new MemoryStream(att.data)) {
string fileContents;
using (StreamReader reader = new StreamReader(ms))
{
fileContents = reader.ReadToEnd();
List<string> arr = fileContents.Split(',').ToList<string>();
// convert base 64 string back to bytes
var myBytes = Convert.FromBase64String(arr[1]);
System.IO.File.WriteAllBytes(att.filePath + "File1" + att.extension, myBytes);
}
}