从 grpc 连接创建 ZipArchive

问题描述 投票:0回答:1

我在从 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

我做错了什么?

c# zip grpc-c#
1个回答
0
投票

这都是关于编码的。 UTF8 不适合此目的。我在 base64 字符串上重写它并且它有效

© www.soinside.com 2019 - 2024. All rights reserved.