我在从GRPC连接创建ZipArchive时遇到了麻烦. 模式:我有服务与压缩创建功能.我从第三方服务商那里获得了一些数据,根据这些数据生成了CSV文件,并将其放入了Zip存档中. 在那之后,我得到了Memory Stream(它是Zip的父级),读到最后,得到字符串,发送到另一个服务并清理它.在我的情况下,这是必要的,因为来自第三方服务的数据非常有可能是巨大的,所以我需要节省大量发送的机会. 在使用结束压缩后,我发送了eocd字节.
另一方面,我得到了这些字符串,将它们转换为字节数组,并将其合并,然后try 重新创建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类的Enrains之后,我发现中央目录需要一个文件,但我得到的却是零.
Number of bytes in both service (sender\receiver) is equal.
And there is 100% zip, because byte headers are corresponding with zip archive specs.
I have no idea what is wrong.
Code is below.
加油站
// 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
我做错了什么?