Некоторые файлы повреждены SQL Server FileStream - PullRequest
4 голосов
/ 07 июля 2010

Я сохраняю файлы в базе данных SQL Server 2008 (Express) с помощью FILESTREAM, проблема в том, что некоторые файлы, похоже, повреждаются в процессе.

Например, если я сохраняюДокумент Word или Excel в одном из более новых форматов (docx или xslx), а затем при попытке открыть файл выдает сообщение об ошибке, в котором говорится, что данные повреждены, и я хотел бы, чтобы 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 ]

5 голосов
/ 07 июля 2010

Ваш код чтения неверен:

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

        }

Если bytesRead меньше, чем buffer.Length, вы все равно добавляете весь буфер в attachchementBytes.Таким образом, вы всегда портите возвращаемый документ, добавляя мусор в конце последней записи буфера bytesRead.

Кроме этого, позвольте мне получить действительно WTF-момент.Чтение потока как List<byte> ??Да брось!Во-первых, я не вижу причины, по которой вам нужно начинать с промежуточного хранения в памяти.Вы можете просто читать буфер по буферу и записывать каждый буфер прямо в outputStream.Во-вторых, если вы должны использовать промежуточное хранилище в памяти, используйте MemoryStream, а не List<byte>.

1 голос
/ 08 июля 2010

Несколько месяцев назад у меня была точная проблема , и я понял, что добавляю дополнительный байт в конец файла при чтении его из FILESTREAM.

...