如何使用WebClient将大数据上传到主机

时间:2018-09-27 10:17:34

标签: c# file-upload webclient

我需要一个功能,可以通过外部服务提供商的POST通过HTTP上传将大数据文件上传到服务器。 目前,我使用以下weblient函数,并且适用于较小的文件:

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

但是在那种情况下,存在2GB边框的问题,并且函数ReadAllBytes()将所有字节读取到内存中。 当然,我可以使用其他网络功能

_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();
    }
}

重点是“ IT WORKS”。我在上传过程中没有错误,并且在上传完成后从服务器得到了正确的答案,但是上传就像地狱一样快。(在10秒内以10MBit / s的速度上传1GB)。

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

2 个答案:

答案 0 :(得分: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);
        }
    }

}

答案 1 :(得分:0)

基于Aydin Adn和其他搜索结果,我找到了最终的解决方案。 必须将 AllowWriteStreamBuffering 属性设置为false。原始的webclient无法实现此功能,而只能在扩展类中实现。就我而言,这非常容易,因为我已经编写了自己的Web客户端来处理响应数据。在那里,我用以下代码覆盖了功能 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);
}