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();
}
}
}
Related
I made myself some code that is supposed to make a Zip file containing another file. This file is created from a canvas. But the zip file that is created is empty and doesn't contain anything. The exception also isn't thrown. Any idea what might be wrong?
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
savePicker.FileTypeChoices.Add("Extended sketchpad", new[] { ".exsk" });
Windows.Storage.StorageFile file = await savePicker.PickSaveFileAsync();
if (null != file)
{
try
{
using (var memoryStream = new MemoryStream())
{
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
{
var giffile = archive.CreateEntry("layer.gif");
using (Stream entryStream = giffile.Open())
{
await MyInkCanvas.InkPresenter.StrokeContainer.SaveAsync(entryStream.AsOutputStream());
}
}
using (Windows.Storage.Streams.IRandomAccessStream finalStream = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
{
finalStream.Size = 0;
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(finalStream.AsStreamForWrite());
}
}
//MainPage.NotifyUser("File has been saved!", NotifyType.StatusMessage);
}
catch (Exception ex)
{
//MainPage.NotifyUser(ex.Message, NotifyType.ErrorMessage);
}
}
Why not write to file directly?
using (var fileStream = await file.OpenStreamForWriteAsync())
{
using (var archive = new ZipArchive(fileStream, ZipArchiveMode.Create, true))
{
var giffile = archive.CreateEntry("layer.gif");
using (Stream entryStream = giffile.Open())
{
await MyInkCanvas.InkPresenter.StrokeContainer.SaveAsync(entryStream.AsOutputStream());
}
}
}
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 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.
I am trying to save an image from the web to local storage to be manipulated later, but it appears to be corrupt and attempting to open it with an external application fails. Opening the image in the webbrowser works completely normally. Thanks for any help.
var client = new HttpClient();
var clientResponse = await client.GetByteArrayAsync(imageUri);
var temp = ApplicationData.Current.TemporaryFolder;
StorageFile file;
if ((await temp.GetFilesAsync()).Any(f => f.Name == "temp_image.png")) {
file = await temp.GetFileAsync("tempcolorizer.png");
} else {
file = await temp.CreateFileAsync("temp_image.png");
}
using (var fs = await file.OpenReadAsync())
using (var writer = new DataWriter(fs)) {
writer.WriteBytes(clientResponse);
}
You have to call StoreAsync:
using (var fs = await file.OpenReadAsync())
using (var writer = new DataWriter(fs)) {
writer.WriteBytes(clientResponse);
await writer.StoreAsync();
}
What is the best way to read amnd write and IO.Stream (Zip file downloded from internet in my case) to ApplicationData.Current.LocalFolder
I tried
public static async Task WriteToFile(
this System.IO.Stream input,
string fileName,
StorageFolder folder = null)
{
folder = folder ?? ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync(
fileName,
CreationCollisionOption.ReplaceExisting);
using (var fs = await file.OpenAsync(FileAccessMode.ReadWrite))
{
using (var outStream = fs.GetOutputStreamAt(0))
{
using (var dataWriter = new DataWriter(outStream))
{
byte[] buffer = new byte[8 * 1024];
int len;
while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
{
dataWriter.WriteBytes(buffer);
}
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
await outStream.FlushAsync();
}
}
}
for writing and
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync(filename);
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
var stream = fileStream.AsStreamForRead();
but the file gets corrupted somewhere along the way.I do no think there is a problem with reading so it should be somewhere in writing the file. Is there a better way to write IO.Stream to ApplicationData.Current.LocalFolder that works?
Try this:
static async void DownloadFileAsync(
this HttpClient httpClient,
string requestUri,
string fileName,
StorageFolder folder = null)
{
folder = folder ?? ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync(
fileName, CreationCollisionOption.ReplaceExisting);
using (var httpStream = await httpClient.GetStreamAsync(uri))
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
await httpStream.CopyToAsync(fileStream.AsStreamForWrite());
}
}
MSDN: HttpClient Class, HttpClient.GetStreamAsync Method, WindowsRuntimeStreamExtensions.AsStreamForWrite Method, Stream.CopyToAsync Method.