Search code examples
c#asp.net-mvczip

How to add existing file (image/mp4/pdf) to a ziparchive? - .Net Framework 4.6.2


I am trying to implement a "Download All" button that will zip up a selection of files from the server and return them as a zip file download. With the code below, I have the zip file being created. The expected files are inside, with the filenames expected, but the contents of the zipped files appears to be corrupted.

public ActionResult DownloadAll(Guid id)
{
    var assets = db.InviteAssets.Include(i => i.AssetPages).Where(w => w.InviteID == id).ToList();

    var cd = new System.Net.Mime.ContentDisposition
    {
        // for example foo.bak
        FileName = "allAssets.zip",

        // always prompt the user for downloading, set to true if you want 
        // the browser to try to show the file inline
        Inline = false,
    };
    Response.AppendHeader("Content-Disposition", cd.ToString());

    using (var memoryStream = new MemoryStream())
    {
        using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, true))
        {
            foreach (var asset in assets)
            {
                string path, extension, name;
                if (asset.AssetType != AssetType.PDF)
                {
                    path = asset.AssetPages.First(f => f.PageNumber == 1).FilePath;
                }
                else
                {
                    path = string.Format("/Content/Assets/asset_{0}.pdf", asset.ID);
                }
                extension = path.Substring(path.IndexOf('.'));
                name = "asset" + asset.Order + extension;

                var file = archive.CreateEntry(name);

                using (var streamWriter = new StreamWriter(file.Open()))
                {
                    using (var fileStream = System.IO.File.Open(Server.MapPath("~" + path), FileMode.Open))
                    {
                        int filelength = (int)fileStream.Length;
                        var filedata = new byte[fileStream.Length];
                        streamWriter.Write(fileStream.Read(filedata, 0, filelength));
                    }
                }
            }
        }

        return File(memoryStream.ToArray(), "application/json", "allAssets.zip");
    }
}

I'm thinking my issue is therefore with this section:

using (var streamWriter = new StreamWriter(file.Open()))
{
    using (var fileStream = System.IO.File.Open(Server.MapPath("~" + path), FileMode.Open))
    {
        int filelength = (int)fileStream.Length;
        var filedata = new byte[fileStream.Length];
        streamWriter.Write(fileStream.Read(filedata, 0, filelength));
    }
}

I keep reading examples that use a method archive.CreateEntryFromFile(filePath, fileName) but no such method is recognised. Has this been deprecated, or requires a higher version of .Net Framework?

Thanks in advance.


Solution

  • I discovered that the reason I couldn't see the CreateEntryFromFile method was because I had not included a reference to System.IO.Compression.FileSystem. Once I added that, I could use CreateEntryFromFile which worked fine.

    So now I have: archive.CreateEntryFromFile(Server.MapPath("~" + path), name);

    Instead of:

    var file = archive.CreateEntry(name);
    
    using (var streamWriter = new StreamWriter(file.Open()))
    {
        using (var fileStream = System.IO.File.Open(Server.MapPath("~" + path), FileMode.Open))
        {
            int filelength = (int)fileStream.Length;
            var filedata = new byte[fileStream.Length];
            fileStream.Read(filedata, 0, filelength);
            streamWriter.Write(filedata);
        }
    }