【问题标题】:how to upload big data to a host with webclient如何使用 webclient 将大数据上传到主机
【发布时间】:2019-03-03 05:35:52
【问题描述】:

我需要一个函数来将大数据文件上传到服务器,作为来自外部服务提供商的带有 POST 的 HTTP 上传。 在我使用以下 webclient 功能的那一刻,它适用于较小的文件:

_byteReturn = await _webClient.UploadDataTaskAsync(_url, File.ReadAllBytes(@"c:\tmp\test.zip"));

但在这种情况下存在 2GB 边界的问题,函数 ReadAllBytes() 将所有字节读取到内存中。 当然我可以使用另一个 weblient 功能

_byteReturn = await _webClient.UploadFileTaskAsync(_url, @"c:\tmp\test.zip"));

但使用该功能,我从服务器收到 HTTP 错误 400。 :/ 所以它尝试使用我自己的代码进行上传。

using (WebClient _webClient = new WebClient())
{
    _webClient.Headers[HttpRequestHeader.UserAgent] = "Test";
    _webClient.Headers[HttpRequestHeader.CacheControl] = "no-cache";
    _webClient.Headers[HttpRequestHeader.Authorization] = string.Format("Basic {0}", Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes("Username") + ":" + ("Password" )));

    using (StreamWriter _output = new StreamWriter(await _webClient.OpenWriteTaskAsync(_url)))
    {

        _output.AutoFlush = true;


        using (FileStream _fileStream = new FileStream(@"c:\tmp\install.esd", FileMode.Open, FileAccess.Read))
        {
            _bytesRead = 0;
            _readByteBuffer = new byte[_bufferLength];
            _bytesToRead = _fileStream.Length;


#if DEBUG

            FileStream _testOutFileStream = new FileStream(_writeTestFileNameZip, FileMode.OpenOrCreate, FileAccess.ReadWrite);
#endif
            do
            {
                _fileStream.Seek(_bytesRead, SeekOrigin.Begin);
                _readCount = _fileStream.Read(_readByteBuffer, 0, _bufferLength);
                _output.Write(_readByteBuffer);

#if DEBUG
                if (_testOutFileStream != null)
                { 
                    _testOutFileStream.Write(_readByteBuffer, 0, _readCount);
                    _testOutFileStream.Flush();
                }
#endif
                _bytesRead += _readCount;
            }
            while (_readCount > 0);

#if DEBUG
            if (_testOutFileStream != null)
                _testOutFileStream.Dispose();
#endif
        }

        if (_output != null)
            _output.Close();
    }
}

重点是“它可以工作”。我在上传过程中没有收到任何错误,上传完成后我从服务器得到了正确的答案,但是上传速度非常快。(在 10 秒内以 10MBit/s 的速度上传 1GB)。

我相信这是一个缓存问题,但我不确定。谁知道问题出在哪里?

【问题讨论】:

    标签: c# file-upload webclient


    【解决方案1】:

    您能否尝试下面的代码,如果它为您解决了问题,请告诉我,您需要重新配置您的变量/等...

    string _username = string.Empty;
    string _password = string.Empty;
    string _url = "http://example.com";
    string _writeTestFileNameZip = string.Empty;
    
    using (WebClient _webClient = new WebClient())
    {
        _webClient.Headers[HttpRequestHeader.UserAgent] = "Test";
        _webClient.Headers[HttpRequestHeader.CacheControl] = "no-cache";
        _webClient.Headers[HttpRequestHeader.Authorization] = $"{Convert.ToBase64String(Encoding.ASCII.GetBytes($"{_username}:{_password}"))}";
    
    
        using (Stream _output = await _webClient.OpenWriteTaskAsync(_url))
        using (FileStream _fileStream = new FileStream(@"c:\tmp\install.esd", FileMode.Open, FileAccess.Read))
        {
            byte[] _readByteBuffer = new byte[1024 * 4];
            long _bytesToRead = _fileStream.Length;
            int _bytesRead = 0;
    
            _fileStream.Seek(0, SeekOrigin.Begin);
    
            while ((_bytesRead = await _fileStream.ReadAsync(_readByteBuffer, 0, _readByteBuffer.Length)) > 0)
            {
                await _output.WriteAsync(_readByteBuffer, 0, _bytesRead);
            }
        }
    
    }
    

    【讨论】:

    • 感谢该提示,是的,它有效但很奇怪。关键是,我在等待服务器响应,在我的版本中,我在上传后直接得到响应,这意味着一切正常,但上传无法完成。你的版本是上传(字节的写入)也非常快,就像我的版本一样,但是程序正在等待服务器响应,直到上传真正完成。所以我领先一步,但我必须实时向用户显示进度,并且愚蠢的程序加载仍然在内存中的上传数据。 ((
    【解决方案2】:

    根据 Aydin Adn 和我的其他搜索,我找到了最终解决方案。 需要将 AllowWriteStreamBuffering 属性设置为 false。这在原始 webclient 中是不可能的,但在扩展类中是不可能的。就我而言,这很容易,因为我已经编写了自己的网络客户端来处理响应数据。在那里我用以下代码覆盖了函数 GetWebRequest

    protected override WebRequest GetWebRequest(Uri _uri)
    {
    
        HttpWebRequest _webRequest = base.GetWebRequest(_uri) as HttpWebRequest;
    
        if (_webRequest != null)
        {
            // no buffer
            _webRequest.AllowWriteStreamBuffering = false;
            // if data size overhanded in constructur(necessary with AllowWriteStreamBuffering ==  false)
            if (this.ContentLength > 0)
                _webRequest.ContentLength = this.ContentLength;
            // if NO data size overhanded in constructur(necessary with AllowWriteStreamBuffering ==  false)
            else
                _webRequest.SendChunked = true;
            // if timeout overhanded in constructur
            if (this.TimeOut > 0)
                _webRequest.Timeout = this.TimeOut * 1000;
    
            return (_webRequest);
        }
        else
            return (null);
    }
    

    【讨论】:

      猜你喜欢
      • 2022-06-14
      • 2021-10-31
      • 2023-03-31
      • 1970-01-01
      • 2013-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多