c# - 某些文件被 SQL Server FileStream 损坏

标签 c# sql-server-2008 filestream

我正在使用 FILESTREAM 将文件保存到 SQL Server 2008 (Express) 数据库,我遇到的问题是某些文件似乎在这个过程中被损坏了。

例如,如果我以一种较新的格式(docx 或 xslx)保存一个 word 或 excel 文档,那么当我尝试打开该文件时,我收到一条错误消息,指出数据已损坏,我是否需要 word/excel 尝试恢复它,如果我单击是,office 能够“恢复”数据并以兼容模式打开文件。

但是,如果我先压缩文件,然后在提取内容后,我就可以毫无问题地打开文件。奇怪的是,如果我将一个 mp3 文件保存到数据库中,那么我就会遇到相反的问题,我可以毫无问题地打开该文件,但是如果我保存了 mp3 的压缩版本,我什至无法提取该 zip 的内容。当我尝试保存 pdf 或 power-point 文件时,我遇到了类似的问题(如果我先压缩它,我只能阅读 pdf,而我根本无法阅读 ppt)。

更新:这是我用来写入和读取数据库的代码

写入数据库:

SQL = "SELECT Attachment.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Activity " +
               "WHERE RowID = CAST(@RowID as uniqueidentifier)";
           transaction = connection.BeginTransaction();

           command.Transaction = transaction;
           command.CommandText = SQL;
           command.Parameters.Clear();
           command.Parameters.Add(rowIDParam);

           SqlDataReader readerFS = null;
           readerFS= command.ExecuteReader();

   string path = (string)readerFS[0].ToString();
   byte[] context = (byte[])readerFS[1];
   int length = context.Length;

   SqlFileStream targetStream = new SqlFileStream(path, context, FileAccess.Write);

         int blockSize = 1024 * 512; //half a megabyte
            byte[] buffer = new byte[blockSize];
            int bytesRead = sourceStream.Read(buffer, 0, buffer.Length);
            while (bytesRead > 0)
            {
                targetStream.Write(buffer, 0, bytesRead);
                bytesRead = sourceStream.Read(buffer, 0, buffer.Length);
            }

            targetStream.Close();
            sourceStream.Close();
            readerFS.Close();
            transaction.Commit();

阅读:

        SqlConnection connection = null;
        SqlTransaction transaction = null;

        try
        {
            connection = getConnection();
            connection.Open();
            transaction = connection.BeginTransaction();

            SQL = "SELECT Attachment.PathName(), + GET_FILESTREAM_TRANSACTION_CONTEXT() FROM Activity"
          +  " WHERE ActivityID = @ActivityID";


            SqlCommand command = new SqlCommand(SQL, connection);
            command.Transaction = transaction;

            command.Parameters.Add(new SqlParameter("ActivityID", activity.ActivityID));

            SqlDataReader reader = command.ExecuteReader();

            string path = (string)reader[0];
            byte[] context = (byte[])reader[1];
            int length = context.Length;
            reader.Close();

            SqlFileStream sourceStream = new SqlFileStream(path, context, FileAccess.Read);

            int blockSize = 1024 * 512; //half a megabyte
            byte[] buffer = new byte[blockSize];
           List<byte> attachmentBytes = new List<byte>();

            int bytesRead = sourceStream.Read(buffer, 0, buffer.Length);

            while (bytesRead > 0)
            {
                bytesRead = sourceStream.Read(buffer, 0, buffer.Length);
                foreach (byte b in buffer)
                {
                    attachmentBytes.Add(b);
                }

            }

            FileStream outputStream = File.Create(outputPath);

            foreach (byte b in attachmentBytes)
            {
                 byte[] barr = new byte[1];

                 barr[0] = b;

                 outputStream.Write(barr, 0, 1);
            }

            outputStream.Close();
            sourceStream.Close();
            command.Transaction.Commit();

最佳答案

您读取的代码不正确:

  while (bytesRead > 0)
        {
            bytesRead = sourceStream.Read(buffer, 0, buffer.Length);
            foreach (byte b in buffer)
            {
                attachmentBytes.Add(b);
            }

        }

如果 bytesRead 小于 buffer.Length,您仍将整个缓冲区添加到 attachementBytes。因此,您总是通过在字节读取后的最后一个缓冲区末尾添加任何垃圾来破坏返回的文档。

除此之外,请允许我有一个真正的 WTF 时刻。以 List<byte> 形式读取流??来吧!首先,我不明白为什么您需要先读入中间内存存储的原因。您可以简单地逐个读取缓冲区并将每个缓冲区直接写入 outputStream。其次,如果您必须使用中间内存存储,请使用 MemoryStream , 不是 List<byte> .

关于c# - 某些文件被 SQL Server FileStream 损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3190590/

相关文章:

Javascript 哈希原型(prototype)到 C#

c# - Entity Framework 不保存更改

sql - 如何为 db 中的所有表设置数据库审计规范

sql - 动态查询中的问题

sql-server - Sql Filestream 可以流式传输视频吗?

c# - 找不到 IAuthenticationManager 的对象引用

c# - 任何真正的 Silverlight 项目?

c# - 基于罗马数字拆分字符串 C#

Android-保存文件(输入和输出流)抛出异常(打开失败 : EINVAL (Invalid argument)) in Pre-lollipop devices

c# - 如何定期将 c# FileStream 刷新到磁盘?