2010-07-06 2 views
4

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

Например, если я сохраняю слово или документ excel в одном из новых форматов (docx или xslx), то при попытке открыть файл я получаю сообщение об ошибке, сообщающее, что данные повреждены и мне хотелось бы сложить слова/excel, чтобы попытаться восстановить его. Если я нажму «да», он сможет «восстановить» данные и открыть файл в режиме совместимости.

Однако, если я сначала заархивирую файл, а затем извлекая содержимое, я могу открыть файл без проблем. Странно Если я сохраню mp3-файл в базе данных, тогда у меня есть обратная проблема, я могу открыть файл без проблем, но если бы я сохранил zipped-версию mp3, я даже не смог бы извлечь содержимое этого почтового индекса. Когда я попытался сохранить файл в формате 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(); 
+0

Возможно ли, что повреждение происходит при обработке клиентом ваших вставок? Например. преждевременное усечение, или использовать использование аргумента varchar() vs. nvarchar(), переданного SQL, или char vs. binary? Woudl вы хотите опубликовать код, который вы используете для загрузки контента в потоки и код, используемый для доступа к файловому потоку? –

+0

Спасибо за ответ, я отредактировал мой вопрос с моим кодом. Я не уверен, что вы подразумеваете под неправильным аргументом типа, поле в sql-сервере имеет тип Varbinary (max) FILESTREAM). – Jack

ответ

5

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

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

     } 

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

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

+0

Спасибо, что сделал трюк. Я изменил его так, что я пишу непосредственно из потока ввода в выходной поток. – Jack

+1

И игнорируя на данный момент, что он отбрасывает первый buffer.length байтов во время чтения также (bytesRead = ..., while (bytesRead> 0), bytesRead = ...) –

+0

Интересно, что я недавно читал [ Jon Skeet's] (http://stackoverflow.com/users/22656/Jon-Skeet) [C# in Depth] (http://csharpindepth.com/), и он упоминает (стр. 86), как с генериками во многих отношениях " Список 'действительно ведет себя как' MemoryStream'.Я не говорю, что это был правильный выбор в этом случае, и единственное, что я могу сказать в моей защите здесь, это то, что когда я его писал, я был намного более неопытным, и если я правильно помню, я основывал часть своего исходного кода от фрагмента, который я читал в Интернете, который использовал список. – Jack

1

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

+1

Я прочитал ваш пост, и я нашел его информативным, поскольку я было интересно, почему у меня возникла проблема с конкретными форматами файлов (и, особенно, почему старые форматы Office, похоже, не повреждались). – Jack