FileStream 损坏的 zip - SignalR Stream

FileStream corrupt zip - SignalR Stream

我正在尝试获取在客户端上创建的 zip 文件,并通过 Hub 流以块的形式上传该文件。当流结束时,我尝试打开文件,windows 表示无法打开,{file name} 无效。

在执行 File.WriteAllBytes(path, bytes[]) 时,字节数组在分块之前在客户端上写得很好。查看流文件时文件大小相同,File.WriteAllBytes.

我没主意了...

客户端

private async IAsyncEnumerable<byte[]> StreamBytes(byte[] bytes)
    {
        //this works and I'm able to open the file it creates.
        File.WriteAllBytes(@"C:\test.zip", bytes);
        long fileSize = bytes.Length;
        long fileWrite = 0;

        while (fileSize != 0)
        {
            byte[] buffer = fileSize > ByteHelper.BUFFER_SIZE ? new byte[ByteHelper.BUFFER_SIZE] : new byte[fileSize];
            Array.Copy(bytes, buffer, buffer.Length);

            fileSize -= buffer.Length;
            fileWrite += buffer.Length;

            var bufResult = await Task.FromResult(buffer);
            yield return bufResult;
        }
    }

服务器端

public async Task UploadCommandResultStream(IAsyncEnumerable<byte[]> byteChunk, int commandQueueKey, string folder)
    {
        var path = Path.Combine(_settings.UploadPath, folder);
        if (Directory.Exists(path) == false)
        {
            Directory.CreateDirectory(path);
        }

        var file = Path.Combine(path, $"{commandQueueKey}.zip");
        long bytesread = 0;
        try
        {
            //this creates a file but can't open
            using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read, ByteHelper.BUFFER_SIZE))
            {
                await foreach (var bytes in byteChunk)
                {
                    fs.Write(bytes, 0, bytes.Length);
                    bytesread += bytes.Length;
                }
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "asyncwrite");
        }
    }

您可能需要改变方法;新提议的功能 Async Streams in C# 8 使异步模式更加灵活,但我认为这种方法不会正确结束或刷新 FileStream 对象。请尝试使用此语法移动最后一个方法:

//this creates a file but can't open
using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read, ByteHelper.BUFFER_SIZE, true))
{
   await fs.WriteAsync(bytes, 0, bytes.Length);
}

我相信您的文件没有完全清除最后一个缓冲区。试试改成这个

//this creates a file but can't open
using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.Read, ByteHelper.BUFFER_SIZE))
{
    await foreach (var bytes in byteChunk)
    {
        fs.Write(bytes, 0, bytes.Length);
        bytesread += bytes.Length;
    }
    fs.Flush(); //or await fs.FlushAsync()
}

好的,我找到答案了。它是客户端的 IAsyncEnumerable。作为测试,我在客户端将文件写入磁盘,我知道这是可行的,然后打开一个 FileStream 并分块读取产生结果。

仍在调查为什么原始客户端代码错误,但现在 100% 有效。

代码需要稍微清理一下,因为可以更好地处理修剪缓冲区,但只是写得很快。

客户端

private async IAsyncEnumerable<byte[]> StreamBytes(byte[] bytes)
    {
        string fileName = @"test.zip";
        File.WriteAllBytes(fileName, bytes);

        using(var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read, ByteHelper.BUFFER_SIZE, true))
        {
            long fileSize = fs.Length;
            int totalBytesRead = 0;
            byte[] buffer = new byte[ByteHelper.BUFFER_SIZE];

            while (fileSize > 0)
            {
                fs.Seek(totalBytesRead, SeekOrigin.Begin);
                var bytesRead = await fs.ReadAsync(buffer, 0, ByteHelper.BUFFER_SIZE);
                if (bytesRead == 0)
                    break;

                totalBytesRead += bytesRead;
                fileSize -= bytesRead;

                if (bytesRead != ByteHelper.BUFFER_SIZE)
                {
                    byte[] trimmedBuffer = new byte[bytesRead];
                    Array.Copy(buffer, trimmedBuffer, bytesRead);

                    buffer = new byte[bytesRead];
                    Array.Copy(trimmedBuffer, buffer, bytesRead);
                }

                yield return buffer;
            }
        }
        //long fileSize = bytes.Length;
        //long fileWrite = 0;

        //while (fileSize != 0)
        //{
        //    byte[] buffer = fileSize > ByteHelper.BUFFER_SIZE ? new byte[ByteHelper.BUFFER_SIZE] : new byte[fileSize];
        //    Array.Copy(bytes, buffer, buffer.Length);

        //    fileSize -= buffer.Length;
        //    fileWrite += buffer.Length;

        //    var bufResult = await Task.FromResult(buffer);
        //    yield return bufResult;
        //}
    }