I am trying to create dynamically created, downloadable ZIP files. The files are created correctly on the server, however when they are sent to the client using "Response.OutputStream" the file becomes corrupted. This only seems to happen when the zip file is over 4GB. Does anyone have any idea why this is?
The exact code I am using is:
string path = #"C:\temp\vid";
Response.BufferOutput = false; // Disable Buffer Output to start the download immediately
// Set custom headers to force browser to download the file instad of trying to open it
Response.ContentType = "application/x-zip-compressed";
Response.AppendHeader("content-disposition", "attachment; filename=Archive.zip");
ZipOutputStream zipOutputStream = new ZipOutputStream(Response.OutputStream, 20000);
zipOutputStream.SetLevel(0); // No compression
zipOutputStream.UseZip64 = UseZip64.On;//Forces Zip64 to be used
zipOutputStream.IsStreamOwner = true;
try
{
foreach (string file in Directory.GetFiles(path, "*.*", SearchOption.AllDirectories))
{
using (var fs = System.IO.File.Open(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
ZipEntry entry = new ZipEntry(ZipEntry.CleanName(Path.GetFileName(file))); //Create zip compatible name
zipOutputStream.PutNextEntry(entry); //Adds entry to list
fs.CopyTo(zipOutputStream);
zipOutputStream.CloseEntry();
zipOutputStream.Flush();
Response.Flush();
Response.Clear();
}
}
zipOutputStream.Finish();
zipOutputStream.Close();
Response.End();
Response.Flush();
}
catch
{
Debug.WriteLine("Connection Closed or error");
}
return new HttpStatusCodeResult(HttpStatusCode.OK);
Related
I have an excel file template, and then add dropdown data to excel using C#, everthing is fine in my local machine, i can download it but when i put it in server is always getting error
and actually, this error file still can be used, but its really annoying especially for user
i,m using NPOI for processing this excel file
XSSFWorkbook hssfwb;
string path = Server.MapPath("~/Content/Uploads").ToString() + ConfigurationManager.AppSettings["PathAllocationRuleTemplate"].ToString();
string newpath = Server.MapPath("~/Content/Uploads").ToString() + ConfigurationManager.AppSettings["PathAllocationRule"].ToString();
using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read))
{
hssfwb = new XSSFWorkbook(file);
file.Close();
}
> some code for filling data
**downloading part**
using (FileStream file = new FileStream(newpath, FileMode.Create, FileAccess.Write))
{
hssfwb.Write(file);
file.Close();
}
System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
response.ClearContent();
response.Clear();
response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
response.AddHeader("Content-Disposition", "attachment; filename=Allocation Rule Template.xlsx");
response.TransmitFile(newpath);
response.Buffer = true;
response.Flush();
response.End();
I'm trying to read files from my database (varbinary) and add them to a zip file so that users can download all files related to a specific user.
From what I can gather, I need to read the files from the database, create the zip file, read the files into memory and then write that to the file (doing it without this returned a blank zip file).
It will save the files to the zip, but unfortunately the files are all corrupted.
public FileResult DownloadAllDocuments(int userId)
{
// File name
string ZipFilename = DateTime.Now + "_Files.zip";
// Get files from database
List<DocumentVO> Documents = DocumentDAO.DownloadAllDocuments(userId);
var zipFileMemoryStream = new MemoryStream();
using (ZipArchive archive = new ZipArchive(zipFileMemoryStream, ZipArchiveMode.Update, leaveOpen: true))
{
foreach (DocumentVO document in Documents)
{
var entry = archive.CreateEntry(document.fileName, CompressionLevel.Fastest);
using (var entryStream = entry.Open())
{
entryStream.Write(document.File, 0, document.File.Length);
}
}
}
zipFileMemoryStream.Seek(0, SeekOrigin.Begin);
return File(zipFileMemoryStream, "application/octet-stream", ZipFilename);
}
Please try these codes instead of return File line
using (MemoryStream ms = new MemoryStream())
{
zip.Save(ms);
Response.ClearHeaders();
Response.ClearContent();
Response.Charset = "";
Response.AppendHeader("Content-Disposition", "attachment; filename=" + ZipFilename);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = "application/zip";
Response.BinaryWrite(ms.ToArray());
}
I use the SharpZipLib for zipping multiple files and download them in my asp.net c# web app. After the download I can't open the zip archive. Windows error message is:
Windows cannot open the folder. The Compressed (zipped) Folder 'filename.zip' is
invalid.
This is my code
if (Session["lstFilesToZip"] != null)
{
List<string> filesToZip = (List<string>)Session["lstFilesToZip"];
if (filesToZip.Count > 0)
{
Response.AddHeader("Content-Disposition", "attachment; filename=fileName.zip");
Response.ContentType = "application/zip";
using (var zipStream = new ZipOutputStream(Response.OutputStream))
{
foreach (string filePath in filesToZip)
{
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
var fileEntry = new ZipEntry(Path.GetFileName(filePath))
{
Size = fileBytes.Length
};
zipStream.PutNextEntry(fileEntry);
zipStream.Write(fileBytes, 0, fileBytes.Length);
}
zipStream.Flush();
zipStream.Close();
}
}
}
I already tried adding
zipStream.Dispose();
zipStream.Finish();
without success.
Maybe someone can help. I can't find the problem.
my scenario:
asp.net mvc web application
User clicks on a button in a view to start the action
Action:
Create several csv files from records that are stored in tables of an sql db
Compress all created files into a single ZipArchive
Present the ZipArchive for download to the client computer
I have a working code for creating a single csv file and presenting it for download.
public class ExportCSVController : BaseController
{
public ExportCSVController(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
public void ExportCSV_Company()
{
var sb = new StringBuilder();
var companies = UnitOfWork.GetAll<Company>();
var list = companies.ToList();
sb.AppendFormat("{0};{1};{2}{3};{4}", "Name", "Street", "City", "Zipcode", Environment.NewLine);
foreach (var item in list)
{
sb.AppendFormat("{0};{1};{2};{3};{4}", "\"" + item.Name + "\"", item.Street, item.City, item.Zip, Environment.NewLine);
}
//Get Current Response
var response = System.Web.HttpContext.Current.Response;
response.BufferOutput = true;
response.Clear();
response.ClearHeaders();
response.ContentEncoding = Encoding.Unicode;
response.AddHeader("content-disposition", "attachment;filename=Companies.txt ");
response.ContentType = "text/plain";
response.Write(sb.ToString());
response.End();
}
}
I also have a working code for compressing a file to a ZipArchive (using System.IO.Compression).
My idea:
Set up a loop (in my working code) for each file that needs to be generated
after generating the first file, add the file to the ZipArchive (using System.IO.Compression)
continue with the next file generation and append the file to the ZipArchive ...
then present the ZipArchive for download
My problem:
I do not quite understand where in the given code the file is generated, if at all?
I think, that response.Write() just directs the generated string to the browser where finally it is converted to a file when the user clicks on save.
Questions:
Must the response be saved to a file before it can be added to a ZipArchive?
If yes,
How would I convert the response via code to a file?
Is there any way to skip writing a physical file in order to get it into the ZipArchive?
Below, my example solution (for zipping 2 files)
public void ExportFilesToZip()
{
string zipFileName = "Test.zip";
string firstFileName = "FirstFile.txt";
string secondFileName = "SecondFile.txt";
string firstFileContent ="1";
string secondFileContent ="2";
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.AddHeader("content-disposition", "attachment;filename=" + zipFileName);
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
var demoFile = archive.CreateEntry(firstFileName);
using (var entryStream = demoFile.Open())
using (var streamWriter = new StreamWriter(entryStream))
{
streamWriter.Write(firstFileContent);
}
demoFile = archive.CreateEntry(secondFileName);
using (var entryStream = demoFile.Open())
using (var streamWriter = new StreamWriter(entryStream))
{
streamWriter.Write(secondFileContent);
}
}
using (var fileStream = Response.OutputStream)
{
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(fileStream);
}
}
Response.End();
}
I'm debugging a rather odd situation involving DotNetZip and ASP.NET. Long story short, the resulting zip files that are being created by the code are being reliably downloaded by Firefox, but most other browsers are intermittently returning a Network Error. I've examined the code and it reads about as generically as anything that involves DotNetZip.
Any clues?
Thanks!
EDIT: Here's the complete method. As I mentioned, it's about as generic as it gets:
protected void btnDownloadFolders_Click(object sender, EventArgs e)
{
//Current File path
var diRoot = new DirectoryInfo(_currentDirectoryPath);
var allFiles = Directory.GetFiles(diRoot.FullName, "*.*", SearchOption.AllDirectories);
Response.Clear();
Response.BufferOutput = false;
var archiveName = String.Format("{0}-{1}.zip", diRoot.Name, DateTime.Now.ToString("yyyy-MM-dd HHmmss"));
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "inline; filename=\"" + archiveName + "\"");
using (var zip = new ZipFile())
{
foreach (var strFile in allFiles)
{
var strFileName = Path.GetFileName(strFile);
zip.AddFile(strFile,
strFile.Replace("\\" + strFileName, string.Empty).Replace(diRoot.FullName, string.Empty));
}
zip.Save(Response.OutputStream);
}
Response.Close();
}
It could be because you are not sending the content-length. I've seen errors occur in sending files to the browser where it was not specified. So create the zip file in a MemoryStream. save the stream to a Byte Array so you can send the length as a Response also. Although I can't say for sure that it will fix your specific problem.
byte[] bin;
using (MemoryStream ms = new MemoryStream())
{
using (var zip = new ZipFile())
{
foreach (var strFile in allFiles)
{
var strFileName = Path.GetFileName(strFile);
zip.AddFile(strFile, strFile.Replace("\\" + strFileName, string.Empty).Replace(diRoot.FullName, string.Empty));
}
//save the zip into the memorystream
zip.Save(ms);
}
//save the stream into the byte array
bin = ms.ToArray();
}
//clear the buffer stream
Response.ClearHeaders();
Response.Clear();
Response.Buffer = true;
//set the correct contenttype
Response.ContentType = "application/zip";
//set the filename for the zip file package
Response.AddHeader("content-disposition", "attachment; filename=\"" + archiveName + "\"");
//set the correct length of the data being send
Response.AddHeader("content-length", bin.Length.ToString());
//send the byte array to the browser
Response.OutputStream.Write(bin, 0, bin.Length);
//cleanup
Response.Flush();
HttpContext.Current.ApplicationInstance.CompleteRequest();