Extracting specific File from archive in UWP

2019-09-10 06:55发布

To save space I have zipped my books(in xml format) in my UWP Project. I want to Extract a file to my Local Folder based upon it's name.

Till Now what I have done(This extracts all files) :

ZipFile.ExtractToDirectory(sourceCompressedFile.Path, destinationFolder.Path);

However this extracts all the files from my archive to my destination folder. I know this could be a trivial task using SharpZipLib but this is an inbuilt method and would help me reduce my app size . I simply want to extract a file whose name matches with a name I provide. There are three methods other than this but I lost my way using them.

This can be done easily using DotNetZip as seen here but I don't want to use any third party Library

2条回答
何必那么认真
2楼-- · 2019-09-10 07:47

I think you have several files zipped in one zip archive, so will the ZipFile.ExtractToDirectory Method (String, String) extract all the files in the specified zip archive to a directory.

If you just want to access one special file in this zipped archive, you can use ZipArchiveEntry Class to achieve this work, for example here:

StorageFolder _folder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("Assets");
/*fails here FileNotFound*/
StorageFile sourceCompressedFile = await _folder.GetFileAsync("archived.zip");

StorageFolder folder = ApplicationData.Current.LocalFolder;

// ZipFile.ExtractToDirectory(file.Path, folder.Path);

using (ZipArchive archive = ZipFile.OpenRead(sourceCompressedFile.Path))
{
    foreach (ZipArchiveEntry entry in archive.Entries)
    {
        if (entry.FullName.ToString() == "miao2.jpg")
        {
            entry.ExtractToFile(Path.Combine(folder.Path, entry.FullName));
        }
    }
}

I zipped several pictures as the "archived.zip" file for test, in this sample, it will only extract the image file named "miao2.jpg".

查看更多
别忘想泡老子
3楼-- · 2019-09-10 07:50

Ok... got it!

First, to read a specific entry, use ZipArchiveEntry.GetEntry(entrytosearch);

Second, can't read a ZipArchiveEntry into a IRandomAccessStream, I don't know why... fiddled with it for a good while before deciding to read it in memory first. Since what I'm doing is read images to display on screen, it has limited memory management impact. However, beware of the size if you're reading something big. I would put a check on the .Length of the entry before reading it. However, for simplicty purposes, here is the updated code to read a specific ".jpg" entry of a zip file into a Image.Source.

Not elegant or sophisticated yet, but i hope it saves someone the time I spent fiddling with this!

    public class ZipItem
    {
        public StorageFile motherfile { get; set; }
        public ZipArchiveEntry motherentry { get; set; }
        public string Name { get; set; }
        public string ActualBytes { get; set; }
        public string CompressedBytes { get; set; }
    }

    public List<ZipItem> results;
    public int i = 0;

    private async void  nextimg_Click(object sender, RoutedEventArgs e)
    {
        //Open the zip file. At that point in the program, I previously read
        //all zip files in a hierarchy and stored them in the "results" a 
        //list of ZipItems populated in another method. i points to the
        //image I wish to display in the list. 

        Stream stream = await results[i].motherfile.OpenStreamForReadAsync();

        using (ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Read))
        {
            //look for the entry "i", which is my current slideshow position
            ZipArchiveEntry entry = archive.GetEntry(results[i].motherentry.Name);

            //Open the entry as a stream
            Stream fileStream = entry.Open();

            //Before I read this in memory, I do check for entry.Length to make sure it's not too big. 
            //For simplicity purposes here, I jsut show the "Read it in memory" portion
            var memStream = new MemoryStream();
            await fileStream.CopyToAsync(memStream);
            //Reset the stream position to start
            memStream.Position = 0;

            //Create a BitmapImage from the memStream;
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.DecodePixelHeight = (int)ctlImage.Height;
            bitmapImage.DecodePixelWidth = (int)ctlImage.Width;

            //Set the source of the BitmapImage to the memory stream
            bitmapImage.SetSource(memStream.AsRandomAccessStream());

            //Set the Image.Source to the BitmapImage
            ctlImage.Source = bitmapImage;
            }
        }
    }
查看更多
登录 后发表回答