通过从 SQL 文件流中获取文件,使用 ICSharpCode.SharpZipLib.Zip 压缩文件

Compress the Files using ICSharpCode.SharpZipLib.Zip by fetching files from SQL File stream

我正在使用 ICSharpCode.SharpZipLib.Zip 压缩文件并下载 zip 文件,这里使用 SQL 文件流来存储任何类型的文件(任何数量的 GB)。 然后,我如何从 sql 文件流中压缩文件并下载... 我尝试了类似下面的方法,它抛出异常 "size was 845941, but I expected 16 at ICSharpCode.SharpZipLib.Zip.ZipOutputStream.CloseEntry()"。如何解决这个问题...

string zipFileName = "ZipName.zip";
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "fileName=" + zipFileName);
byte[] buffer = new byte[4096];
ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream);
zipOutputStream.SetLevel(3);

string cs = System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
foreach (Filec file1 in Files)
 {
   StreamModel model123 = new StreamModel();
   const string SelectTSql = @"
        SELECT FileData.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT(), FileType
         FROM MyFiles WHERE FileId = @FileId";

   using (TransactionScope ts = new TransactionScope())
    {
     using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(cs))
     {
      conn.Open();

      using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(SelectTSql, conn))
       {
        cmd.Parameters.Add("@FileId", System.Data.SqlDbType.Int).Value = Convert.ToInt32(file1.FileId);
        using (System.Data.SqlClient.SqlDataReader rdr = cmd.ExecuteReader())
         {
           rdr.Read();
           model123.serverPath = rdr.GetSqlString(0).Value;
           model123.serverTxn = rdr.GetSqlBinary(1).Value;
           model123.filetype = rdr.GetSqlString(2).Value;
           rdr.Close();
         }
        }
      }
 ZipEntry zipEntry = new ZipEntry(ZipEntry.CleanName(file1.FileName));
 zipEntry.Size = model123.serverTxn.Length;
 zipOutputStream.PutNextEntry(zipEntry);
 byte[] buffer3 = new byte[4096];
 using (System.Data.SqlTypes.SqlFileStream sfs = new System.Data.SqlTypes.SqlFileStream(model123.serverPath, model123.serverTxn, FileAccess.Read))
  {
    int bytesRead;
    while ((bytesRead = sfs.Read(buffer3, 0, buffer3.Length)) > 0)
      {
         zipOutputStream.Write(buffer3, 0, bytesRead);
      }
    sfs.Close();
  }
 zipOutputStream.CloseEntry(); // at this line throwing an exception.
 ts.Complete();
   }
}
zipOutputStream.Close();
Response.Flush();
Response.End();

理解了每一行代码后,我找到了解决方案..

1) "zipEntry.Size = model123.serverTxn.Length;" 此行导致异常 "size was 845941, but I expected 16"..因为 "model123.serverTxn.Length" 不是文件的完整大小,所以我将其更改为 "sfs.Length" 这是 SqlFileStream 的长度。

2) zipOutputStream 级别设置为最大值 "zipOutputStream.SetLevel(9)" 因为,我在这里压缩大文件,例如视频..

3) TransactionScope 必须更大,否则完整的文件(超过 500mb 的大文件)将不会被下载因此我们会在下载后看到文件损坏的错误消息..

string zipFileName = "ZipName.zip";
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "fileName=" + zipFileName);
byte[] buffer = new byte[4096];
ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream);
zipOutputStream.SetLevel(9);     // Point 2

try
 {
   string cs = System.Configuration.ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
   foreach (Filec file1 in Files)
    {
     StreamModel model123 = new StreamModel();
     const string SelectTSql = @"SELECT FileData.PathName(), GET_FILESTREAM_TRANSACTION_CONTEXT(), FileType
                         FROM MyFiles WHERE FileId = @FileId";
     using (TransactionScope ts = new TransactionScope(TransactionScopeOption.Required,
      new TransactionOptions { Timeout = TimeSpan.FromDays(1) })) // Point 3
        {
         using (System.Data.SqlClient.SqlConnection conn = new System.Data.SqlClient.SqlConnection(cs))
          {
            conn.Open();
          using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(SelectTSql, conn))
           {
             cmd.Parameters.Add("@FileId", System.Data.SqlDbType.Int).Value = Convert.ToInt32(file1.FileId);
           using (System.Data.SqlClient.SqlDataReader rdr = cmd.ExecuteReader())
            {
              rdr.Read();
              model123.serverPath = rdr.GetSqlString(0).Value;
              model123.serverTxn = rdr.GetSqlBinary(1).Value;
              model123.filetype = rdr.GetSqlString(2).Value;
              rdr.Close();
            }
           }
          }
      using (System.Data.SqlTypes.SqlFileStream sfs = new System.Data.SqlTypes.SqlFileStream(model123.serverPath, model123.serverTxn, FileAccess.Read))
        {
          ZipEntry zipEntry = new ZipEntry(ZipEntry.CleanName(file1.FileName));
          zipEntry.Size = sfs.Length;      // Point 1
          zipOutputStream.PutNextEntry(zipEntry);
          int bytesRead;
          while ((bytesRead = sfs.Read(buffer, 0, buffer.Length)) > 0)
           {
            if (!Response.IsClientConnected)
              {
                  break;
              }
            zipOutputStream.Write(buffer, 0, bytesRead);
            Response.Flush();
           }
             sfs.Close();
         }

    ts.Complete();
  }
    zipOutputStream.CloseEntry();
 }

  zipOutputStream.Finish();
  zipOutputStream.Close();
  Response.Flush();
  Response.End();
}
catch (Exception ex)
 {
   TempData["ErrorMessage"] = "Oohhhh! Exception Occured(Error)...";
 }