Create multiple ZipArchiveEntry in ZipArchive class with different extensions C# - c#

I am trying to figure it out how to create a zip archive that contains files with different extensions e.g. .txt file, .html file
If I do following:
using (var zipArchive = new ZipArchive(memory, ZipArchiveMode.Create, true))
{
var file1= zipArchive .CreateEntry("file1.html");
var file2= zipArchive .CreateEntry("file2.txt");
using (var entryStream = file1.Open())
using (var sw = new StreamWriter(entryStream))
{
streamWriter.Write("testing testinsg steing");
}
using (var entryStream = file2.Open())
using (var sw = new StreamWriter(entryStream))
{
sw.Write("xyxyxyxyxyxy");
}
}
Entries in create mode may only be written to once, and only one entry
may be held open at a time.
How can I solve this?

You just need to move down the line:
var file2= zipArchive .CreateEntry("file2.txt");
... and place it after you've finished writing to the previous entry:
using (var zipArchive = new ZipArchive(memory, ZipArchiveMode.Create, true))
{
var file1= zipArchive .CreateEntry("file1.html");
using (var entryStream = file1.Open())
using (var sw = new StreamWriter(entryStream))
{
streamWriter.Write("testing testinsg steing");
}
var file2= zipArchive .CreateEntry("file2.txt"); // <-- move this down
using (var entryStream = file2.Open())
using (var sw = new StreamWriter(entryStream))
{
sw.Write("xyxyxyxyxyxy");
}
}

Related

Zip S3 files using C#

What I'm looking for is zip/compress S3 files without having them first downloaded to EFS or on a file system and then upload the zip file back to S3. Is there a C# way to achieve the same? I found the following post, but not sure its C# equivalent
https://www.antstack.io/blog/create-zip-using-lambda-with-files-streamed-from-s3/
I've written following code to zip files from a MemoryStream
public static void CreateZip(string zipFileName, List<FileInfo> filesToZip)
{
//zipFileName is the final zip file name
LambdaLogger.Log($"Zipping in progress for: {zipFileName}");
using (MemoryStream zipMS = new MemoryStream())
{
using (ZipArchive zipArchive = new ZipArchive(zipMS, ZipArchiveMode.Create, true))
{
//loop through files to add
foreach (var fileToZip in filesToZip)
{
//read the file bytes
byte[] fileToZipBytes = File.ReadAllBytes(fileToZip.FullName);
ZipArchiveEntry zipFileEntry = zipArchive.CreateEntry(fileToZip.Name);
//add the file contents
using (Stream zipEntryStream = zipFileEntry.Open())
using (BinaryWriter zipFileBinary = new BinaryWriter(zipEntryStream))
{
zipFileBinary.Write(fileToZipBytes);
}
}
}
using (FileStream finalZipFileStream = new FileStream(zipFileName, FileMode.Create))
{
zipMS.Seek(0, SeekOrigin.Begin);
zipMS.CopyTo(finalZipFileStream);
}
}
}
But problem is how to make it read file directly from S3 and upload the compressed file.
public static async Task CreateZipFile(List<List<KeyVersion>> keyVersions)
{
using MemoryStream zipMS = new MemoryStream();
using (ZipArchive zipArchive = new ZipArchive(zipMS, ZipArchiveMode.Create, true))
{
foreach (var key in keyVersions)
{
foreach (var fileToZip in key)
{
GetObjectRequest request = new GetObjectRequest
{
BucketName = "dev-s3-zip-bucket",
Key = fileToZip.Key
};
using GetObjectResponse response = await s3client.GetObjectAsync(request);
using Stream responseStream = response.ResponseStream;
ZipArchiveEntry zipFileEntry = zipArchive.CreateEntry(fileToZip.Key);
//add the file contents
using Stream zipEntryStream = zipFileEntry.Open();
await responseStream.CopyToAsync(zipEntryStream);
}
}
zipArchive.Dispose();
}
zipMS.Seek(0, SeekOrigin.Begin);
var fileTxfr = new TransferUtility(s3client);
await fileTxfr.UploadAsync(zipMS, "dev-s3-zip-bucket", "test.zip");
}

How to create a ZipArchive and return it?

I have to create a ZipArchive and return it. I can add the Entries but when I return it, it comes empty and I don't know why.
Could you help me please?
Here is my code
public static ZipArchive CreateZip(Dictionary<string, Stream> nameAndContent)
{
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Update, true))
{
foreach (var i in nameAndContent)
{
var file = archive.CreateEntry(i.Key);
using (var entryStream = file.Open())
using (var streamWriter = new StreamWriter(entryStream))
{
streamWriter.Write(i.Value);
}
}
return archive;
}
}
}

C# ZipArchive: zip file not created

I tried below code to first convert my bytes to compressed bytes and try to create a zip file, but file is not generated. Could someone please suggest!
byte[] result;
var X = 86251;
byte[] compressedBytes;
using (FileStream SourceStream = File.Open(filename, FileMode.Open))
{
SourceStream.Seek(0, SeekOrigin.Begin);
result = new byte[X];
await SourceStream.ReadAsync(result, 0, X);
}
string fileName = "Export_" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".zip";
using (var outStream = new MemoryStream())
{
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
var fileInArchive = archive.CreateEntry(fileName, CompressionLevel.Optimal);
using (var entryStream = fileInArchive.Open())
using (var fileToCompressStream = new MemoryStream(result))
{
fileToCompressStream.CopyTo(entryStream);
}
}
compressedBytes = outStream.ToArray();
}
You're not creating an actual file anywhere. You're just writing to a memory stream. Change it to write to a file.
using (var outStream = new File.Create(fileName))
{
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
var fileInArchive = archive.CreateEntry(filename, CompressionLevel.Optimal);
using (var entryStream = fileInArchive.Open())
using (var fileToCompressStream = new MemoryStream(result))
{
fileToCompressStream.CopyTo(entryStream);
}
}
}

Compressing an object in memory with System.IO.Compression in C#

I'm trying to serialize an instance of a class (let's call it Car) into an xml and compress it in memory to a zip file with a single file entry in it.
I'm using the System.IO.Compression.ZipArchive class to do it:
private byte[] CompressCar(Car car)
{
using (var carStream = new MemoryStream())
using (var zipStream = new MemoryStream())
using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create))
{
new XmlSerializer(typeof(Car)).Serialize(carStream, car);
ZipArchiveEntry entry = archive.CreateEntry("car.xml", CompressionLevel.Optimal);
using (var zippedFileStream = entry.Open())
{
carStream.Seek(0, SeekOrigin.Begin);
carStream.CopyTo(zippedFileStream);
}
return zipStream.ToArray();
}
}
When I save the compressed bytes to a file and later try to open it with Windows Explorer I get an error:
What am I doing wrong here?
I looked for other StackOverflow entries but I just couldn't find anything that would solve my problem. I want to compress it in memory rather than using a temporary file.
You need to dispose the ZipArchive before returning the underlying zipStream.ToArray(). E.g., you could extract the following helper method:
public static class SerializationExtensions
{
public static byte[] ToCompressedXmlZipArchive<T>(T root, string entryName)
{
using (var zipStream = new MemoryStream())
{
using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create))
{
var entry = archive.CreateEntry(entryName, CompressionLevel.Optimal);
using (var zippedFileStream = entry.Open())
{
new XmlSerializer(typeof(T)).Serialize(zippedFileStream, root); // Possibly use root.GetType() instead of typeof(T)
}
}
return zipStream.ToArray();
}
}
}
And then your method becomes:
private byte[] CompressCar(Car car)
{
return SerializationExtensions.ToCompressedXmlZipArchive(car, "car.xml");
}

How can I merge 2 zip files into 1?

i have 2 zip files (zip1 and zip2), i need merge this files in one, how can i solve it?
I understand that I can fix it decompressing ZIP1 to a temp folder and then add it to zip2, but i think it is inefficient, what is the faster method?
I'm using System.IO.Compression library...
I use this code to explore Zip2:
using (ZipArchive archive = ZipFile.OpenRead(Zip2))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
/*...*/
}
}
PD/: The Zip1 and Zip2 files have FILES, FOLDERS AND SUBFOLDERS
I haven't really tested this, but you can give it a try:
public ZipArchive Merge(List<ZipArchive> archives)
{
if (archives == null) throw new ArgumentNullException("archives");
if (archives.Count == 1) return archives.Single();
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
foreach (var zipArchive in archives)
{
foreach (var zipArchiveEntry in zipArchive.Entries)
{
var file = archive.CreateEntry(zipArchiveEntry.FullName);
using (var entryStream = file.Open()) {
using (var streamWriter = new StreamWriter(entryStream)) { streamWriter.Write(zipArchiveEntry.Open()); }
}
}
}
return archive;
}
}
}
I had an equivalent problem. The zip files came from another process as byte arrays. This method adds their contents to an existing ZipArchive.
using System.IO;
using System.IO.Compression;
/// <summary>
/// Copies the contents of a zip "file" represented as a byte array
/// to the given ZipArchive.
/// </summary>
/// <param name="targetArchive">The archive to which to add the entries.</param>
/// <param name="zippedSourceBuffer">The source data as zip "file" in a byte array.</param>
public static void addZipBufferToZipArchive(ZipArchive targetArchive, byte[] zippedSourceBuffer)
{
using (MemoryStream zippedSourceStream = new MemoryStream(zippedSourceBuffer))
{
using (ZipArchive sourceArchive = new ZipArchive(zippedSourceStream))
{
foreach (ZipArchiveEntry sourceEntry in sourceArchive.Entries)
{
ZipArchiveEntry targetEntry = targetArchive.CreateEntry(sourceEntry.FullName);
using (Stream targetEntryStream = targetEntry.Open())
{
using (Stream sourceStream = sourceEntry.Open())
{
sourceStream.CopyTo(targetEntryStream);
}
}
}
}
}
}
There does not appear to be any way to directly move a ZipArchiveEntry from one ZipArchive to another, so I resorted to unpacking the source and repacking it to the target via the copy operation.
If you already have a ZipArchive as source, you wouldn't need the MemoryStream zippedSourceStream and could modify the code to use sourceArchive directly as the method parameter.
This example shows how to merge two zip files into third one in memory or with actual files with the help of DotNetZip library:
//file1 and file2 are MemoryStream or file names
//for performance reason it is better that file1 is less than file2
//file1.Position = 0;//ensure at case of MemoryStream
using (var zip1 = ZipFile.Read(file1))
{
//file2.Position = 0;//ensure at case of MemoryStream
using (var zip2 = ZipFile.Read(file2))
{
var zip2EntryNames = zip2.Entries.Select(y => y.FileName).ToList();
foreach (var entry in zip1.Entries.Where(x => !zip2EntryNames.Contains(x.FileName)).ToList())
{
var memoryStream = new MemoryStream();
entry.Extract(memoryStream);
memoryStream.Position = 0;
zip2.AddEntry(entry.FileName, memoryStream);
}
if(save2file)
zip2.Save(fileNameResult);
else
using (var result = new MemoryStream())
{
zip2.Save(result);
}
}
}

Categories

Resources