C# create zip file using zip archive System.IO.Compression - c#

Here is the functionality I want to achieve
Write a JSON file.
Write a PDF file.
Create an archive for these two files
I am using the System.IO.Compression ZipArchive to achieve this. From the documentation, I have not found a good use case for this. The examples in documentation assume that the zip file exists.
What I want to do
Create zipArchive stream write JSON file and pdf file as entries in the zip file.
using (var stream = new FileStream(path, FileMode.Create))
{
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, true))
{
ZipArchiveEntry manifest = archive.CreateEntry(filenameManifest);
using (StreamWriter writerManifest = new StreamWriter(manifest.Open()))
{
writerManifest.WriteLine(JSONObject_String);
}
ZipArchiveEntry pdfFile = archive.CreateEntry(filenameManifest);
using (StreamWriter writerPDF = new StreamWriter(pdfFile.Open()))
{
writerPDF.WriteLine(pdf);
}
}
}

You don't close the stream, you open with 'manifest.Open()'. Then it might not have written everything to the zip.
Wrap it in another using, like this:
using (var stream = new FileStream(path, FileMode.Create))
{
using (var archive = new ZipArchive(stream, ZipArchiveMode.Create, true))
{
ZipArchiveEntry manifest = archive.CreateEntry(filenameManifest);
using (Stream st = manifest.Open())
{
using (StreamWriter writerManifest = new StreamWriter(st))
{
writerManifest.WriteLine(JSONObject_String);
}
}
ZipArchiveEntry pdfFile = archive.CreateEntry(filenameManifest);
using (Stream st = manifest.Open())
{
using (StreamWriter writerPDF = new StreamWriter(st))
{
writerPDF.WriteLine(pdf);
}
}
}
}

Related

Passing compressed files from C# to R

I don't know very well C# and compressed files, but i need to create comrpessed files with C# and read them with R. So which format should i use, that it is compatible with both C# and R?
I have tried this:
using (FileStream zipToOpen = new FileStream("myfile.gff", FileMode.Create))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create))
{
ZipArchiveEntry write_entry = archive.CreateEntry(path);
using (BinaryWriter writer = new BinaryWriter(write_entry.Open()))
{
//writing
}
}
}
but i can't open this file with the R function unzip().
EDIT:
zipF<-file.choose()
unzip(zipF)
Warning message: In unzip(zipF) : error 1 in extracting from zip file

how to read a compressed file from c# in R

String fileName = "0001.gff";
using (FileStream zipToOpen = new FileStream(fileName, FileMode.Create))
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Create))
{
ZipArchiveEntry write_entry = archive.CreateEntry(fileName);
using (BinaryWriter writer = new BinaryWriter(write_entry.Open()))
{
writer.Write((Int32)1);
writer.Write((Int32)2);
writer.Write((Int32)3);
writer.Write((Int32)4);
}
}
}
I have created the file myFile in c#, but i want to read it in R. How can i do that?
There is a function called read.gff from the ape package the documentation says to try using
read.gff(file)

C# ZipArchive - How to nest internal .zip files without writing to disk

I need to create a zip file in memory, then send the zip file to the client. However, there are cases where the created zip file will need to contain other zip files that were also generated in memory. For instance, the file structure might look like this:
SendToClient.zip
InnerZip1.zip
File1.xml
File2.xml
InnerZip2.zip
File3.xml
File4.xml
I've been attempting to use the System.IO.Compression.ZipArchive library. I cannot use the System.IO.Compression.ZipFile library because my project's version of .NET is not compatible with it.
Here's an example of what I've tried.
public Stream GetMemoryStream() {
var memoryStream = new MemoryStream();
string fileContents = "Lorem ipsum dolor sit amet";
string entryName = "Lorem.txt";
string innerZipName = "InnerZip.zip";
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) {
ZipArchiveEntry entry = archive.CreateEntry(Path.Combine(innerZipName, entryName), CompressionLevel.Optimal);
using (var writer = new StreamWriter(entry.Open())) {
writer.Write(fileContents);
}
}
return memoryStream
}
However, this just puts Lorem.txt in a folder called "Inner.zip" (instead of in an actual zip file).
I can create an empty inner zip file if I create an entry called "Inner.zip" without writing to it. I can't add anything to it, though, and writing to an entry called "Inner.zip\Lorem.txt" afterward just creates a folder again (alongside the identically named empty .zip file).
I've also tried creating a separate archive, serializing it with a memory stream, then writing that to the original archive as a .zip.
public Stream CreateOuterZip() {
var memoryStream = new MemoryStream();
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) {
ZipArchiveEntry entry = archive.CreateEntry("Outer.zip", CompressionLevel.NoCompression);
using (var writer = new BinaryWriter(entry.Open())) {
writer.Write(GetMemoryStream().ToArray());
}
}
return memoryStream;
}
This just creates an invalid .zip file that windows doesn't know how to open, though.
Thanks in advance!
So I created a FileStream instead of a MemoryStream so the code can be tested easier
public static Stream CreateOuterZip()
{
string fileContents = "Lorem ipsum dolor sit amet";
// Final zip file
var fs = new FileStream(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SendToClient.zip"), FileMode.OpenOrCreate);
// Create inner zip 1
var innerZip1 = new MemoryStream();
using (var archive = new ZipArchive(innerZip1, ZipArchiveMode.Create, true))
{
var file1 = archive.CreateEntry("File1.xml");
using (var writer = new BinaryWriter(file1.Open()))
{
writer.Write(fileContents); // Change fileContents to real XML content
}
var file2 = archive.CreateEntry("File2.xml");
using (var writer = new BinaryWriter(file2.Open()))
{
writer.Write(fileContents); // Change fileContents to real XML content
}
}
// Create inner zip 2
var innerZip2 = new MemoryStream();
using (var archive = new ZipArchive(innerZip2, ZipArchiveMode.Create, true))
{
var file3 = archive.CreateEntry("File3.xml");
using (var writer = new BinaryWriter(file3.Open()))
{
writer.Write(fileContents); // Change fileContents to real XML content
}
var file4 = archive.CreateEntry("File4.xml");
using (var writer = new BinaryWriter(file4.Open()))
{
writer.Write(fileContents); // Change fileContents to real XML content
}
}
using (var archive = new ZipArchive(fs, ZipArchiveMode.Create, true))
{
// Create inner zip 1
var innerZipEntry = archive.CreateEntry("InnerZip1.zip");
innerZip1.Position = 0;
using (var s = innerZipEntry.Open())
{
innerZip1.WriteTo(s);
}
// Create inner zip 2
var innerZipEntry2 = archive.CreateEntry("InnerZip2.zip");
innerZip2.Position = 0;
using (var s = innerZipEntry2.Open())
{
innerZip2.WriteTo(s);
}
}
fs.Close();
return fs; // The file is written, can probably just close this
}
You can obviously modify this method to return a MemoryStream, or change the method to Void to just have the zip file written out to disk
You should create ZipArchive for internal zip file also. Write it to stream (memorystream). And after write this stream as general stream into main zip.
static Stream Inner() {
var memoryStream = new MemoryStream();
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) {
var demoFile = archive.CreateEntry("foo2.txt");
using (var entryStream = demoFile.Open())
using (var streamWriter = new StreamWriter(entryStream)) {
streamWriter.Write("Bar2!");
}
}
return memoryStream;
}
static void Main(string[] args) {
using (var memoryStream = new MemoryStream()) {
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true)) {
var demoFile = archive.CreateEntry("foo.txt");
using (var entryStream = demoFile.Open())
using (var streamWriter = new StreamWriter(entryStream)) {
streamWriter.Write("Bar!");
}
var zip = archive.CreateEntry("inner.zip");
using (var entryStream = zip.Open()) {
var inner = Inner();
inner.Seek(0, SeekOrigin.Begin);
inner.CopyTo(entryStream);
}
}
using (var fileStream = new FileStream(#"d:\test.zip", FileMode.Create)) {
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(fileStream);
}
}
Thanks to this answer.

c# - How can I write a file to memorystream, zip three of those memorystreams, and put that into another memorystream?

First, I want to create three files without actually creating a file like memorystream. I want to compress those three files and put them in a memoeystream.
It is possible to put a zip file in memoeystream, but like memorystream, can it actually contain three files without creating a file?
Here is my code,
using (MemoryStream ms = new MemoryStream()) {
using (ZipArchive fileContainer = new ZipArchive(ms, ZipArchiveMode.Create, true)) {
using(MemoryStream fileMS = new MemoryStream()){
//I want to create file to like memorystream, Not local
//file txt1.txt contain 123456789
//file txt2.txt contain 12345
//file txt1.txt contain 6789
}
}
return File(ms.ToArray(), System.Net.Mime.MediaTypeNames.Application.Octet, "Result.zip");
}
Worked fine for me
using (MemoryStream ms = new MemoryStream())
{
using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
for (int i = 0; i < 3; i++)
{
ZipArchiveEntry readmeEntry = archive.CreateEntry($"text{i}.txt");
using (StreamWriter writer = new StreamWriter(readmeEntry.Open()))
{
writer.WriteLine("text");
}
}
}
return File(ms.ToArray(), System.Net.Mime.MediaTypeNames.Application.Octet, "Result.zip");
}

How to compress multiple files in zip file

I'm trying to compress two text files to a zip file. This is how my public method looks like:
public ActionResult Index()
{
byte[] file1 = System.IO.File.ReadAllBytes(#"C:\file1.txt");
byte[] file2 = System.IO.File.ReadAllBytes(#"C:\file2.txt");
Dictionary<string, byte[]> fileList = new Dictionary<string, byte[]>();
fileList.Add("file1.txt", file1);
fileList.Add("file2.txt", file2);
CompressToZip("zip.zip", fileList);
return View();
}
This is how my compress method looks like:
private void CompressToZip(string fileName, Dictionary<string, byte[]> fileList)
{
using (var memoryStream = new MemoryStream())
{
foreach (var file in fileList)
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
var demoFile = archive.CreateEntry(file.Key);
using (var entryStream = demoFile.Open())
using (var b = new BinaryWriter(entryStream))
{
b.Write(file.Value);
}
}
}
using (var fileStream = new FileStream(fileName, FileMode.Create))
{
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(fileStream);
}
}
}
In this approach, the zip folder is perfectly created. However the issue is I'm getting only one file inside the zip folder (Just the second file will be created inside the zip folder).
There are no errors found.
Question: How to compress both text files into the zip folder?
Thank you in advanced!
Your code is actually saving two separate zip archives to the zip.zip file (a new ZipArchive is created for each file to be compressed). The first zip archive contains only file1.txt, the second only file2.txt. When you open zip.zip in Windows Explorer, it shows just the contents of the second zip archive.
To create a single zip archive containing both files, just move the creation of the ZipArchive outside of your fileList loop:
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach (var file in fileList)
{
var demoFile = archive.CreateEntry(file.Key);
using (var entryStream = demoFile.Open())
using (var b = new BinaryWriter(entryStream))
{
b.Write(file.Value);
}
}
}
At first glance, I would suggest that your foreach statement around the using var (archive = new ZipArchive...) is the wrong way round.
This way you are creating a new ZipArchive each time you iterate the foreach loop.
Surely you want to create the ZipArchive and loop through the foreach inside of that?
Like this:
private void CompressToZip(string fileName, Dictionary<string, byte[]> fileList)
{
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach (var file in fileList)
{
var demoFile = archive.CreateEntry(file.Key);
using (var entryStream = demoFile.Open())
using (var b = new BinaryWriter(entryStream))
{
b.Write(file.Value);
}
}
}
using (var fileStream = new FileStream(fileName, FileMode.Create))
{
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(fileStream);
}
}
}
Hope this helps!
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
ZipFile.CreateFromDirectory(startPath, zipPath);

Categories