【问题标题】:C# Extract File From varbinary(max) field - file is corruptedC# 从 varbinary(max) 字段中提取文件 - 文件已损坏
【发布时间】:2020-08-21 09:43:25
【问题描述】:

问题:我有一个数据库,它在 varbinary(max) 列中有文件。我知道文件的类型,因为有一个扩展字段。我需要提取数据并将文件保存到文件系统。我没有关于如何存储数据的大量信息。在 DB 中看起来像这样:

我尝试了几种不同的方法来提取此值并将其保存为文件。我可以很容易地从数据中创建文件,但它们总是被损坏。打开 PDF 时收到此消息。

如果是 excel 文件,我会收到类似类型的消息。 (xls) 我尝试了以下方法来访问数据,前两种方法使用 SQL 阅读器,带或不带 commandBehaviour.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....等

感谢您的帮助,谢谢!

【问题讨论】:

    标签: arrays filestream varbinarymax


    【解决方案1】:

    我想通了 - 基本上是通过粗暴的反复试验。 根据我在记事本中打开时在文件中找到的数据,我提取了 base64 字符串并将其转换为文件。所以我的过程是,从数据库中获取字节,提取 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);
         }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-12-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-29
      • 1970-01-01
      • 2020-12-29
      • 1970-01-01
      • 2015-03-15
      相关资源
      最近更新 更多