将多个文件(具有不同文件类型)从数据库(字节数组)导出到单个压缩文件
Export multiple files (with different file types) from database (Byte Array) to single zipped file
我需要导出存储在数据库(字节数组)中的具有不同文件类型(pdf、xlsx、.docx)的多个文件,并将它们另存为单个压缩文件。我应该如何处理多个文件?我假设我需要先将文件存储在列表中并使用 MemoryStream?我正在使用 ZipArchive class 将文件导出为 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 建议的方法将文件放入内存流和 return 字节数组:
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;
}
你似乎大部分时间都在那里,事实上我认为你需要使用 List<ZipList>
因为你的 byteArrayList
不包含 fileNameor
Length` 的定义。
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());
}
}
你可以用一块石头杀死几只鸟,而且不需要额外的模型就可以一次完成(这还没有经过测试,但你会明白要点):
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;
}
我需要导出存储在数据库(字节数组)中的具有不同文件类型(pdf、xlsx、.docx)的多个文件,并将它们另存为单个压缩文件。我应该如何处理多个文件?我假设我需要先将文件存储在列表中并使用 MemoryStream?我正在使用 ZipArchive class 将文件导出为 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 建议的方法将文件放入内存流和 return 字节数组:
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;
}
你似乎大部分时间都在那里,事实上我认为你需要使用 List<ZipList>
因为你的 byteArrayList
不包含 fileNameor
Length` 的定义。
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());
}
}
你可以用一块石头杀死几只鸟,而且不需要额外的模型就可以一次完成(这还没有经过测试,但你会明白要点):
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;
}