Search code examples
c#sqlasp.net-mvcsharpziplibsqlfilestream

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


i am using ICSharpCode.SharpZipLib.Zip to compress the files & download zip file, and here using SQL File stream to store any kind of file(any amount of GB). Then, how can i zip the files from sql file stream and get download... And i tried something like below, which is throwing an exception "size was 845941, but I expected 16 at ICSharpCode.SharpZipLib.Zip.ZipOutputStream.CloseEntry()".How to solve this...

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();

Solution

  • After Understanding each line of code, i figured out the solution..

    1) "zipEntry.Size = model123.serverTxn.Length;" this line is causing the exception as "size was 845941, but I expected 16"..because "model123.serverTxn.Length" is not the complete size of the file., So i changed this to "sfs.Length" which is SqlFileStream length.

    2) zipOutputStream level is set maximum as "zipOutputStream.SetLevel(9)" because, i am zipping the large size files here like videos..

    3) And TransactionScope has to be more, other wise the complete file(large files more than 500mb) is not going to be downloaded hence we will see file damaged error message after downloading..

    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)...";
     }