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

我做错了什么?

推荐答案

这里的问题是,您正在读取它,就好像它被编码为UTF8字符串一样,这是不会起作用的,因为许多字节与UTF8不兼容.

您需要直接传递字节

public async Task WriteDataPartAsync(
    AsyncDuplexStreamingCall<WriteData, WriteResponse> call,
    Stream stream,
    CancellationToken cancellationToken)
{
    await call.RequestStream.WriteAsync(
            new WriteData
            {
                DataPart = new WriteChunk
                {
                    Data = stream.ToArray(),
                }
            },
            cancellationToken);
}

另一边:

var stream1 = new MemoryStream(requestStream.Current.DataPart.Data);
using var zipArchiveSubexport = new ZipArchive(stream1);
var t = zipArchiveSubexport.Entries.First();

如果你不能改变包的格式,你将不得不使用Base64编码.

public async Task WriteDataPartAsync(
    AsyncDuplexStreamingCall<WriteData, WriteResponse> call,
    Stream stream,
    CancellationToken cancellationToken)
{
    await call.RequestStream.WriteAsync(
            new WriteData
            {
                DataPart = new WriteChunk
                {
                    Data = Convert.ToBase64String(stream.GetBuffer(), 0, stream.Length),
                }
            },
            cancellationToken);
}

另一边:

var stream1 = new MemoryStream(Convert.FromBase64String(requestStream.Current.DataPart.Data));
using var zipArchiveSubexport = new ZipArchive(stream1);
var t = zipArchiveSubexport.Entries.First();

Csharp相关问答推荐

在C# 11之前, struct 中的每个字段都必须显式分配?不能繁殖

使用C#中的Shape API从Azure目录获取所有用户

注册通用工厂的C# Dep注入

在C#中使用in修饰符

将委托传递到serviceccollection c#web API

ASP.NET核心结果.文件vs结果.流

更新产品但丢失产品ASP.NET Core的形象

有没有办法在WPF文本框中添加复制事件的处理程序?

Blazor EventCallback<;MyType<;T>;>;

应用程序启动器,可 Select 物理屏幕

Blazorise折线图仅绘制数据集的一部分

为基本审计设置Audit.EntityFramework.Core

在try 使用访问服务器上的文件夹时,如何解决CORS错误.NET核心API

具有嵌套属性的IGGroup

处理方法内部过滤与外部过滤

默认架构不存在EF核心迁移

如何在flutter dart中使用publicKey.xml文件进行rsa加密,我遇到了问题Exception:Could not parse BigInt

无法创建工具窗口(用于VBIDE、VBA的COM加载项扩展)

初始化具有EntityFrameworkCore和不同架构的数据库时引发System.MissingMethodExcept

C#如何替换两个XML元素值?