Получить расположение файла каждого файла в поток - PullRequest
0 голосов
/ 27 марта 2020

Я отправляю несколько файлов из моего веб-интерфейса, но я хочу прочитать каждую часть потока, чтобы преобразовать его в байтовый массив, затем в конце у меня есть список байтов [], и я могу сохранить каждый файл:

 [Route("GetFiles")]
    public HttpResponseMessage GetFile([FromUri] List<string> filesNames)
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);

        if (filesNames.Count == 0)
            return Request.CreateResponse(HttpStatusCode.BadRequest);

        var content = new MultipartContent();

        filesNames.ForEach(delegate (string fileName)
        {
            string filePath = System.Web.Hosting.HostingEnvironment.MapPath("~/Uploads/" + fileName);
            byte[] pdf = File.ReadAllBytes(filePath);

            content.Add(new ByteArrayContent(pdf));
            response.Headers.Add(fileName, fileName);
        });

        var files = JsonConvert.SerializeObject(content);

        response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
        response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
        response = Request.CreateResponse(HttpStatusCode.OK, content);

        return response;
    }

Вот как я получаю один файл в поток, а затем преобразую его в байтовый массив для отчета о процентах процесса:

public static async Task<byte[]> CreateDownloadTaskForFile(string urlToDownload, IProgress<DownloadBytesProgress> progessReporter)
    {
        int receivedBytes = 0;
        int totalBytes = 0;
        WebClient client = new WebClient();

        using (var stream = await client.OpenReadTaskAsync(urlToDownload))
        {

            byte[] buffer = new byte[BufferSize];
            totalBytes = Int32.Parse(client.ResponseHeaders[HttpResponseHeader.ContentLength]);
            using (MemoryStream memoryStream = new MemoryStream())
            {
                for (; ; )
                {
                    int bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
                    memoryStream.Write(buffer, 0, buffer.Length);
                    if (bytesRead == 0)
                    {
                        await Task.Yield();
                        break;
                    }

                    receivedBytes += bytesRead;
                    if (progessReporter != null)
                    {
                        DownloadBytesProgress args = new DownloadBytesProgress(urlToDownload, receivedBytes, totalBytes);
                        progessReporter.Report(args);
                    }
                }
                return memoryStream.ToArray();
            }
        }
    }

Как получить позицию поток для каждого файла отправлять?

Обновление :

Я сделал HttpResponseMessage так:

[Route("GetFiles")]
    public HttpResponseMessage GetFiles([FromUri] List<string> filesNames)
    {
        HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);

        if (filesNames.Count == 0)
            return Request.CreateResponse(HttpStatusCode.BadRequest);

        var content = new MultipartFormDataContent();

        filesNames.ForEach(delegate (string fileName)
        {
            string filePath = System.Web.Hosting.HostingEnvironment.MapPath("~/Uploads/" + fileName);
            byte[] pdf = File.ReadAllBytes(filePath);

            content.Add(new ByteArrayContent(pdf), fileName);
        });

        response = Request.CreateResponse(HttpStatusCode.OK, content);
        response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
        response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");

        return response;
    }

Но со стороны моего устройства: когда я пытаюсь выполнить запрос, но в содержимом ответа ничего нет:

using (var httpResponseMessage = await httpClient.GetAsync(urlToDownload + filesNamesArg))
            {
                var streamProvider = new MultipartMemoryStreamProvider();

                streamProvider = httpResponseMessage.Content.ReadAsMultipartAsync().Result;
            }

Не могли бы вы показать мне несколько документов или совет?

1 Ответ

1 голос
/ 28 марта 2020

Что?

Этот ответ дает 100% рабочий пример для:

  1. Обслуживание нескольких файлов в виде одного ответа от веб-API с использованием multipart/mixed типа контента,
  2. Чтение содержимого файла на клиенте путем анализа ответа веб-API, реализованного в 1

Надеюсь, это поможет.


Сервер:

Серверное приложение представляет собой проект. Net 4.7.2 MVC с поддержкой веб-API.

Следующий метод реализован в ApiController и возвращает все файлы в ~/Uploads папка в одном ответе.

Обратите внимание на использование расширения Request.RegisterForDispose для регистрации FileStream s для последующего удаления.

    public async Task<HttpResponseMessage> GetFiles()
    {
        string filesPath = System.Web.Hosting.HostingEnvironment.MapPath("~/Uploads");

        List<string> fileNames = new List<string>(Directory.GetFiles(filesPath));

        var content = new MultipartContent();

        fileNames.ForEach(delegate(string fileName)
        {
            var fileContent = new StreamContent(File.OpenRead(fileName));
            Request.RegisterForDispose(fileContent);
            fileContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("image/jpeg");
            content.Add(fileContent);
        });

        var response = new HttpResponseMessage();
        response.Content = content;
        return response;
    }

Заголовок Content-Type ответа показывает как Content-Type: multipart/mixed; boundary="7aeff3b4-2e97-41b2-b06f-29a8c23a7aa7", и каждый файл упакован в разные блоки, разделенные boundary.

Клиент:

Клиентское приложение представляет собой консольное приложение. Net Core 3.0.1.

Обратите внимание на синхронное использование асин c методов. Это может быть легко изменено на асинхронный с помощью await, но реализовано так для простоты:

using System;
using System.IO;
using System.Net.Http;

namespace console
{
    class Program
    {
        static void Main(string[] args)
        {
            using (HttpClient httpClient = new HttpClient())
            {
                using (HttpResponseMessage httpResponseMessage = httpClient.GetAsync("http://localhost:60604/api/GetImage/GetFiles").Result)
                {
                    var content = (HttpContent)new StreamContent(httpResponseMessage.Content.ReadAsStreamAsync().Result);
                    content.Headers.ContentType = httpResponseMessage.Content.Headers.ContentType;
                    MultipartMemoryStreamProvider multipartResponse = new MultipartMemoryStreamProvider();
                    content.ReadAsMultipartAsync(multipartResponse);
                    for(int i = 0; i< multipartResponse.Contents.Count;i++)
                    {
                        Stream contentStream = multipartResponse.Contents[i].ReadAsStreamAsync().Result;
                        Console.WriteLine("Content {0}, length {1}", i, contentStream.Length);
                    }
                }
            }
        }
    }
}
...