I could download the .xlsm file individually but when I tried to download them as ZIP. It says 'The file is corrupt and cannot be opened'. This is happening only for the .xlsm files but not while downloading .csv files as ZIP
Server-side API controller
public async Task<IActionResult> DownloadZIP([FromBody] List<SomeList> req)
{
List<string> pathLists = new List<string>();
// From the req getting the file paths
pathLists.Add(filePath);
try
{
// if pathLists null, return from there
Stream streamZip = await Task.Run(() => someServer.ConvertToZIP(pathLists));
return File(streamZip, "application/zip", "file_name.zip");
}
catch (Exception ex)
{
// Handle exception and return
}
}
Server-side service API
public Stream ConvertToZIP (List<string> pathList)
{
var memoryStream = new MemoryStream();
using (ZipArchive zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
pathList.ForEach(filePath =>
{
string fileName = Path.GetFileName(filePath);
var demoFile = zipArchive.CreateEntry(fileName);
var stream = CreateStream(filePath, FileMode.Open);
var reader = new StreamReader(stream);
var entryStream = demoFile.Open();
using (var streamWriter = new StreamWriter(entryStream))
{
streamWriter.Write(reader.ReadToEnd());
}
});
}
memoryStream.Position = 0;
return memoryStream;
}
Client side
downloadZIPFile()
{
someService.DownloadZIP(this.createList()).subscribe(res => {
if (res) {
var binaryData = [];
binaryData.push(res);
var url= window.URL.createObjectURL(new Blob(binaryData, {type: "application/zip"}));
var link = document.createElement('a');
link.href = url;
link.download = "filename.zip";
link.click();a
}
});
}
Client service
DownloadZIP(req: someEvents[]) : observable<Blob>
{
let dowloadAPI = "someapi/some/some";
const httpOptions = {
responseType : 'blob' as 'json';
headers: new HttpHeaders({
// type as 'text/csv' also not worked
'Accept': 'application/vnd.ms-excel.sheet.macroEnabled.12'
})
};
return this.http.post<Blob>(downloadAPI, req, httpOptions);
}
The file size is same both at the server and client side. What am I missing?
StreamReader
and StreamWriter
are designed to read/write text. If you use them to read and write non-text binary data (like .xlsm files) you run the risks of:
StreamReader
misinterpreting binary data as characters, or:StreamWriter
messing up the output dataEither situation, or the combination of both, causes the data that's fed to the compression algorithm to differ from that of the original file, in essence corrupting it.
The reason CSV files work is because they are plain-text files, which is exactly what StreamReader
/StreamWriter
were designed for. Assuming that the encoding of the CSV files are ASCII or UTF-8, the compressed data will pretty much be 1:1 to the original file (by default, StreamReader
and StreamWriter
use UTF-8 encoding to interpret/write data).
To solve the problem, remove the use of StreamReader
and StreamWriter
, and copy the data between the base streams directly:
using (ZipArchive zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
pathList.ForEach(filePath =>
{
string fileName = Path.GetFileName(filePath);
var demoFile = zipArchive.CreateEntry(fileName);
// Don't forget to dispose the input stream
using (var stream = CreateStream(filePath, FileMode.Open))
{
using (var entryStream = demoFile.Open())
{
stream.CopyTo(entryStream);
}
}
});
}