Нужен асинхронный ридер файлов без знания размера

Мне нужен метод, который асинхронно считывает файл в массив байтов, но я не знаю, какого размера будет файл (это может быть несколько килобайт или несколько мегабайт).

Я пробовал FileStream, чтобы получить длину и использовать BeginRead, но проблема в том, что длина длинная, а BeginRead принимает только int, если файл слишком большой, он, вероятно, переполнится. другой способ, которым я думал, читал его меньшими кусками, но каждый раз, когда мне нужно читать новый кусок байтов, мне придется создавать новый массив (просто хотел избежать инициализации новых и больших массивов).

Если кто-нибудь знает лучший или более простой способ, я был бы счастлив и благодарен: в противном случае я сделаю это, читая небольшими кусками. Тю за любую помощь.


person Hugo Alves    schedule 01.02.2011    source источник
comment
Это действительно зависит от того, что вам нужно делать с данными после прочтения. Вы хотите загрузить все это в память, в чем я сомневаюсь? Или обрабатывать их по мере чтения в буфер, скажем, 4K? Сделайте это более ясным.   -  person Aliostad    schedule 01.02.2011
comment
Обратите внимание, что параметр count представляет максимальное количество байтов для чтения. Кроме того, вам нужно будет вызвать метод EndRead, чтобы определить, сколько байтов было фактически прочитано. msdn.microsoft.com/en-us/library/   -  person RQDQ    schedule 01.02.2011


Ответы (4)


Другой способ сделать это — просто запустить поток и вызвать System.IO.File.ReadAllBytes(строка). Не похоже, что у разбиения на фрагменты есть какое-то преимущество (потому что вы собираетесь перенести все это в память), так что это было бы довольно просто.

С помощью этого образца:

    private void GetTheFile()
    {
        FileFetcher fileFetcher = new FileFetcher(Fetch);

        fileFetcher.BeginInvoke(@"c:\test.yap", new AsyncCallback(AfterFetch), null);
    }

    private void AfterFetch(IAsyncResult result)
    {
        AsyncResult async = (AsyncResult) result;

        FileFetcher fetcher = (FileFetcher)async.AsyncDelegate;

        byte[] file = fetcher.EndInvoke(result);

        //Do whatever you want with the file
        MessageBox.Show(file.Length.ToString());
    }

    public byte[] Fetch(string filename)
    {
        return File.ReadAllBytes(filename);
    }
person RQDQ    schedule 01.02.2011
comment
ty за помощь, это выглядит как хорошее решение для того, что я ищу. - person Hugo Alves; 01.02.2011

Вы можете разделить его на MemoryStream (MemoryStream будет управлять добавлением двоичной информации в память), и в конце вы можете просто вызвать memoryStream.ToArray().

Кроме того, вот способ копирования между двумя экземплярами потока (из вашего файлового потока в ваш MemorySream:

Как скопировать содержимое одного потока в другой?

person RQDQ    schedule 01.02.2011

Вы можете указать offset в своем массиве, что позволит вам выделить один большой массив.

public IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)

stream.BeginRead(buffer, totalRead, chunkSize, ...);

Затем в EndRead добавьте размер чтения к totalRead.

person Nekresh    schedule 01.02.2011

В любом случае вам придется читать его по частям, поскольку .NET не поддерживать объекты размером более 2 ГБ.

person Konstantin Oznobihin    schedule 01.02.2011
comment
Похоже, что OP не знает точный размер, но несколько КБ или несколько хороших МБ звучит так, как будто он подпадает под ограничение в 2 ГБ. - person Jon Skeet; 01.02.2011
comment
но проблема в том, что длина длинная, и BeginRead принимает только int, если файл слишком большой, он, вероятно, переполнится, вероятно, это заставляет меня думать, что OP может получить довольно большие файлы, и если ему нужно общее решение, помещающее все в один большой массив, может не всегда работать. - person Konstantin Oznobihin; 01.02.2011