C# 如何压缩文件并通过HTTP发送,而无需写入磁盘或在内存中加载完整文件?

C# 如何压缩文件并通过HTTP发送,而无需写入磁盘或在内存中加载完整文件?,c#,http,stream,.net-core,C#,Http,Stream,.net Core,我的要求是上传一个zip格式的文件到某个目的地 该文件需要以zip文件的形式通过HTTP发布到目标 帖子必须是包含额外数据的多部分消息(我认为这与我的问题无关) 解决方案在.Net核心中 我有一些工作代码;但是,这需要我将输入流复制到内存流中进行压缩,从而将完整文件加载到内存中 当文件大于可用内存时,这将成为一个问题,导致我的进程因OOM而结束 代码如下: using System; using System.IO; using System.IO.Compression; using Sy

我的要求是上传一个zip格式的文件到某个目的地

  • 该文件需要以zip文件的形式通过HTTP发布到目标
  • 帖子必须是包含额外数据的多部分消息(我认为这与我的问题无关)
  • 解决方案在.Net核心中
我有一些工作代码;但是,这需要我将输入流复制到内存流中进行压缩,从而将完整文件加载到内存中

当文件大于可用内存时,这将成为一个问题,导致我的进程因OOM而结束

代码如下:

using System;
using System.IO;
using System.IO.Compression;
using System.Net.Http;
using System.Net.Http.Headers;

namespace HttpZipPipe
{
    public class Program
    {
        private const string sourceUrl = "https://aacapps.com/lamp/sound/amy.wav";
        private const string destUrl = "http://httpbin.org/post";    

        public static Stream CreateZipStream(Stream inputStream, string zipEntryName)
        {
            var zipStream = new MemoryStream();
            using (var zipArchive = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
            {
                var zipEntry = zipArchive.CreateEntry(zipEntryName);
                using (var zipEntryStream = zipEntry.Open())
                    inputStream.CopyTo(zipEntryStream);
            }
            zipStream.Seek(0, SeekOrigin.Begin);
            return zipStream;
        }

        static void Main(string[] args)
        {
            String responseMessage;
            var Client = new HttpClient();

            using (var httpStream = Client.GetStreamAsync(sourceUrl).Result)
            using (var zipStream = CreateZipStream(httpStream, "audio.wav"))
            using (var fileContent = new StreamContent(zipStream))
            {  
                var content = new MultipartFormDataContent();
                content.Add(fileContent, "file", "file.zip");
                // ignored additional content and headers for clarity...
                responseMessage = Client.PostAsync(destUrl, content).Result.Content.ReadAsStringAsync().Result;
            }
            Console.WriteLine(responseMessage);
        }
    }
}
问题是“CreateZipStream”方法中发生了什么,特别是:

inputStream.CopyTo(zipEntryStream);
我怀疑这是导致我的进程失败的原因


有没有一种方法可以通过zip流将输入流传输到内容,而不必复制内存中的全部内容?

我不想使用您的服务,所以我使用了一个常规的web应用程序来使用
响应进行测试,但类似的方法应该可以工作。你必须同时读和写

我还使用了
SharpZipLib
作为
nuget

对于文件,您必须向数据中添加边界和文件名(在SO中添加的多部分消息)。有一些关于如何做到这一点的帖子

// Create the request
var request = WebRequest.Create("https://aacapps.com/lamp/sound/amy.wav");
request.UseDefaultCredentials = true;

var size = 1024 * 8;
var buffer = new byte[size];

// Create a POST request
// The four next rows I haven't tested but it's a regular POST you'll need to do
var sq = WebRequest.Create("http://httpbin.org/post");
sq.Method = "POST";
sq.ContentType = "application/octet-stream";

// Get the stream to write to
using (var res = sq.GetRequestStream())
{
    // Create zip using the httpbin request stream as writer
    using (var zip = new ZipOutputStream(res))
    {
        zip.SetLevel(3);

        // Create file entry
        var entry = new ZipEntry(ZipEntry.CleanName("amy.wav"));
        zip.PutNextEntry(entry);

        // Get the data stream
        using (var stream = request.GetResponse().GetResponseStream())
        {
            int numBytes;
            // Read the data until no more
            while ((numBytes = stream.Read(buffer, 0, size)) > 0)
            {
                // Write to the zip file buffer
                zip.Write(buffer, 0, size);
            }
        }
        zip.Close();
    }
}

// Didn't try these either but it's just reading the result if any
var resp = sq.GetResponse();
new StreamReader(resp.GetResponseStream()).ReadToEnd();

谢谢你的回复。我关心的是这段代码:
while((numBytes=stream.Read(buffer,0,size))>0{zip.Write(buffer,0,size);}
将在发送响应之前一直填充内存中的缓冲区。简而言之,这似乎不像我想的那样做“管道”。不,缓冲区只是
1024*8
。数据直接通过流发送。正如您所看到的,没有文件或其他存储数据的地方。想想它是如何写入磁盘的;当数据被压缩成
1024*8
块并放入文件流时,文件会增长。碰巧它现在是一个网络流。