【问题标题】:Export multiple files (with different file types) from database (Byte Array) to single zipped file将多个文件(具有不同文件类型)从数据库(字节数组)导出到单个压缩文件
【发布时间】:2020-11-27 09:05:08
【问题描述】:

我需要导出存储在数据库(字节数组)中的具有不同文件类型(pdf、xlsx、.docx)的多个文件,并将它们保存为单个压缩文件。我应该如何处理多个文件?我假设我需要先将文件存储在列表中并使用 MemoryStream?我正在使用 ZipArchive 类将文件导出为 zip 文件。假设这种方法可行,我不确定如何将列表作为参数传递给 ZipArchive (DownloadMultipleFiles) 方法。

protected void lnkExport_Click(object sender, EventArgs e)
{
    string applicationID = ((sender as LinkButton).CommandArgument);
    var myList = GetFilesandConvertToList(applicationID);
    DownloadMultipleFiles(myList); //How would I pass myList as an argument here? Obviously, this would not work.
}

调用存储过程来获取文件并将它们放在一个列表中:

public List<ZipList> GetFilesandConvertToList(string applicationID)
{           
    List<ZipList> fileList = new List<ZipList>();
    SqlCommand cmd = new SqlCommand("dbo.spGetFilesByID", ConnC.con);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@ApplicationID", applicationID); //This will return several files (different file types using the ID)
    ConnC.con.Open();
    using (SqlDataReader sdr = cmd.ExecuteReader())
    {
        if (sdr.HasRows)
        {
            while(sdr.Read())
            {
                ZipList zl = new ZipList();
                sdr.Read();
                zl.bytes = (byte[])sdr["FILE_CONTENT"];
                zl.contentType = sdr["FILE_TYPE"].ToString();
                zl.fileName = sdr["FILE_NAME"].ToString();
                fileList.Add(zl);
            }                    
         }
    }
    return fileList;
}

使用 ZipArchive 将列表放入 MemoryStream 并导出为 zip 文件:

public void DownloadMultipleFiles(List<byte[]> byteArrayList)
{
    using (MemoryStream ms = new MemoryStream())
    {
        using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create, true))
        {
            foreach (byte[] file in byteArrayList)
            {
                ZipArchiveEntry entry = archive.CreateEntry(file.fileName + ".pdf", CompressionLevel.Fastest);
                using (Stream zipStream = entry.Open())
                {
                    zipStream.Write(file, 0, file.Length);
                }
            }
        }
        return File(ms.ToArray(), "application/zip", "Archive.zip");
    }
}
 
public class ZipList
{
    internal byte[] bytes;
    internal string contentType;
    internal string fileName;
}

更新:我已经用@Andy 稍微修改的答案更新了这个方法。这很好用:

protected void lnkExport_Click(object sender, EventArgs e)
{
    string applicationID = ((sender as LinkButton).CommandArgument);
    var myList = GetFilesandConvertToList(applicationID);
    //Download Zipped File
    byte[] fileBytes = GetZipFileForApplicationId(applicationID);
    Response.Clear();
    Response.Buffer = true;
    Response.Charset = "";
    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.ClearContent();
    Response.AppendHeader("Content-Disposition", "attachment; filename=Application.zip");
    Response.AppendHeader("Content-Type", "application/zip");
    Response.BinaryWrite(fileBytes);
    HttpContext.Current.Response.Flush();
    HttpContext.Current.Response.SuppressContent = true;
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

使用@Andy 建议的方法将文件放入内存流并返回一个字节数组:

public byte[] GetZipFileForApplicationId(string applicationID)
{
    byte[] fileBytes = null;
    SqlCommand cmd = new SqlCommand("dbo.spGetFilesByID", ConnC.con);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@ApplicationID", applicationID);
    ConnC.con.Open();
    using (SqlDataReader sdr = cmd.ExecuteReader())
    {
        if (sdr.HasRows)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create, true))
                {
                    while (sdr.Read())
                    {
                        byte[] bytes = (byte[])sdr["FILE_CONTENT"];
                        string contentType = sdr["FILE_TYPE"].ToString();
                        string fileName = sdr["FILE_NAME"].ToString();

                        ZipArchiveEntry entry = archive.CreateEntry(fileName);
                        using (Stream zipStream = entry.Open())
                        {
                            zipStream.Write(bytes, 0, bytes.Length);
                        }
                    }
                }
                ms.Position = 0;
                fileBytes = ms.ToArray();

            }
        }
    }
    return fileBytes;
}

【问题讨论】:

  • @DaleK 当我尝试DownloadMultipleFiles(List&lt;ZipList&gt;); 我得到...is a type, which is not valid in the given context.
  • 我已将您的问题重新编辑以包含其原始内容,否则提供的答案将毫无意义。在这个网站上,您需要提出一个明确的问题,然后一旦人们发布了答案,就不要再从根本上改变它。如果您想向我们展示您最终使用的代码,请发布您自己的答案,因为这样未来的读者仍然清楚问题本身是什么以及可能的答案是什么。您也不应该将问题用作调试会话,如果您有其他问题,请再提出其他问题。

标签: c# asp.net memorystream


【解决方案1】:

看起来你大部分时间都在那里,事实上我认为你需要使用List&lt;ZipList&gt;,因为你的byteArrayList不包含fileNameorLength`的定义。

public void DownloadMultipleFiles(List<ZipList> zipList)
{
    using (MemoryStream ms = new MemoryStream())
    {
        using (ZipArchive archive = new ZipArchive(ms, ZipArchiveMode.Create, true))
        {
            foreach (var file in zipList)
            {
                ZipArchiveEntry entry = archive.CreateEntry(file.fileName + ".pdf", CompressionLevel.Fastest);
                using (Stream zipStream = entry.Open())
                {
                    zipStream.Write(file.bytes, 0, file.bytes.Length);
                }
            }
        }
        // Currently method returns void?
        // return File(ms.ToArray(), "application/zip", "Archive.zip");
        // Maybe you want
        File.WriteAllBytes("application/zip/Archive.zip", ms.ToArray());
    }
}

【讨论】:

  • 这确实回答了我的一个原始问题,关于如何将列表作为参数传递,但是,我修改了我的原始帖子,希望能消除我想要完成的困惑(返回一个压缩文件)并按照@Andy 的建议去做(用一块石头杀死几只鸟)。
【解决方案2】:

你可以用一块石头杀死几只鸟,并且不需要额外的模型就可以一次完成(这还没有经过测试,但你会明白要点):

public byte[] GetZipFileForApplicationId(string applicationID)
{
    SqlCommand cmd = new SqlCommand("dbo.spGetFilesByID", ConnC.con);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@ApplicationID", applicationID);
    ConnC.con.Open();
    using (SqlDataReader sdr = cmd.ExecuteReader())
    {
        if (sdr.HasRows)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                using (var archive = new ZipArchive(ms, ZipArchiveMode.Create, true))
                {
                    while(sdr.Read())
                    {
                        var bytes = (byte[])sdr["FILE_CONTENT"];
                        var contentType = sdr["FILE_TYPE"].ToString();
                        var fileName = sdr["FILE_NAME"].ToString();
                        
                        var entry = archive.CreateEntry(fileName);
                        using (var zipStream = entry.Open())
                        {
                            zipStream.Write(bytes, 0, bytes.Length);
                        }
                    } 
                }
                ms.Position = 0;
                // This is kind of redundant. You should return the
                // MemoryStream object instead of duplicating it's data.
                // I'll let you play with that.
                return ms.ToArray();
            }
        }
    }
    return null;
}

【讨论】:

  • 这让我非常接近。使用您的示例(稍作修改 - 请参阅我的原始帖子),我将如何返回字节以下载文件?
  • @Shane -- 查看所有答案:stackoverflow.com/questions/19778941/…
  • 一些小的修改修复了它(我已经更新了我的原始帖子)。谢谢你,效果很好!。
  • @Shane -- 很棒的工作。我喜欢计划好的时候。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-09
  • 2020-01-24
  • 2021-10-16
  • 2017-06-04
相关资源
最近更新 更多