Rvby
Rvby
CC#
Created by Rvby on 12/11/2023 in #help
Writing Images to Zip File using DotNetZip
Hi, all! I'm working on a library that I plan to use for a much larger project, just to get my feet wet with it. Right now, I'm trying to take all images from a given folder and then push them into a .ZIP (really a .CBZ, but they're the same, just with a different extension). I want to avoid any disk IO until the .ZIP is fully created and ready to be written, though I am starting to wonder if this is possible without some temp files. I'm using ImageSharp to convert the files to .webp first, then trying to add them as entries into the .ZIP. Originally, I tried to use the built-in ZipArchive system. I was able to get it to write out a .CBZ with the images in there... or, to write files. The images would be corrupted during the write for some reason. My guess is that there's some weirdness around the stream being a compressed stream and my writing uncompressed data to it. I had a problem like this with it at work a while back. No matter--people seem to like DotNetZip, and it seemed simpler to use, so I decided to give that a try. My first attempt with it was this was this:
using (ZipFile zipFile = new ZipFile(zipPath))
{
foreach (string currentFilePath in imagePathsInFolder)
{
string currentFileName = Path.GetFileNameWithoutExtension(currentFilePath);
using (MemoryStream imageMemoryStream = new MemoryStream())
{
using (Image currentImage = Image.Load(currentFilePath))
{
currentImage.SaveAsWebp(imageMemoryStream, encoder);
}
ZipEntry entryStream = zipFile.AddEntry(currentFileName + ".webp", imageMemoryStream);
}
}
zipFile.Save();
}
using (ZipFile zipFile = new ZipFile(zipPath))
{
foreach (string currentFilePath in imagePathsInFolder)
{
string currentFileName = Path.GetFileNameWithoutExtension(currentFilePath);
using (MemoryStream imageMemoryStream = new MemoryStream())
{
using (Image currentImage = Image.Load(currentFilePath))
{
currentImage.SaveAsWebp(imageMemoryStream, encoder);
}
ZipEntry entryStream = zipFile.AddEntry(currentFileName + ".webp", imageMemoryStream);
}
}
zipFile.Save();
}
The above complains because it Cannot access a closed Stream. I'm guessing that the imageMemoryStreams aren't flushed properly into the zip until we choose to save to disk? I did try to push zipFile.save() up into the imageMemoryStream using statement, but that gives me a different headache around a NRE that must be happening in the internal code. I thought ZipOutputStream might be the right option instead, since it's purpose built to work with streams, but I'm getting a weird error when trying to run even the example code from the github:
string zipPath = Path.Combine(testFolder, "c01.cbz");

using (var fs = File.Create(zipPath))
{
using (var s = new ZipOutputStream(fs))
{
s.PutNextEntry("entry1.txt");
byte[] buffer = Encoding.ASCII.GetBytes("This is the content for entry #1.");
s.Write(buffer, 0, buffer.Length);
}
}
string zipPath = Path.Combine(testFolder, "c01.cbz");

using (var fs = File.Create(zipPath))
{
using (var s = new ZipOutputStream(fs))
{
s.PutNextEntry("entry1.txt");
byte[] buffer = Encoding.ASCII.GetBytes("This is the content for entry #1.");
s.Write(buffer, 0, buffer.Length);
}
}
'IBM437' is not a supported encoding name. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.
'IBM437' is not a supported encoding name. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method.
StackOverflow directed me to this: https://stackoverflow.com/a/49068626 But even with that nuget package installed alongside a using directive and this line of code at the start of the test method, I'm still getting the above error. My project is in .NET 6.0. Any thoughts on what I'm doing wrong here? Or thoughts on how I could do this better?
14 replies