ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

wpf 上传文件带进度条

2022-09-08 15:33:02  阅读:182  来源: 互联网

标签:stream 进度条 totalBytes public var new wpf 上传 throw


在网上找了好久,才找到一位俄罗斯大神写的文章。

遇到超大文件的话还是会报异常。

 

服务端采用webapi

[Authorize]
[HttpPost]
public async Task<IActionResult> Post(IFormFile file)
{

var content = new MultipartFormDataContent();

var fileContent = new StreamContent(file.OpenReadStream());
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(file.ContentType);

Stream stream = file.OpenReadStream();

return Ok();

}

客户端wpf

public async Task UploadAsync(Uri uri, Stream stream, IProgress<float> progress, CancellationToken cancelToken = default(CancellationToken))
        {
            if (uri == null) throw new ArgumentNullException(nameof(uri));
            if (stream == null) throw new ArgumentNullException(nameof(stream));
            if (progress == null) throw new ArgumentNullException(nameof(progress));

            // Название файла
            var fileName = System.IO.Path.GetFileName(((FileStream)stream).Name);

            // Подготавливаем контент потока
            var streamContent = new ProgressStreamContent(stream);
            streamContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
            streamContent.ProgressChanged += (bytes, currBytes, totalBytes) 
                => progress.Report((float)currBytes / totalBytes * 100);

            // Данные на отправление
            var content = new MultipartFormDataContent();
            content.Add(streamContent, "file", fileName);

            try
            {
                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                    // Здесь скорее всего устанавливаем всякие заголовки
                    // ...

                    // Посылаем Post запрос
                    var response = await client.PostAsync(uri, content, cancelToken);

                    // Проверяем статус ответа
                    switch (response.StatusCode)
                    {
                        case HttpStatusCode.OK:
                            this.Close();
                            break;
                        default:
                            break;
                    /* Здесь проверяем статус ответа и предпринимаем действия */
                    }
                }
            }
            catch (HttpRequestException ex)
            {
                throw new Exception(ex.Message);
            }
        }
    public delegate void ProgressHandler(long bytes, long currentBytes, long totalBytes);

    class ProgressStreamContent : StreamContent
    {
        private const int DEFAULT_BUFFER_SIZE = 4096;

        public event ProgressHandler ProgressChanged = delegate { };

        private long currentBytes = 0;
        private long totalBytes = -1;


        public Stream InnerStream { get; }
        public int BufferSize { get; }

        public ProgressStreamContent(Stream innerStream, int bufferSize = DEFAULT_BUFFER_SIZE) :
            base(innerStream, bufferSize)
        {
            InnerStream = innerStream ?? throw new ArgumentNullException(nameof(innerStream));
            BufferSize = bufferSize > 0 ? bufferSize : throw new ArgumentOutOfRangeException(nameof(bufferSize));
        }

        private void ResetInnerStream()
        {
            if (InnerStream.Position != 0)
            {
                // Если внутренний поток нужно считать повторно, то этот внутренний поток должен поддерживать
                // возврат каретки(например FileStream), иначе внутренний поток не может быть считан повторно
                // в целевой поток(например NetworkStream)
                if (InnerStream.CanSeek)
                {
                    InnerStream.Position = 0;
                    currentBytes = 0;
                }
                else
                    throw new InvalidOperationException("The inner stream has already been read!");
            }
        }

        protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            if (stream == null) throw new ArgumentNullException(nameof(stream));

            // Сбрасываем состояние внутреннего потока
            ResetInnerStream();

            // Если общее количество байт еще не получено, то пытаемся получить
            // его из заголовков контента
            if (totalBytes == -1)
                totalBytes = Headers.ContentLength ?? -1;

            // Если общее количество байт еще не найдено, то пытаемся
            // вычислить его из потока
            if (totalBytes == -1 && TryComputeLength(out var computedLength))
                totalBytes = computedLength == 0 ? -1 : computedLength;

            // Если общее количество байт отрицательное значение, то
            // присваеваем ему -1, идентифицирующее о невалидном общем количестве байт
            totalBytes = Math.Max(-1, totalBytes);

            // Начинаем читать внутренний поток
            var buffer = new byte[BufferSize];
            var bytesRead = 0;
            while ((bytesRead = await InnerStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
            {
                stream.Write(buffer, 0, bytesRead);
                currentBytes += bytesRead;
                Thread.Sleep(100);
                // Генерируем событие ProgressChanged, чтобы оповестить о текущем прогрессе считывания
                ProgressChanged(bytesRead, currentBytes, totalBytes);
            }
        }

        protected override bool TryComputeLength(out long length)
        {
            var result = base.TryComputeLength(out length);
            totalBytes = length;
            return result;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
                InnerStream.Dispose();

            base.Dispose(disposing);
        }
    }

调用

await UploadAsync(new Uri(upUrl + apiName), stream, new Progress<float>((percent) =>
            {
                this.Pbupload.Dispatcher.Invoke(new Action(delegate
                {
                    Pbupload.Value = percent;
                }));
            }));

 

标签:stream,进度条,totalBytes,public,var,new,wpf,上传,throw
来源: https://www.cnblogs.com/ccqin/p/16669554.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有