web-dev-qa-db-ja.com

DotNetZipを使用したASP.NET MVCを介したZipファイルのダウンロード

フォルダーにテキストファイルを作成し、そのフォルダーを圧縮して、テスト目的で@sameロケーションを保存しました。そのZipファイルは、作成後にユーザーマシンに直接ダウンロードしたかったのです。私はdotnetzipライブラリを使用しており、次のことを行っています。

Response.Clear();
Response.ContentType = "application/Zip";
Response.AddHeader("content-disposition", "filename=" + "sample.Zip");
using (ZipFile Zip = new ZipFile())
{
    Zip.AddDirectory(Server.MapPath("~/Directories/hello"));
    Zip.Save(Server.MapPath("~/Directories/hello/sample.Zip"));
}

誰かがZipファイルをユーザー側でダウンロードする方法を提案できますか?

9
user2801336

次のように、コントローラのFileメソッドを使用してファイルを返すことができます。

public ActionResult Download()
{
    using (ZipFile Zip = new ZipFile())
    {
        Zip.AddDirectory(Server.MapPath("~/Directories/hello"));
        Zip.Save(Server.MapPath("~/Directories/hello/sample.Zip"));
        return File(Server.MapPath("~/Directories/hello/sample.Zip"), 
                                   "application/Zip", "sample.Zip");
    }
}

Zipファイルを保存する必要がない場合、サーバー上のファイルに書き込む必要はありません。

public ActionResult Download()
{
    using (ZipFile Zip = new ZipFile())
    {
        Zip.AddDirectory(Server.MapPath("~/Directories/hello"));

        MemoryStream output = new MemoryStream();
        Zip.Save(output);
        return File(output.ToArray(), "application/Zip", "sample.Zip");
    }  
}
23
mcserep

まず、サーバーのディスクにファイルを作成しない方法を検討してください。悪い練習。代わりに、ファイルを作成してメモリに圧縮することをお勧めします。以下の私の例をお役に立てば幸いです。

/// <summary>
///     Zip a file stream
/// </summary>
/// <param name="originalFileStream"> MemoryStream with original file </param>
/// <param name="fileName"> Name of the file in the Zip container </param>
/// <returns> Return byte array of zipped file </returns>
private byte[] GetZippedFiles(MemoryStream originalFileStream, string fileName)
{
    using (MemoryStream zipStream = new MemoryStream())
    {
        using (ZipArchive Zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
        {
            var zipEntry = Zip.CreateEntry(fileName);
            using (var writer = new StreamWriter(zipEntry.Open()))
            {
                originalFileStream.WriteTo(writer.BaseStream);
            }
            return zipStream.ToArray();
        }
    }
}

/// <summary>
///     Download zipped file
/// </summary>
[HttpGet]
public FileContentResult Download()
{
    var zippedFile = GetZippedFiles(/* your stream of original file */, "hello");
    return File(zippedFile, // We could use just Stream, but the compiler gets a warning: "ObjectDisposedException: Cannot access a closed Stream" then.
                "application/Zip",
                "sample.Zip");
}

上記のコードに関する注意:

  1. MemoryStreamインスタンスを渡すには、開いているか、有効であるかなどのチェックが必要です。それらは省略しました。コードをより堅牢にするために、MemoryStreamインスタンスの代わりにファイルコンテンツのバイト配列を渡したいのですが、この例では多すぎます。
  2. メモリに必要なコンテキスト(ファイル)を作成する方法は示していません。手順については MemoryStream classを参照してください。
4
Alex Klaus

klausソリューションの単なる修正:(コメントを追加できないため、別の回答を追加する必要があります!)

解決策は素晴らしいですが、私にとってはZipファイルが破損しており、Zipオブジェクトをファイナライズする前に返されるため、Zipを閉じずにZipが破損することがわかりました。

修正するには、Zipブロックを使用した後に戻り行を移動するだけで機能します。最終結果は次のとおりです。

/// <summary>
///     Zip a file stream
/// </summary>
/// <param name="originalFileStream"> MemoryStream with original file </param>
/// <param name="fileName"> Name of the file in the Zip container </param>
/// <returns> Return byte array of zipped file </returns>
private byte[] GetZippedFiles(MemoryStream originalFileStream, string fileName)
{
    using (MemoryStream zipStream = new MemoryStream())
    {
        using (ZipArchive Zip = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
        {
            var zipEntry = Zip.CreateEntry(fileName);
            using (var writer = new StreamWriter(zipEntry.Open()))
            {
                originalFileStream.WriteTo(writer.BaseStream);
            }
        }
        return zipStream.ToArray();
    }
}

/// <summary>
///     Download zipped file
/// </summary>
[HttpGet]
public FileContentResult Download()
{
    var zippedFile = GetZippedFiles(/* your stream of original file */, "hello");
    return File(zippedFile, // We could use just Stream, but the compiler gets a warning: "ObjectDisposedException: Cannot access a closed Stream" then.
                "application/Zip",
                "sample.Zip");
}
2
HamedH

App_Dataフォルダーから既存のZipファイルを返すだけの場合(Zipファイルをそこにダンプするだけ)、Homeコントローラーで次のアクションメソッドを作成します。

    public FileResult DownLoad(string filename)
    {
        var content = XFile.GetFile(filename);
        return File(content, System.Net.Mime.MediaTypeNames.Application.Zip, filename);

    }

Get Fileは拡張メソッドです。

   public static byte[] GetFile(string name)
    {
        string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
        string filenanme = path + "/" + name;
        byte[] bytes = File.ReadAllBytes(filenanme);
        return bytes;
    }

ホームコントローラーのインデックスビューは次のようになります。

@model  List<FileInfo>

<table class="table">
    <tr>
        <th>
            @Html.DisplayName("File Name")
        </th>
        <th>
            @Html.DisplayName("Last Write Time")
        </th>
        <th>
            @Html.DisplayName("Length (mb)")
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td>
                @Html.ActionLink("DownLoad","DownLoad",new {filename=item.Name})
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.LastWriteTime)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Length)
            </td>
        </tr>
    }
</table>

メインインデックスファイルのアクションメソッド:

    public ActionResult Index()
    {
        var names = XFile.GetFileInformation();
        return View(names);
    }

GetFileInformationは拡張メソッドです。

    public static List<FileInfo> GetFileInformation()
    {
        string path = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
        var dirInfo = new DirectoryInfo(path);
        return dirInfo.EnumerateFiles().ToList();
    }
0
John Peters