I have got a code from this link:
http://www.codeproject.com/Tips/515704/Archive-Multiple-Files-In-Zip-Extract-Zip-Archive
that compresses and extracts a file in zip format.
However the compressing part in the code just creates an empty zipfile, so how can i add files programmatically in this zip archieve?
i have checked the doc for the ziparchieve class and it has a method for .net called CreateEntryFromFile(String, String) , however this method doesn't apply for .net windows store version.
this is the code we are concerned with:
private async void ZipClick(object sender, RoutedEventArgs e)
{
FileSavePicker picker = new FileSavePicker();
picker.FileTypeChoices.Add("Zip Files (*.zip)", new List<string> { ".zip" });
picker.SuggestedStartLocation = PickerLocationId.Desktop;
picker.SuggestedFileName = "1";
zipFile = await picker.PickSaveFileAsync();
using (var zipStream = await zipFile.OpenStreamForWriteAsync())
{
using (ZipArchive zip = new ZipArchive(zipStream, ZipArchiveMode.Create))
{
foreach (var file in storeFile)
{
ZipArchiveEntry entry = zip.CreateEntry(file.Name);
using (Stream ZipFile = entry.Open())
{
byte[] data = await GetByteFromFile(file);
ZipFile.Write(data, 0, data.Length);
}
}
}
}
}
I misunderstood the sample code, it actually can archive the the files you pass it for the first time, but i'm not sure if the same method can be used to add to add other files in the same zip file later.
public async void zipit(StorageFile zipFile, StorageFile file)
{
using (var zipToOpen = await zipFile.OpenStreamForWriteAsync())
{
using (ZipArchive archive = new ZipArchive(zipToOpen, ZipArchiveMode.Update))
{
ZipArchiveEntry readmeEntry = archive.CreateEntry(file.Name);
using (Stream writer = readmeEntry.Open())
{
//writer.WriteLine("Information about this package.");
//writer.WriteLine("========================");
byte[] data = await GetByteFromFile(file);
writer.Write(data, 0, data.Length);
}
}
}
}
where "zipFile" is the file you have chose to archive in (destination ) and "file" is the original non zipped file.
Related
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");
}
I have files (from 3rd parties) that are being FTP'd to a directory on our server. I download them and process them even 'x' minutes. Works great.
Now, some of the files are .zip files. Which means I can't process them. I need to unzip them first.
FTP has no concept of zip/unzipping - so I'll need to grab the zip file, unzip it, then process it.
Looking at the MSDN zip api, there seems to be no way i can unzip to a memory stream?
So is the only way to do this...
Unzip to a file (what directory? need some -very- temp location ...)
Read the file contents
Delete file.
NOTE: The contents of the file are small - say 4k <-> 1000k.
Zip compression support is built in:
using System.IO;
using System.IO.Compression;
// ^^^ requires a reference to System.IO.Compression.dll
static class Program
{
const string path = ...
static void Main()
{
using(var file = File.OpenRead(path))
using(var zip = new ZipArchive(file, ZipArchiveMode.Read))
{
foreach(var entry in zip.Entries)
{
using(var stream = entry.Open())
{
// do whatever we want with stream
// ...
}
}
}
}
}
Normally you should avoid copying it into another stream - just use it "as is", however, if you absolutely need it in a MemoryStream, you could do:
using(var ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0; // rewind
// do something with ms
}
You can use ZipArchiveEntry.Open to get a stream.
This code assumes the zip archive has one text file.
using (FileStream fs = new FileStream(path, FileMode.Open))
using (ZipArchive zip = new ZipArchive(fs) )
{
var entry = zip.Entries.First();
using (StreamReader sr = new StreamReader(entry.Open()))
{
Console.WriteLine(sr.ReadToEnd());
}
}
using (ZipArchive archive = new ZipArchive(webResponse.GetResponseStream()))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Stream s = entry.Open();
var sr = new StreamReader(s);
var myStr = sr.ReadToEnd();
}
}
Looks like here is what you need:
using (var za = ZipFile.OpenRead(path))
{
foreach (var entry in za.Entries)
{
using (var r = new StreamReader(entry.Open()))
{
//your code here
}
}
}
You can use SharpZipLib among a variety of other libraries to achieve this.
You can use the following code example to unzip to a MemoryStream, as shown on their wiki:
using ICSharpCode.SharpZipLib.Zip;
// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,
// which is returned as a memory stream or a byte array.
//
public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {
MemoryStream outputMemStream = new MemoryStream();
ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);
zipStream.SetLevel(3); //0-9, 9 being the highest level of compression
ZipEntry newEntry = new ZipEntry(zipEntryName);
newEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(newEntry);
StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
zipStream.CloseEntry();
zipStream.IsStreamOwner = false; // False stops the Close also Closing the underlying stream.
zipStream.Close(); // Must finish the ZipOutputStream before using outputMemStream.
outputMemStream.Position = 0;
return outputMemStream;
// Alternative outputs:
// ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
byte[] byteArrayOut = outputMemStream.ToArray();
// GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.
byte[] byteArrayOut = outputMemStream.GetBuffer();
long len = outputMemStream.Length;
}
Ok so combining all of the above, suppose you want to in a very simple way take a zip file called
"file.zip" and extract it to "C:\temp" folder. (Note: This example was only tested for compress text files) You may need to do some modifications for binary files.
using System.IO;
using System.IO.Compression;
static void Main(string[] args)
{
//Call it like this:
Unzip("file.zip",#"C:\temp");
}
static void Unzip(string sourceZip, string targetPath)
{
using (var z = ZipFile.OpenRead(sourceZip))
{
foreach (var entry in z.Entries)
{
using (var r = new StreamReader(entry.Open()))
{
string uncompressedFile = Path.Combine(targetPath, entry.Name);
File.WriteAllText(uncompressedFile,r.ReadToEnd());
}
}
}
}
I would like to add the SharpZipLib.Portable library to my Xamarin.Forms PCL project. I am targeting Android and iOS. The documentation mentions that you must implement a VirtualFileSystem in order to use the library, but I do not know how to do that and I have been unable to find much information on this topic.
Has anyone used this library that can guide me in the steps required to use it?
I ended up here when trying to implement the SharpZipLib.Portable.
I start using it without the IVirtualFileSystem because i had already a library called (PCLStorage) that knows how to read and write in filesystem (tested it on iOS and Android).
NOTE: This implementations are all inside a PCL targeting iOS, Android. No specific code for Android or iOS are needed.
Here is a simple example how to extract a Zip file using PCLStorage and SharpZipLib.Portable:
public async void DonwLoadAndStoreZipFile()
{
var bytes = await DownloadImageAsync("https://github.com/fluidicon.png");
// IFolder interface comes from PCLStorage
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.CreateFolderAsync("zipFolder", CreationCollisionOption.OpenIfExists);
IFile file = await folder.CreateFileAsync("test.zip" , CreationCollisionOption.OpenIfExists);
using (Stream stream = await file.OpenAsync(FileAccess.ReadAndWrite))
{
await stream.WriteAsync(bytes, 0, bytes.Length);
using (var zf = new ZipFile(stream))
{
foreach (ZipEntry zipEntry in zf)
{
// Gete Entry Stream.
Stream zipEntryStream = zf.GetInputStream(zipEntry);
// Create the file in filesystem and copy entry stream to it.
IFile zipEntryFile = await rootFolder.CreateFileAsync(zipEntry.Name , CreationCollisionOption.FailIfExists);
using(Stream outPutFileStream = await zipEntryFile.OpenAsync(FileAccess.ReadAndWrite))
{
await zipEntryStream.CopyToAsync(outPutFileStream);
}
}
}
}
}
If you want to get some examples on how to use the SharpZipLib.Portable you can read here (original SharpZipLib):
Code reference
and
Zip samples.
ALTERNATIVE:
After doing what i explained above I ended up with a much simpler solution because i only needed to support ZIP files.
I used ZipArchive Class present in System.IO.Compression and PCLStorage, so with this solution i don't used SharpZipLib.Portable.
Here is the version:
public async void DonwLoadAndStoreZipFile()
{
var bytes = await DownloadImageAsync(https://github.com/fluidicon.png);
// IFolder interface comes from PCLStorage
IFolder rootFolder = FileSystem.Current.LocalStorage;
IFolder folder = await rootFolder.CreateFolderAsync("zipFolder", CreationCollisionOption.OpenIfExists);
IFile file = await folder.CreateFileAsync("test.zip" , CreationCollisionOption.OpenIfExists);
using (Stream stream = await file.OpenAsync(FileAccess.ReadAndWrite))
{
await stream.WriteAsync(bytes, 0, bytes.Length);
using(ZipArchive archive = new ZipArchive(stream))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
IFile zipEntryFile = await rootFolder.CreateFileAsync(entry.Name, CreationCollisionOption.FailIfExists);
using (Stream outPutStream = await zipEntryFile.OpenAsync(FileAccess.ReadAndWrite))
{
await entry.Open().CopyToAsync(outPutStream);
}
}
}
}
}
This worked for me:
Install SharpZipLib.Portable for PCL project only
Code to use it:
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;
public void ExtractZipFile(string archivePath, string password, string outFolder) {
using(Stream fsInput = File.OpenRead(archivePath))
using(zf = new ZipFile(fs)){
if (!String.IsNullOrEmpty(password)) {
zf.Password = password;
}
foreach (ZipEntry zipEntry in zf) {
if (!zipEntry.IsFile) {
continue;
}
String entryFileName = zipEntry.Name;
var fullZipToPath = Path.Combine(outFolder, entryFileName);
var directoryName = Path.GetDirectoryName(fullZipToPath);
if (directoryName.Length > 0) {
Directory.CreateDirectory(directoryName);
}
var buffer = new byte[4096];
using(var zipStream = zf.GetInputStream(zipEntry))
using (Stream fsOutput = File.Create(fullZipToPath)) {
StreamUtils.Copy(zipStream, fsOutput , buffer);
}
}
}
}
I have files (from 3rd parties) that are being FTP'd to a directory on our server. I download them and process them even 'x' minutes. Works great.
Now, some of the files are .zip files. Which means I can't process them. I need to unzip them first.
FTP has no concept of zip/unzipping - so I'll need to grab the zip file, unzip it, then process it.
Looking at the MSDN zip api, there seems to be no way i can unzip to a memory stream?
So is the only way to do this...
Unzip to a file (what directory? need some -very- temp location ...)
Read the file contents
Delete file.
NOTE: The contents of the file are small - say 4k <-> 1000k.
Zip compression support is built in:
using System.IO;
using System.IO.Compression;
// ^^^ requires a reference to System.IO.Compression.dll
static class Program
{
const string path = ...
static void Main()
{
using(var file = File.OpenRead(path))
using(var zip = new ZipArchive(file, ZipArchiveMode.Read))
{
foreach(var entry in zip.Entries)
{
using(var stream = entry.Open())
{
// do whatever we want with stream
// ...
}
}
}
}
}
Normally you should avoid copying it into another stream - just use it "as is", however, if you absolutely need it in a MemoryStream, you could do:
using(var ms = new MemoryStream())
{
stream.CopyTo(ms);
ms.Position = 0; // rewind
// do something with ms
}
You can use ZipArchiveEntry.Open to get a stream.
This code assumes the zip archive has one text file.
using (FileStream fs = new FileStream(path, FileMode.Open))
using (ZipArchive zip = new ZipArchive(fs) )
{
var entry = zip.Entries.First();
using (StreamReader sr = new StreamReader(entry.Open()))
{
Console.WriteLine(sr.ReadToEnd());
}
}
using (ZipArchive archive = new ZipArchive(webResponse.GetResponseStream()))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
Stream s = entry.Open();
var sr = new StreamReader(s);
var myStr = sr.ReadToEnd();
}
}
Looks like here is what you need:
using (var za = ZipFile.OpenRead(path))
{
foreach (var entry in za.Entries)
{
using (var r = new StreamReader(entry.Open()))
{
//your code here
}
}
}
You can use SharpZipLib among a variety of other libraries to achieve this.
You can use the following code example to unzip to a MemoryStream, as shown on their wiki:
using ICSharpCode.SharpZipLib.Zip;
// Compresses the supplied memory stream, naming it as zipEntryName, into a zip,
// which is returned as a memory stream or a byte array.
//
public MemoryStream CreateToMemoryStream(MemoryStream memStreamIn, string zipEntryName) {
MemoryStream outputMemStream = new MemoryStream();
ZipOutputStream zipStream = new ZipOutputStream(outputMemStream);
zipStream.SetLevel(3); //0-9, 9 being the highest level of compression
ZipEntry newEntry = new ZipEntry(zipEntryName);
newEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(newEntry);
StreamUtils.Copy(memStreamIn, zipStream, new byte[4096]);
zipStream.CloseEntry();
zipStream.IsStreamOwner = false; // False stops the Close also Closing the underlying stream.
zipStream.Close(); // Must finish the ZipOutputStream before using outputMemStream.
outputMemStream.Position = 0;
return outputMemStream;
// Alternative outputs:
// ToArray is the cleaner and easiest to use correctly with the penalty of duplicating allocated memory.
byte[] byteArrayOut = outputMemStream.ToArray();
// GetBuffer returns a raw buffer raw and so you need to account for the true length yourself.
byte[] byteArrayOut = outputMemStream.GetBuffer();
long len = outputMemStream.Length;
}
Ok so combining all of the above, suppose you want to in a very simple way take a zip file called
"file.zip" and extract it to "C:\temp" folder. (Note: This example was only tested for compress text files) You may need to do some modifications for binary files.
using System.IO;
using System.IO.Compression;
static void Main(string[] args)
{
//Call it like this:
Unzip("file.zip",#"C:\temp");
}
static void Unzip(string sourceZip, string targetPath)
{
using (var z = ZipFile.OpenRead(sourceZip))
{
foreach (var entry in z.Entries)
{
using (var r = new StreamReader(entry.Open()))
{
string uncompressedFile = Path.Combine(targetPath, entry.Name);
File.WriteAllText(uncompressedFile,r.ReadToEnd());
}
}
}
}
I am building a metro style app for windows 8 and I have a zip file that I am downloading from a web service, and I want to extract it.
I have seen the sample for compression and decompression, but that takes a single file an compresses/decompresses it. I have a whole directory structure that I need to extract.
Here is what I have so far:
var appData = ApplicationData.Current;
var file = await appData.LocalFolder.GetItemAsync("thezip.zip") as StorageFile;
var decompressedFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("tempFileName", CreationCollisionOption.GenerateUniqueName);
using (var decompressor = new Decompressor(await file.OpenSequentialReadAsync()))
using (var decompressedOutput = await decompressedFile.OpenAsync(FileAccessMode.ReadWrite))
{
var bytesDecompressed = await RandomAccessStream.CopyAsync(decompressor, decompressedOutput);
}
But this is no good, the bytesDecompressed variable is always zero size, but the zip File is 1.2MB
Any help here would be greatly appreciated.
EDIT: Answer, thanks to Mahantesh
Here is the code for unzipping a file:
private async void UnZipFile()
{
var folder = ApplicationData.Current.LocalFolder;
using (var zipStream = await folder.OpenStreamForReadAsync("thezip.zip"))
{
using (MemoryStream zipMemoryStream = new MemoryStream((int)zipStream.Length))
{
await zipStream.CopyToAsync(zipMemoryStream);
using (var archive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.Name != "")
{
using (Stream fileData = entry.Open())
{
StorageFile outputFile = await folder.CreateFileAsync(entry.Name, CreationCollisionOption.ReplaceExisting);
using (Stream outputFileStream = await outputFile.OpenStreamForWriteAsync())
{
await fileData.CopyToAsync(outputFileStream);
await outputFileStream.FlushAsync();
}
}
}
}
}
}
}
}
In Metro style apps, you work with compressed files by using the methods in the ZipArchive, ZipArchiveEntry, DeflateStream, and GZipStream classes.
Refer : UnZip File in Metro
Refer : Folder zip/unzip in metro c#
Based on your code and suggestions, I came up with one which supports folders extraction, which was one of my needs:
private async void UnZipFile(string file)
{
var folder = ApplicationData.Current.LocalFolder;
using (var zipStream = await folder.OpenStreamForReadAsync(file))
{
using (MemoryStream zipMemoryStream = new MemoryStream((int)zipStream.Length))
{
await zipStream.CopyToAsync(zipMemoryStream);
using (var archive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.Name == "")
{
// Folder
await CreateRecursiveFolder(folder, entry);
}
else
{
// File
await ExtractFile(folder, entry);
}
}
}
}
}
}
private async Task CreateRecursiveFolder(StorageFolder folder, ZipArchiveEntry entry)
{
var steps = entry.FullName.Split('/').ToList();
steps.RemoveAt(steps.Count() - 1);
foreach (var i in steps)
{
await folder.CreateFolderAsync(i, CreationCollisionOption.OpenIfExists);
folder = await folder.GetFolderAsync(i);
}
}
private async Task ExtractFile(StorageFolder folder, ZipArchiveEntry entry)
{
var steps = entry.FullName.Split('/').ToList();
steps.RemoveAt(steps.Count() - 1);
foreach (var i in steps)
{
folder = await folder.GetFolderAsync(i);
}
using (Stream fileData = entry.Open())
{
StorageFile outputFile = await folder.CreateFileAsync(entry.Name, CreationCollisionOption.ReplaceExisting);
using (Stream outputFileStream = await outputFile.OpenStreamForWriteAsync())
{
await fileData.CopyToAsync(outputFileStream);
await outputFileStream.FlushAsync();
}
}
}