3

私が望んでいる最終結果を示すテスト プログラムがあります (このテスト プログラムでは手順が不要に見えるかもしれませんが)。

プログラムは、GZipStream を使用してデータをファイルに圧縮します。結果の圧縮ファイルはC:\mydata.datです。

次に、このファイルを読み取り、新しいファイルに書き込みます。

//Read original file
string compressedFile = String.Empty;
using (StreamReader reader = new StreamReader(@"C:\mydata.dat"))
{
    compressedFile = reader.ReadToEnd();
    reader.Close();
    reader.Dispose();
}

//Write to a new file
using (StreamWriter file = new StreamWriter(@"C:\mynewdata.dat"))
{
    file.WriteLine(compressedUserFile);
}

2 つのファイルを解凍しようとすると、元のファイルは完全に解凍されますが、新しいファイルは InvalidDataException をスローし、GZip ヘッダーのマジック ナンバーが正しくありませんというメッセージが表示されます。GZip ストリームを渡していることを確認してください。

これらのファイルが異なるのはなぜですか?

4

2 に答える 2

3

StreamReaderバイトではなく、一連の文字を読み取るためのものです。についても同様StremWriterです。圧縮ファイルを文字のストリームとして扱うのは意味がないので、何らかの実装を使用する必要がありますStream。ストリームをバイトの配列として取得する場合は、 を使用できますMemoryStream

文字ストリームの使用が機能しない正確な理由は、デフォルトで UTF-8 エンコーディングが想定されているためです。一部のバイトが有効な UTF-8 でない場合 (ヘッダーの 2 番目のバイト、0x8B など)、Unicode の「置換文字」(U+FFFD) として表されます。文字列が書き戻されると、その文字は UTF-8 を使用してソースにあったものとはまったく異なるものにエンコードされます。

たとえば、ストリームからファイルを読み取るには、それをバイト配列として取得し、ストリームとして別のファイルに書き込みます。

byte[] bytes;
using (var fileStream = new FileStream(@"C:\mydata.dat", FileMode.Open))
using (var memoryStream = new MemoryStream())
{
    fileStream.CopyTo(memoryStream);
    bytes = memoryStream.ToArray();
}

using (var memoryStream = new MemoryStream(bytes))
using (var fileStream = new FileStream(@"C:\mynewdata.dat", FileMode.Create))
{
    memoryStream.CopyTo(fileStream);
}

このCopyTo()メソッドは .Net 4 でのみ使用できますが、古いバージョンを使用している場合は独自のものを作成できます。

もちろん、この単純な例では、ストリームを使用する必要はありません。あなたは簡単に行うことができます:

byte[] bytes = File.ReadAllBytes(@"C:\mydata.dat");
File.WriteAllBytes(@"C:\mynewdata.dat", bytes);
于 2011-07-13T15:45:45.143 に答える
-1

編集:どうやら、私の提案は間違っている/無効である/何でもあります...余分なパフォーマンスを達成できない点まで高度にリファクタリングされている疑いのない他のものの1つを使用してください(そうでない場合、それらは私と同じくらい無効です)

using (System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\mydata.dat"))
{
    using (System.IO.StreamWriter sw = new System.IO.StreamWriter(@"C:\mynewdata.dat"))
    {
        byte[] bytes = new byte[1024];
        int count = 0;
        while((count = sr.BaseStream.Read(bytes, 0, bytes.Length)) > 0){
            sw.BaseStream.Write(bytes, 0, count);
        }
    }
}

すべてのバイトを読み取る

byte[] bytes = null;
using (System.IO.StreamReader sr = new System.IO.StreamReader(@"C:\mydata.dat"))
{
    bytes = new byte[sr.BaseStream.Length];
    int index = 0;
    int count = 0;
    while((count = sr.BaseStream.Read(bytes, index, 1024)) > 0){
        index += count;
    }
}

すべてのバイトを読み取る/すべてのバイトを書き込む(svickの回答から):

byte[] bytes = File.ReadAllBytes(@"C:\mydata.dat");
File.WriteAllBytes(@"C:\mynewdata.dat", bytes);

他の回答を使用したパフォーマンス テスト:

私の回答(StreamReader)(上記の最初の部分、ファイルコピー)とsvickの回答(FileStream/MemoryStream)(最初のもの)の間で簡単なテストを行いました。テストはコードの 1000 回の反復です。ここに 4 つのテストの結果があります (結果は秒単位であり、すべての実際の結果はこれらの値をわずかに上回っています)。

My Code | svick code
--------------------
9       | 12
9       | 14
8       | 13
8       | 14

ご覧のとおり、少なくとも私のテストでは、コードのパフォーマンスが向上しました。おそらく注意すべきことの 1 つは、文字ストリームを読み取っていないことです。実際には、バイト ストリームを提供している BaseStream にアクセスしています。おそらく、svick の答えは遅いでしょう。なぜなら、彼は 2 つのストリームを読み取り用に使用し、次に 2 つのストリームを書き込み用に使用しているからです。もちろん、パフォーマンスを改善するために svick の回答に対して実行できる多くの最適化があります (また、単純なファイル コピーの代替手段も提供しました)。

3 番目のオプション (ReadAllBytes/WriteAllBytes) を使用したテスト

My Code | svick code | 3rd
----------------------------
8       | 14         | 7
9       | 18         | 9
9       | 17         | 8
9       | 17         | 9

注: ミリ秒単位では、3 番目のオプションが常に優れていました

于 2011-07-13T15:15:34.910 に答える