как получить позицию и длину разархивированного gzipstream в С#?

Я пытаюсь читать файлы .gz с помощью двоичного считывателя, сначала разархивируя его с помощью gzipstream, а затем создавая новый двоичный считыватель с помощью gzipstream. однако, когда я пытаюсь использовать BaseStream.Position и BaseStream.Length BinaryReader (чтобы узнать, когда я нахожусь в конце моего файла), я получаю исключение NotSupportedException, проверка документа для этих полей в классе GZipStream показывает:

Length
Это свойство не поддерживается и всегда создает исключение NotSupportedException. (Переопределяет Stream.Length.)

Position
Это свойство не поддерживается и всегда создает исключение NotSupportedException. (Переопределяет Stream.Position.)

поэтому мой вопрос: как я могу узнать, когда я нахожусь в конце своего файла при чтении распакованного GZipStream с помощью BinaryReader? Благодарность

вот мой код:

Stream stream = new MemoryStream(textAsset.bytes);
GZipStream zippedStream = new GZipStream(stream, CompressionMode.Decompress);
using (BinaryReader reader = new BinaryReader(zippedStream))
    while(reader.BaseStream.Position != reader.BaseStream.Length)
    {
        //do stuff with BinaryReader
    }

вышеприведенные броски: NotSupportedException: операция не поддерживается. System.IO.Compression.DeflateStream.get_Position()

из-за вызова BaseStream.Position в while()


person Russell Butler    schedule 19.04.2018    source источник
comment
Я на самом деле не использовал это, но не могли бы вы просто продолжать читать, пока это не выйдет из строя?   -  person 500 - Internal Server Error    schedule 20.04.2018
comment
BinaryReader — это класс .Net. Заархивированный файл не обязательно должен соответствовать своей спецификации. Поэтому напрямую используйте zippedStream.Read, пока он не вернет ‹=0 (наиболее простым способом будет zippedStream.CopyTo())   -  person Eser    schedule 20.04.2018
comment
@Eser проверка на ‹=0 сработала, спасибо.   -  person Russell Butler    schedule 20.04.2018


Ответы (2)


Вы можете скопировать свой экземпляр zippedStream в экземпляр MemoryStream, который можно полностью прочитать с помощью функции ToArray. Это самое простое решение, которое я могу придумать.

Stream stream = new MemoryStream(textAsset.bytes);
byte[] result;
using (GZipStream zippedStream = new GZipStream(stream, CompressionMode.Decompress))
{
    using (MemoryStream reader = new MemoryStream())
    {
        zippedStream.CopyTo(reader);
        result = reader.ToArray();
    }
}

В качестве альтернативы, если вы хотите читать поток порциями

using (GZipStream zippedStream = new GZipStream(stream, CompressionMode.Decompress))
{
    byte[] buffer = new byte[16 * 1024];
    int read;
    while ((read = zippedStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        // do work
    }
}
person Yaroslav Veremenko    schedule 19.04.2018
comment
GZipStream не содержит определения для CopyTo. - person Russell Butler; 20.04.2018
comment
@RussellButler каждый поток содержит CopyTo для .Net›=4.0. msdn.microsoft.com /en-us/library/ и msdn.microsoft.com/en-us/library/ - person Eser; 20.04.2018
comment
@RussellButler, что именно говорит ваш компилятор и какую версию .Net вы используете в своем проекте? - person Yaroslav Veremenko; 20.04.2018
comment
@YaroslavVeremenko просто говорит, что GZipStream не содержит определения для CopyTo и метода расширения CopyTo ... не уверен, какая версия .Net, но я использую C# в Unity 2017.1.1f1, так что, может быть, 4.6? blogs.unity3d.com/2017/07/11/introduction-unity -2017 в любом случае я решил проблему с помощью хака ›= 0, так что это не проблема. хотя спасибо за ответ :) - person Russell Butler; 20.04.2018
comment
@RussellButler, вы имеете в виду, что использовали второй фрагмент кода в моем ответе или что-то подобное? - person Yaroslav Veremenko; 21.04.2018
comment
нет, я сделал то, что предложил Эсер в своем комментарии к моему первоначальному вопросу. - person Russell Butler; 22.04.2018

В зависимости от того, что вы декодируете, вы можете прочитать первый тип в массив байтов с помощью BinaryReader, а затем использовать BitConverter для преобразования этих байтов в нужный тип. Затем вы можете использовать BinaryReader как обычно до начала следующей записи.

byte[] headermarker = new byte[4];

int count;

// if bytes available in underlying stream.
while ((count = br.Read(headermarker, 0, 4) > 0 )
{
    Int32 marker = BitConverter.ToInt32(headermarker, 0);

    //
    // now use Binary Reader for the rest of the record until we loop
    //
 
}
person James    schedule 14.09.2020