某些文件被SQL Server FileStream损坏

时间:2010-07-06 22:07:46

标签: c# sql-server-2008 filestream

我使用FILESTREAM将文件保存到SQL Server 2008(Express)数据库,我遇到的麻烦是某些文件似乎在此过程中被破坏。

例如,如果我以一种较新的格式(docx或xslx)保存单词或excel文档,那么当我尝试打开文件时,我收到一条错误消息,说明数据已损坏且我喜欢word / excel尝试恢复它,如果我点击是办公室能够'恢复'数据并以兼容模式打开文件。

但是,如果我首先压缩文件然后解压缩内容后我可以毫无问题地打开文件。奇怪的是如果我将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();

2 个答案:

答案 0 :(得分:5)

您的阅读代码不正确:

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

        }

如果bytesRead小于buffer.Length,您仍然将整个缓冲区添加到attachementBytes。因此,您总是通过在最后一个缓冲区postRead。

的末尾添加任何垃圾来破坏返回的文档

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

答案 1 :(得分:1)

几个月前我有exact problem,并且发现当我从FILESTREAM读取它时,我在文件的末尾添加了一个额外的字节。