デフレート ストリームは、バイナリ データに対して機能します。テキスト ファイルの途中にある任意のバイナリ チャンクは、破損したテキスト ファイルとも呼ばれます。これを正しくデコードする方法はありません:
- バイナリデータについて話すときの「行」の定義がないため、「行」を読むことはできません。CR/LF/CRLF/etc の任意の組み合わせは、バイナリ データで完全にランダムに発生する可能性があります。
- 「文字列行」を読み取ることはできません。これは、データを
Encoding
;で実行していることを示唆しているためです。しかし、これはテキストデータではないため、繰り返しますが、処理できない意味不明なものになります(読み取り時にデータが失われます)
さて、これら 2 つの問題の 2 つ目は、Stream
API ではなく APIを介して読み取ることで解決できるため、バイナリStreamReader
のみを読み取ることになります。次に、 を使用してできることを調べて、自分で行末を探す必要があります(UTF-8 などのマルチ/可変バイト エンコーディングを使用している場合、これは思ったほど単純ではないことに注意してください)。Encoding
ただし、これら 2 つの問題のうち最初の 1 つは、本質的にそれ自体では解決できません。これを確実に行うには、ある種のバイナリ フレーミング プロトコルが必要になります。これも、テキスト ファイルには存在しません。この例では "mark" と "endmark" を使用しているように見えます - 繰り返しますが、技術的にはこれらがランダムに発生する可能性がありますが、99.999% の場合はおそらくそれで済むでしょう。Stream
トリックは、 andを使用してファイル全体を手動で読み取り、Encoding
「マーク」と「エンドマーク」を探し、圧縮データであるビットからテキストとしてエンコードされたビットを取り除くことです。次に、encoded-as-text ピースを正しいEncoding
.
でも!バイナリを読み取っている時点では、それは簡単です: 適切な量を (データが書き込まれるフレーミング/センチネル プロトコルを使用して) バッファリングし、次のようなものを使用します。
using(var ms = new MemoryStream(bytes))
using(var inflate = new GZipStream(ms, CompressionMode.Decompress))
{
// now read from 'inflate'
}
マーカーの追加と、l 73
それが ASCII であるという情報により、もう少し実行可能になります。
ここのSOのデータはすでに破損しているため(テキストとしてバイナリを投稿するとそれが行われます)、これは私にはうまくいきませんが、基本的には次のようなものです:
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Text.RegularExpressions;
class Program
{
static void Main()
{
using (var file = File.OpenRead("my.txt"))
using (var buffer = new MemoryStream())
{
List<string> lines = new List<string>();
string line;
while ((line = ReadToCRLF(file, buffer)) != null)
{
lines.Add(line);
Console.WriteLine(line);
if (line == "mark" && lines.Count >= 2)
{
var match = Regex.Match(lines[lines.Count - 2], "^l ([0-9]+)$");
int bytes;
if (match.Success && int.TryParse(match.Groups[1].Value, out bytes))
{
ReadBytes(file, buffer, bytes);
string inflated = Inflate(buffer);
lines.Add(inflated); // or something similar
Console.WriteLine(inflated);
}
}
}
}
}
static string Inflate(Stream source)
{
using (var deflate = new DeflateStream(source, CompressionMode.Decompress, true))
using (var reader = new StreamReader(deflate, Encoding.ASCII))
{
return reader.ReadToEnd();
}
}
static void ReadBytes(Stream source, MemoryStream buffer, int count)
{
buffer.SetLength(count);
int read, offset = 0;
while (count > 0 && (read = source.Read(buffer.GetBuffer(), offset, count)) > 0)
{
count -= read;
offset += read;
}
if (count != 0) throw new EndOfStreamException();
buffer.Position = 0;
}
static string ReadToCRLF(Stream source, MemoryStream buffer)
{
buffer.SetLength(0);
int next;
bool wasCr = false;
while ((next = source.ReadByte()) >= 0)
{
if(next == 10 && wasCr) { // CRLF
// end of line (minus the CR)
return Encoding.ASCII.GetString(
buffer.GetBuffer(), 0, (int)buffer.Length - 1);
}
buffer.WriteByte((byte)next);
wasCr = next == 13;
}
// end of file
if (buffer.Length == 0) return null;
return Encoding.ASCII.GetString(buffer.GetBuffer(), 0, (int)buffer.Length);
}
}