我在从 grpc 连接创建 ZipArchive 时遇到问题。 架构:我有带有 zip 创建功能的服务。我从第三方服务获取了一些数据,根据这些数据生成了 csv 文件并将其放入 zip 存档中。 之后,我得到了内存流(它是 zip 的父级),读到最后,得到字符串,将其发送到另一个服务并清理它。就我而言,这是必要的,因为来自第三方服务的数据很可能会很大,所以我需要节省块发送的机会。 使用 using 关闭 zip 后,我发送 eocd 字节。
在另一边,我得到了这些字符串,将它们转换为字节数组,将其合并并尝试重新创建 zip 文件。
ZipArchive 创建成功,但没有条目。我遇到错误了
"Error executing Write request: Number of entries expected in End Of Central Directory does not correspond to number of entries in Central Directory."
在探索了 ZipArchive 类的内部结构后,我发现中央目录需要一个文件,但我得到了零个文件。
两个服务中的字节数(发送方
接收器)是相等的。
并且有 100% zip,因为字节头与 zip 存档规范相对应。
我不知道出了什么问题。
代码如下。
服务发送者
// just call for destination
using var call = await _destinationService.InitCall();
using (var stream = new MemoryStream())
{
using (var zip = new ZipArchive(stream, ZipArchiveMode.Create, true))
{
var entry = zip.CreateEntry($"{Model.FileName}.{Model.Format}");
using var writer = new StreamWriter(entry.Open(), Model.Encoding);
var csvConfiguration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
Delimiter = Model.Delimiter
};
using var csv = new CsvWriter(writer, csvConfiguration);
var columns = await _exportService.GetAndWriteColumns(csv, firstChunk, Model, cancellationToken);
// initalChunk to memoryStream
await _exportService.PerformExport();
while (_substreamData.TryDequeue(out var data) || !_isSubstreamEof)
{
// next chunks
await _exportService.PerformExport();
}
}
// sending eocd bytes after closing zip
await _writeDataService.WriteDataPartAsync(call, stream, cancellationToken);
await call.RequestStream.CompleteAsync();
}
// PerformingExport
public async Task PerformExport(CsvWriter csv, StreamWriter writer)
{
// generating csv, getting data from third party services
await csv.FlushAsync();
await writer.FlushAsync();
await WriteDataPartAsync(call, stream, cancellationToken);
stream.Clear();
}
public async Task WriteDataPartAsync(
AsyncDuplexStreamingCall<WriteData, WriteResponse> call,
Stream stream,
CancellationToken cancellationToken)
{
stream.Seek(0, SeekOrigin.Begin);
using (var streamReader = new StreamReader(stream, leaveOpen:true))
{
var streamString = await streamReader.ReadToEndAsync(cancellationToken);
await call.RequestStream.WriteAsync(
new WriteData
{
DataPart = new WriteChunk
{
Data = streamString
}
},
cancellationToken);
}
}
public static void Clear(this MemoryStream source)
{
var buffer = source.GetBuffer();
Array.Clear(buffer, 0, buffer.Length);
source.Position = 0;
source.SetLength(0);
}
服务接收者
var bytes = new List<byte[]>();
while (await requestStream.MoveNext(context.CancellationToken))
{
try
{
var data = Encoding.UTF8.GetBytes(requestStream.Current.DataPart.Data);
bytes.Add(data);
}
catch (Exception ex)
{
_logger.LogError($"Error executing Write request: {ex.Message}");
errors.Add(ex.Message);
}
}
var stream1 = new MemoryStream(bytes.SelectMany(x => x).ToArray());
using var zipArchiveSubexport = new ZipArchive(stream1); // success
var t = zipArchiveSubexport.Entries.First(); // error because of number if entries
我做错了什么?
这都是关于编码的。 UTF8 不适合此目的。我在 base64 字符串上重写它并且它有效