简体   繁体   English

ASP.NET 下载 csv 文件为 zip?

[英]ASP.NET download csv file as zip?

I've been reading through:我一直在阅读:

https://www.aspsnippets.com/Articles/Export-data-from-SQL-Server-to-CSV-file-in-ASPNet-using-C-and-VBNet.aspx https://www.aspsnippets.com/Articles/Export-data-from-SQL-Server-to-CSV-file-in-ASPNet-using-C-and-VBNet.aspx

Rather than only have the option to download as csv as described there in:而不是像 csv 中描述的那样只能选择下载:

                //Download the CSV file.
                Response.Clear();
                Response.Buffer = true;
                Response.AddHeader("content-disposition", "attachment;filename=SqlExport.csv");
                Response.Charset = "";
                Response.ContentType = "application/text";
                Response.Output.Write(csv);
                Response.Flush();
                Response.End();

is there a way using native asp.net to first zip the csv output from the csv variable in Response.Output.Write(csv);有没有办法使用本机 asp.net 到第一个 zip csv output 来自 Response.Output.Write(csv) 中的 csv 变量; so that the user downloads SqlExport.zip rather than SqlExport.csv?以便用户下载 SqlExport.zip 而不是 SqlExport.csv?

Roughly based on this , you can create a zip file while streaming it to the client;大致基于,您可以创建一个 zip 文件,同时将其推流到客户端;

Response.ContentType = "application/octet-stream";
Response.Headers.Add("Content-Disposition", "attachment; filename=\"SqlExport.zip\"");

using var archive = new ZipArchive(Response.Body, ZipArchiveMode.Create);

var entry = archive.CreateEntry("SqlExport.csv");
using var entryStream = entry.Open();

entryStream.Write(csv); // write the actual content here

entryStream.Flush();

Though rather than appending to a single csv string, you should probably consider using a StreamWriter to write each snippet of text directly into the response stream. Substituting from your linked csv example;虽然不是附加到单个csv字符串,您应该考虑使用StreamWriter将每个文本片段直接写入响应 stream。从链接的 csv 示例中替换;

using var sw = new StreamWriter(entryStream);

// TODO write header

foreach (DataRow row in dt.Rows)
{
    foreach (DataColumn column in dt.Columns)
    {
        //Add the Data rows.
        await sw.WriteAsync(row[column.ColumnName].ToString().Replace(",", ";") + ',');
    }
    //Add new line.
    await sw.WriteLineAsync();
}

Though that is a terrible example of a csv file.尽管这是 csv 文件的一个糟糕示例。 Rather than substituting ';'而不是替换';' characters, the string should be quoted & all quotes escaped.字符,字符串应该被引用并转义所有引号。

However Response.Body is only available in .net 5 / core.然而Response.Body仅在 .net 5 / core 中可用。 To write directly to a http response in .net 4.8 or earlier, you'll have to write your own HttpContent .要在 .net 4.8 或更早版本中直接写入 http 响应,您必须编写自己的HttpContent Putting everything together, including a better csv formatter;将所有东西放在一起,包括更好的 csv 格式化程序;

public class ZipContent : HttpContent
{
    private DataTable dt;
    private string name;

    public ZipContent(DataTable dt, string name = null)
    {
        this.dt = dt;
        this.name = name ?? dt.TableName;
        Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
        Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
        {
            FileName = $"{name}.zip"
        };
    }

    private string formatCsvValue(string value)
    {
        if (value == null)
            return "";
        if (value.Contains('"') || value.Contains(',') || value.Contains('\r') || value.Contains('\n'))
            return $"\"{value.Replace("\"", "\"\"")}\"";
        return value;
    }

    private IEnumerable<DataColumn> Columns()
    {
        // Why is this not already an IEnumerable<DataColumn>?
        foreach (DataColumn col in dt.Columns)
            yield return col;
    }

    protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
    {
        using var archive = new ZipArchive(stream, ZipArchiveMode.Create);

        var entry = archive.CreateEntry($"{name}.csv");
        using var entryStream = entry.Open();
        using var sw = new StreamWriter(entryStream);

        await sw.WriteLineAsync(
            string.Join(",",
                Columns()
                .Select(c => formatCsvValue(c.ColumnName))
            ));

        foreach (DataRow row in dt.Rows)
        {
            await sw.WriteLineAsync(
                string.Join(",", 
                    row.ItemArray
                    .Select(o => formatCsvValue(o?.ToString()))
                ));
        }
    }

    protected override bool TryComputeLength(out long length)
    {
        length = 0;
        return false;
    }
}

Have a look at the ZipArchive Class看看ZipArchive Class

you can use public System.IO.Compression.ZipArchiveEntry CreateEntry (string entryName);你可以使用public System.IO.Compression.ZipArchiveEntry CreateEntry (string entryName); to create an ZipEntry nd add it to an archive创建一个 ZipEntry 并将其添加到存档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM