2010-03-02 55 views
1

我已經寫了兩個小方法來保存和加載.docx(以及其他類型的文件)文件到數據庫(SERVER 2005/2008與VarBinary(MAX)列)。一切似乎都很好,但是當我讀取文件時,它創建了,但Word抱怨它已損壞,但最終將其中的所有內容都打開。代碼有什麼問題?從C#的SQLServer 2005/2008讀取/寫入文件時會損壞文件嗎?

public static void databaseFileRead(string varID, string varPathToNewLocation) { 
     const int bufferSize = 100; 
     byte[] outByte = new byte[bufferSize]; 
     using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) 
     using (var sqlQuery = new SqlCommand(@"SELECT [RaportPlik] FROM [dbo].[Raporty] WHERE [RaportID] = @varID", varConnection)) { 
      sqlQuery.Parameters.AddWithValue("@varID", varID); 
      using (var sqlQueryResult = sqlQuery.ExecuteReader(CommandBehavior.Default)) 
       while (sqlQueryResult != null && sqlQueryResult.Read()) { 
        using (FileStream stream = new FileStream(varPathToNewLocation, FileMode.OpenOrCreate, FileAccess.Write)) { 
         using (BinaryWriter writer = new BinaryWriter(stream)) { 
          long startIndex = 0; 
          long retval = sqlQueryResult.GetBytes(0, startIndex, outByte, 0, bufferSize); 
          while (retval == bufferSize) { 
           writer.Write(outByte); 
           writer.Flush(); 
           startIndex += bufferSize; 
           retval = sqlQueryResult.GetBytes(0, startIndex, outByte, 0, bufferSize); 
          } 
          writer.Write(outByte, 0, (int) retval - 1); 
          writer.Flush(); 
          writer.Close(); 
         } 
         stream.Close(); 
        } 
       } 
     } 
    } 
    public static void databaseFilePut(string varFilePath) { 
     FileStream stream = new FileStream(varFilePath, FileMode.Open, FileAccess.Read); 
     BinaryReader reader = new BinaryReader(stream); 
     byte[] file = reader.ReadBytes((int) stream.Length); 
     reader.Close(); 
     stream.Close(); 
     using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) 
     using (var sqlWrite = new SqlCommand("INSERT INTO Raporty (RaportPlik) Values(@File)", varConnection)) { 
      sqlWrite.Parameters.Add("@File", SqlDbType.Binary, file.Length).Value = file; 
      sqlWrite.ExecuteNonQuery(); 
     } 
    } 

編輯:

我已經改變了代碼,每建議,有4096緩衝區大小,但它仍然不是一個去。

原始文件的大小爲48,0 KB(字節數:49 225),磁盤大小爲52,0 KB(字節數:53 248)(Win 7屬性顯示此項)。雖然從數據庫取出的文件大小爲52,0 KB(字節數:53 248),磁盤大小爲52,0 KB(字節數:53 248)。

這一切都發生在Win 7 x64的開發機器上,我已經卸載了Eset Smart Security。

EDIT2:

所以我增加了一個「辦法」從webpage做到這一點,似乎這樣的伎倆。唯一明顯的區別是缺少使用BinaryWriter和Byte [] blob有點奇怪的定義。 奇怪是不是?

public static void databaseFileRead(string varID, string varPathToNewLocation) { 
     const int bufferSize = 4096; 
     byte[] outByte = new byte[bufferSize]; 
     using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) 
     using (var sqlQuery = new SqlCommand(@"SELECT [RaportPlik] FROM [dbo].[Raporty] WHERE [RaportID] = @varID", varConnection)) { 
      sqlQuery.Parameters.AddWithValue("@varID", varID); 
      using (var sqlQueryResult = sqlQuery.ExecuteReader()) 
       while (sqlQueryResult != null && sqlQueryResult.Read()) { 
        using (FileStream stream = new FileStream(varPathToNewLocation, FileMode.OpenOrCreate, FileAccess.Write)) 
        using (BinaryWriter writer = new BinaryWriter(stream)) { 
         long startIndex = 0; 
         long retval = sqlQueryResult.GetBytes(0, startIndex, outByte, 0, bufferSize); 
         while (retval > 0) { 
          writer.Write(outByte); 
          writer.Flush(); 
          startIndex += retval; 
          retval = sqlQueryResult.GetBytes(0, startIndex, outByte, 0, bufferSize); 
         } 
        } 
       } 
     } 
     Byte[] blob = null; 
     FileStream fs = null; 
     const string sConn = Locale.sqlDataConnectionDetailsDZP; 
     SqlConnection conn = new SqlConnection(sConn); 
     SqlCommand cmd = new SqlCommand("SELECT [RaportPlik] FROM [dbo].[Raporty] WHERE [RaportID] = " + varID, conn); 
     conn.Open(); 
     SqlDataReader sdr = cmd.ExecuteReader(); 
     sdr.Read(); 
     blob = new Byte[(sdr.GetBytes(0, 0, null, 0, int.MaxValue))]; 
     sdr.GetBytes(0, 0, blob, 0, blob.Length); 
     sdr.Close(); 
     conn.Close(); 
     fs = new FileStream("c:\\Builder.docx", FileMode.Create, FileAccess.Write); 
     fs.Write(blob, 0, blob.Length); 
     fs.Close(); 
    } 

回答

0

以下代碼似乎無錯地工作。跳過使用BinaryWriter使其正確寫入文件。爲什麼使用BinaryWriter正在破解我不知道的文件:-)

public static void databaseFileRead(string varID, string varPathToNewLocation) { 
     using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetailsDZP)) 
     using (var sqlQuery = new SqlCommand(@"SELECT [RaportPlik] FROM [dbo].[Raporty] WHERE [RaportID] = @varID", varConnection)) { 
      sqlQuery.Parameters.AddWithValue("@varID", varID); 
      using (var sqlQueryResult = sqlQuery.ExecuteReader()) { 
       if (sqlQueryResult != null) { 
        sqlQueryResult.Read(); 
        byte[] blob = new Byte[(sqlQueryResult.GetBytes(0, 0, null, 0, int.MaxValue))]; 
        sqlQueryResult.GetBytes(0, 0, blob, 0, blob.Length); 
        using (FileStream fs = new FileStream(varPathToNewLocation, FileMode.Create, FileAccess.Write)) { 
         fs.Write(blob, 0, blob.Length); 
        } 
       } 

      } 
     } 
    } 
1

代碼可能沒有什麼問題。我會看看你在該服務器上安裝了哪些病毒掃描軟件,並及時卸載它。我已經看到諾頓和邁克菲都沒有表示他們改變了任何東西的clobber文件。

+0

服務器上沒有防病毒/防火牆。 – MadBoy 2010-03-02 17:37:36

4

您的databaseFileRead方法有錯誤。

想想看:你有100個字節的緩衝區大小(真的小 - 我建議4096字節最低!)和你的循環是這樣的:

while (retval == bufferSize) 
{ 
    writer.Write(outByte); 
    writer.Flush(); 
    startIndex += bufferSize; 
    retval = sqlQueryResult.GetBytes(0, startIndex, outByte, 0, bufferSize); 
} 

OK,這工作得很好,直到有在您的文件中只剩下73個字節要處理 - 在這種情況下,最後一次調用

retval = sqlQueryResult.GetBytes(0,startIndex,outByte,0,bufferSize);

將在retval中返回「73」,因爲那是而不是== bufferSize,您將中止。所以用這個,你總是跳過最後幾個字節.....

你需要做的是這樣的:

while (retval > 0) 
{ 
    writer.Write(outByte); 
    writer.Flush(); 
    startIndex += retval; 
    retval = sqlQueryResult.GetBytes(0, startIndex, outByte, 0, bufferSize); 
} 

有了這個,讀的是最後73個字節時,你」你會得到retval=73,你會寫出最後73個字節,然後下一次調用sqlQueryResult應該返回retval=0,然後終止你的循環。

試試吧 - 我敢肯定這是造成這個錯誤的原因。

Marc

+0

我已經用你的代碼替換了它,但它仍然出錯。我已經將buffersize改爲4096。我還認爲'write.Write(outByte,0,(int)retval - 1);'正在處理缺少的73個字節。該代碼基於http://msdn.microsoft.com/en-us/library/87z0hy49%28VS.80%29.aspx – MadBoy 2010-03-02 18:08:10

+0

@madboy:同樣的錯誤?你有任何額外的信息?是磁盤上產生的文件大小的100倍。 4096字節 – 2010-03-02 18:11:22

+0

@madboy:是的,真的 - 我忽略了最後一個'writer.Write'聲明。是的,這將處理最後剩餘的字節... – 2010-03-02 18:12:42