0

次のようなファイルを作成できます。

stream.Write(headerBytes, 0, headerBytes.Count);

using (var gz = new GZipStream(stream, Compress, leaveOpen: true);
{
    gz.Write(otherBytes, 0, otherBytes.Count);
}

stream.Write(moreBytes, 0, moreBytes.Count);

今のようなファイルを読むとき

stream.Read(headerBytes, 0, headerBytes.Count);
// in reality I make sure that indeed headerBytes.Count get read,
// something the above line omits

using (var gz = new GZipStream(stream, Decompress, leaveOpen: true)
{
  do { /* use buffer... */}
  while ((bytesRead = gz.Read(buffer, 0, buffer.Length)) != 0);
}

while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
  // use buffer...

私がチェックした場合、実際の13293バイトの圧縮されたバイトではなく、GZipStream( についても同じですDeflateStream)が から16384バイトを読み取ることがわかりました。stream

ファイルの圧縮部分のサイズも、圧縮データに続くバイト数も事前にわからないと仮定すると、GzipStream/DeflateStream を使用する方法はありますか

  1. そのため、圧縮されたデータのみを読み取りますstream
  2. または、少なくとも圧縮データ部分のサイズを把握して、stream.Position -= actuallyRead - compressedSize手動でできますか?
4

3 に答える 3

0

この答えは醜い回避策になります。私は特に好きではありませんが、GZipStream.

  1. または、少なくとも圧縮データ部分のサイズを把握して、stream.Position -= actuallyRead - compressedSize 手動でできますか?

すべての gzip ファイル (および実際にはすべてのgzip メンバー)

     +---+---+---+---+---+---+---+---+
     |     CRC32     |     ISIZE     |
     +---+---+---+---+---+---+---+---+

     CRC32
        This contains a Cyclic Redundancy Check value of the
        uncompressed data

     ISIZE
        This contains the size of the original (uncompressed) input
        data modulo 2^32.

を閉じた後に知っている圧縮されていないサイズ (モジュール 2^32) を使用して、GzipStream一致する 4 バイトが見つかるまでストリームを逆方向にシークすることができます。

より堅牢にするために、圧縮解除中に CRC32 も計算し、正しい CRC32 と ISIZE を形成する 8 バイトの直後までストリームを逆方向にシークする必要があります。

醜いですが、私はあなたに警告しました。

<皮肉>私はカプセル化が大好きです. すべての有用なものをカプセル化して、すべてを知っている API 設計者が予見した 1 つのユース ケースで機能する圧縮解除ストリームを残します。</皮肉>

これまでのところ機能する簡単なSeekBack実装を次に示します。

/// <returns>the number of bytes sought back (including bytes.Length)
///          or 0 in case of failure</returns>
static int SeekBack(Stream s, byte[] bytes, int maxSeekBack)
{
    if (maxSeekBack != -1 && maxSeekBack < bytes.Length)
        throw new ArgumentException("maxSeekBack must be >= bytes.Length");

    int soughtBack = 0;
    for (int i = bytes.Length - 1; i >= 0; i--)
    {
        while ((maxSeekBack == -1 || soughtBack < maxSeekBack)
               && s.Position > i)
        {
            s.Position -= 1;
            // as we are seeking back, the following will never become
            // -1 (EOS), so coercing to byte is OK
            byte b = (byte)s.ReadByte();
            s.Position -= 1;
            soughtBack++;
            if (b == bytes[i])
            {
                if (i == 0)
                    return soughtBack;
                break;
            }
            else
            {
                var bytesIn = (bytes.Length - 1) - i;
                if (bytesIn > 0) // back to square one
                {
                    soughtBack -= bytesIn;
                    s.Position += bytesIn;
                    i = bytes.Length - 1;
                }
            }
        }
    }
    // no luck? return to original position
    s.Position += soughtBack;
    return 0;
}
于 2015-03-11T04:14:06.043 に答える