创建 ZIP 文件然后发送给客户端

Create ZIP File Then Send to Client

我的网页中有一个按钮可以导出 CSV 文件。一共有5个文件。当客户端点击按钮时,服务器会创建文件,将它们压缩成一个ZIP文件,然后将ZIP文件发送给客户端下载。

我在论坛上听说过 SharpZipLabDotNetZip,但我还没有探索过。我也听说过使用 System.IO.Compression。您会推荐以下哪种方法?

我有创建 5 个 CSV 文件的代码:

StringBuilder sb = new StringBuilder();
        DataTable[] dtCSV =
        {
            file1BLO.SelectFile1ForCSV(),
            file2BLO.SelectFile2ForCSV(),
            file3BLO.SelectFile3ForCSV(),
            file4BLO.SelectFile4ForCSV(),
            file5BLO.SelectFile5ForCSV()
        };
        for (int i = 0; i <= 4; i++)
        {
            DataTable dt = dtCSV[i];
            foreach (DataRow dr in dt.Rows)
            {
                string[] fields = dr.ItemArray.Select(field => field.ToString()).ToArray();
                sb.AppendLine(string.Join("|", fields));
            }
            Response.ContentType = "application/text";
            Response.AddHeader("content-disposition", "attachment;filename=CAPRES-FILE" +
                (i + 1) + "-" + DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".txt");
            Response.Output.Write(sb);
            Response.Flush();
            sb.Clear();
        }
        Response.End();

编辑 我正在使用 ASP.NET v4.0.

编辑 2 显然我有 System.IO.Compression,这很奇怪,因为我认为它仅在 v4.5 中受支持。巧的是,我没有System.IO.Packaging.

Sachu的帮助下,我们完成了这个要求。由于许可问题,我们使用 DotNetZip 而不是 SharpZipLib

为了方便我们开发这个功能,我应该根据我的要求创建一个程序流程:

  1. 创建文本文件
  2. 将文本文件添加到文件夹
  3. Zip 格式压缩此文件夹
  4. 使用Response
  5. 发送给客户端
  6. 删除文件

步骤 0 - 安装项目

在我们开始这个过程之前,我们必须准备项目。这包括添加必要的文件夹和实例化变量。

首先我们添加一个文件夹,我们将 'temporarily' 添加文本文件。该文件夹也将被压缩。我决定在项目的根目录中创建名为 CSV.

的文件夹

现在我们将使用 DotNetZip 库。你可以下载它here。将库添加到您的项目引用中。然后加上using,就是using Ionic.Zip;.

然后我们实例化zipFileNametextFileName等变量,名字不言自明。

我将用于文本文件的数据来自 DataTable[] 数组,每个 DataTable 对应一个特定的 SQL 查询。

DataTable[] dtCSV =
{
    file1BLO.SelectFile1ForCSV(),
    file2BLO.SelectFile2ForCSV(),
    file3BLO.SelectFile3ForCSV(),
    file4BLO.SelectFile4ForCSV(),
    file5BLO.SelectFile5ForCSV()
};
StringBuilder sb = new StringBuilder();
string textFileNameTemplate = Server.MapPath(@"~\CSV") + @"\file";
Response.Clear();
Response.BufferOutput = false;
Response.ContentType = "application/zip";
Response.AppendHeader("content-disposition", "attachment;filename=CAPRES-" + 
    DateTime.Now.ToString("yyyyMMdd-HHmmss") + ".zip");

第 1 步 - 创建文本文件

这很容易。我使用 StringBuilder 来转换 DataTables 的结果。使用它,然后我使用 StreamWriter 自己构建文本文件。

for (int i = 0; i <= 4; i++)
{
    DataTable dt = dtCSV[i];
    foreach (DataRow dr in dt.Rows)
    {
        string[] fields = dr.ItemArray.Select(field => field.ToString()).ToArray();
        sb.AppendLine(string.Join("|", fields));
    }
    string textFileName = textFileNameTemplate + (i + 1) + ".txt";
    var textFile = new StreamWriter(textFileName);
    textFile.WriteLine(sb.ToString());
    textFile.Flush();
    textFile.Close();
}

注意我是如何使用 textFileNameTemplate 变量的。我附加了迭代器和 .txt 文件扩展名。因此,我们将有名为 file1.txtfile2.txtfile3.txt 等的文件

第 3 步和第 4 步 - 压缩文件夹并发送给客户端

现在我们可以继续压缩了。我们修改了步骤 2 中的代码以适应该库。

using (ZipFile zip = new ZipFile()) //encapsulate Step 2 code in this code block
{
    for (int i = 0; i <= 4; i++)
    {
        DataTable dt = dtCSV[i];
        foreach (DataRow dr in dt.Rows)
        {
            string[] fields = dr.ItemArray.Select(field => field.ToString()).ToArray();
            sb.AppendLine(string.Join("|", fields));
        }
        string textFileName = textFileNameTemplate + (i + 1) + ".txt";
        var textFile = new StreamWriter(textFileName);
        textFile.WriteLine(sb.ToString());
        textFile.Flush();
        textFile.Close();
        sb.Clear();
        zip.AddFile(textFileName, @"\"); //this is new
    }
    zip.Save(Response.OutputStream); //this is also new
}
Response.Flush();
Response.End(); 

zip.AddFile(textFileName, @"\"); 将文本文件添加到存档中。 @"\" 表示 DotNetZip 不会创建指向该文件的子文件夹,例如如果我的文件在此路径中:C:\User\Documents\...\file1.txt,存档将具有类似的文件夹结构。使用 @"\",存档将仅包含文本文件。

还要注意 sb.Clear(); 及其在代码中的位置。重要的是它在 for 循环内但在 textFile.WriteLine(sb.ToString()); 行之后。这确保之前写入的字符串在再次循环之前被清除。这样可以避免将字符串从 File1 转移到 File2,以及将 File2 转移到 File3,等等。

zip.Save(Response.OutputStream); 会直接输出 Zip 文件到 Response 而不会在服务器中保存文件。

第 5 步 - 删除文件

这一步取决于您的要求。对我来说,我们将删除生成的文件。使用 System.IO.File,我们将删除文本文件。在 using ZipFile zip = new ZipFile()) 代码块之后,我们将添加以下行:

for (int i = 1; i <= 5; i++)
{
    File.Delete(textFileNameTemplate + i + ".txt");
}

我的代码可能不是最优化的代码。但它有效。如果有人可以建议更好的代码,那就太好了。但现在,我将使用这段代码。非常感谢!特别是 Sachu,一个非常乐于助人的人。