Unpacking an uploaded zip file
To begin, you need to add a reference to System.IO.Compression to your project. Having done that, here is an upload form for the zip file:
@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { enctype = "multipart/form-data" })) { <input type="file" name="zip" /> <div> <button class="btn btn-default">Submit</button> </div> }
Note that the form's method is specified as
POST
and that the enctype
attribute is set with a value of multipart/form-data
- both prerequisites for being able to upload files. The form is posted to the following controller action:[HttpPost] public ActionResult Index(HttpPostedFileBase zip) { var uploads = Server.MapPath("~/uploads"); using (ZipArchive archive = new ZipArchive(zip.InputStream)) { foreach (ZipArchiveEntry entry in archive.Entries) { if (!string.IsNullOrEmpty(Path.GetExtension(entry.FullName))) //make sure it's not a folder { entry.ExtractToFile(Path.Combine(uploads, entry.FullName)); } else { Directory.CreateDirectory(Path.Combine(uploads, entry.FullName)); } } } ViewBag.Files = Directory.EnumerateFiles(uploads); return View(); }
The action's parameter is an
HttpPostedFileBase
named after the name attribute of the file upload control in the form. The code creates an instance of the ZipArchive
class from the content of the uploaded file and then iterates the contents of the archive. If the name of an entry has a file extension, it is a file. If not, it is a folder. The code will save the extracted file or create a folder accordingly.Creating a Zip file for download
The simple example that follows illustrates the use of the static
ZipFile.CreateFromDirectory
method which, despite the fact that it is in the System.IO.Compression
namespace , actually resides in the System.IO.Compression.FileSystem
assembly, so you need to add a reference to that in your controller. The user is presented with a list of checkboxes representing a selection of files to choose from. Submitting the form will result in just those files being packaged up into one zip file and downloaded.
The list of files is passed to the view via
ViewBag
:public ActionResult Index() { ViewBag.Files = Directory.EnumerateFiles(Server.MapPath("~/pdfs")); return View(); }
The files are listed within a form with a set of checkboxes:
<h2>Select downloads</h2> @using(Html.BeginForm("Download", "Home")) { foreach(string file in ViewBag.Files) { <input type="checkbox" name="files" value="@file" /> @: @Path.GetFileNameWithoutExtension(file) <br /> } <div> <button class="btn btn-default">Submit</button> </div> }
The form posts to an action called
Download
which consists of the following code:[HttpPost] public FileResult Download(List<string> files) { var archive = Server.MapPath("~/archive.zip"); var temp = Server.MapPath("~/temp"); // clear any existing archive if (System.IO.File.Exists(archive)) { System.IO.File.Delete(archive); } // empty the temp folder Directory.EnumerateFiles(temp).ToList().ForEach(f => System.IO.File.Delete(f)); // copy the selected files to the temp folder files.ForEach(f => System.IO.File.Copy(f, Path.Combine(temp, Path.GetFileName(f)))); // create a new archive ZipFile.CreateFromDirectory(temp, archive); return File(archive, "application/zip", "archive.zip"); }
The user selection is captured in the
files
parameter. The code checks to see if a file called archive.zip exists from previous operations and it it does, it is deleted. Then a folder called temp is cleared of any existing files. Next,the selected files are copied from their source directory to the temp folder. The ZipFile.CreateFromDirectory
method generates a zip file from the temp directory contents and saves it as archive.zip. Finally, it is written to the Response
.
Both of these examples are simplified to illustrate the main classes and methods required to perform the tasks as clearly as possible. When handling the upload, you should add validation to check that the uploaded file is in fact a zip file, for example. Also, the zip file that gets created is placed into a hardcoded folder. If you have a busy site where multiple users are downloading zip files at the same time, you may want to use a Guid as a folder name instead to avoid the possibility of one user's download overwriting another.
No comments:
Post a Comment