我正在尝试压缩文本文件并将其拆分为控制台应用程序中的块(字节[])。
public List<byte[]> CreateChunks(string fileName, string txtFilePath)
{
long chunkSize = 100 * 1000;//100kb
var fileChunks = new List<byte[]>();
using (var memoryStream = new MemoryStream())
{
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, false))
{
zipArchive.CreateEntryFromFile($"{txtFilePath}", fileName, CompressionLevel.Optimal);
memoryStream.Position = 0;
var buffer = new byte[chunkSize];
while (memoryStream.Read(buffer, 0, buffer.Length) > 0)
{
fileChunks.Add(buffer);
}
}
}
return fileChunks;
}
使用这些块,我尝试在另一个应用程序中创建一个 zip 文件。
public void JoinChunks(List<byte[]> fileChunks, string filePath)
{
var memory = new MemoryStream();
using (var file = new FileStream(filePath + "\\temp.zip", FileMode.Create))
{
foreach (var item in fileChunks)
{
memory.Write(item, 0, item.Length);
}
memory.WriteTo(file);
file.Close();
}
}
查看创建的 zip 文件时,会弹出错误并显示“存档意外结束”。
如果我尝试对文本文件进行分块并将它们连接回来,那么它就可以正常工作。问题出在 ZIP 上。欢迎任何解决方案。
using (var memoryStream = new MemoryStream())
{
using (var zipArchive = new ZipArchive(memoryStream, ZipArchiveMode.Create, false))
{
zipArchive.CreateEntryFromFile($"{txtFilePath}", fileName, CompressionLevel.Optimal);
}
memoryStream.Position = 0;
var buffer = new byte[chunkSize];
while (memoryStream.Read(buffer, 0, buffer.Length) > 0)
{
fileChunks.Add(buffer);
}
}
即将非存档相关代码移出
using
对象的
zipArchive
语句。static byte[] CompressAsZip(string fileName, Stream fileStram)
{
using var memoryStream = new MemoryStream();
using var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, false);
using var entryStream = archive.CreateEntry(fileName).Open();
fileStram.CopyTo(entryStream);
archive.Dispose(); //<- Necessary to close the archive correctly
return memoryStream.ToArray();
}
使用带大括号的 using 语句,
archive.Dispose()
将在作用域结束时隐式调用。
另外,由于您使用的是 C# >8.0,我建议使用这种类型的异步实现,能够通过取消来归档多个文件:
static async Task<byte[]> CompressAsZipAsync(
IAsyncEnumerable<(string FileName, Stream FileStream)> files,
bool disposeStreamsAfterCompression = false,
CancellationToken cancellationToken = default)
{
using var memoryStream = new MemoryStream();
using (var archive = new ZipArchive(memoryStream, ZipArchiveMode.Create, false))
{
await foreach (var (FileName, FileStream) in files.WithCancellation(cancellationToken))
{
using var entryStream = archive.CreateEntry(FileName).Open();
await FileStream.CopyToAsync(entryStream, cancellationToken);
if (disposeStreamsAfterCompression)
await FileStream.DisposeAsync();
}
}
return memoryStream.ToArray();
}