9

FileStreamを使用してStreamReaderを作成する場合、FileStreamを閉じるときにStreamReaderを閉じますか、それともStreamReaderも閉じる必要がありますか?

public void ReadFile()
{
    var file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read);
    var reader = new StreamReader(file);

    try
    {
        txtFile.Text = reader.ReadToEnd();
    }
    catch (Exception)
    {
        throw;
    }
    finally
    {
        file.Close();
    }
}
4

7 に答える 7

8

本質的にそうです。実際にStreamReaderを閉じる必要はありません。そうした場合、それが行うのは、基になるストリームを閉じることだけです。

@Brunoは、最も外側のラッパーを閉じることについて良い点を示しています。すべてのリソースが適切に解放されるように、最も外側のストリームを閉じて、基になるストリームを閉じておくことをお勧めします。

リフレクターから...

public class StreamReader : TextReader
{
    public override void Close()
    {
        this.Dispose(true);
    }

    protected override void Dispose(bool disposing)
    {
        try
        {
            if ((this.Closable && disposing) && (this.stream != null))
            {
                this.stream.Close();
            }
        }
        finally
        {
            if (this.Closable && (this.stream != null))
            {
                this.stream = null;
                this.encoding = null;
                this.decoder = null;
                this.byteBuffer = null;
                this.charBuffer = null;
                this.charPos = 0;
                this.charLen = 0;
                base.Dispose(disposing);
            }
        }
    }
}
于 2009-11-24T19:02:00.947 に答える
6

File.ReadAllText メソッドを使用することもできます。

txtFile.Text = File.ReadAllText(@"c:\file.txt");
于 2009-11-24T19:07:06.023 に答える
6

いいえreader。代わりに を閉じる必要があります。実際には、これで問題が発生するStreamReaderことはありませんが、クリーンアップが必要なオーバーヘッドが追加される可能性があります。したがって、常に一番上のラッパーを閉じる必要があります。

于 2009-11-24T19:02:41.103 に答える
2

アンマネージ リソースを所有していないため、StreamReader を閉じる必要はありません。FileStream を閉じるだけで十分です。using次のようにコードを書き直すことができます。

public void ReadFile()
{
    using (var file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read))
    {
        txtFile.Text = new StreamReader(file).ReadToEnd();
    }
}

一般に、疑問がある場合は、IDisposable オブジェクトの使用が終了したら、すべての IDisposable オブジェクトを安全に破棄することをお勧めします。

public void ReadFile()
{
    using (FileStream file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read))
    {
        using (StreamReader streamReader = new StreamReader(file))
        {
            txtFile.Text = streamReader.ReadToEnd();
        }
    }
}
于 2009-11-24T19:04:42.457 に答える
0

いいえ。最善の方法は、開いたときと逆の順序で閉じることです。

于 2009-11-24T19:02:16.813 に答える
0

興味深いことに、StreamReaderまたはライターを閉じると、所有しているFileStreamの読み取り/書き込みステータスに影響します。これは、同じファイルストリームを使用してStreamReaderを使用してからStreamWriterを使用できないことを意味しているようです。

于 2011-10-27T09:03:27.490 に答える
0

これを全体的に行う最善の方法は、FileStream を自分自身だけで閉じることだと思います。上位のレイヤーに存在するものを暗黙的に認識していないため、それらの上位レイヤーに影響を与えるようなことを行うと、事実上エラーになります。

そうは言っても、高レベルの構成要素は、提供された下層のレイヤーについても公理的に何も仮定すべきではありません。そうする場合は、明示的にそうする必要があります。

1) 既存のストリームから作成された場合、上位レベルの構成は、基になるストリームとは独立して閉じられる(事実上、独自の使用のために割り当てられたすべてのリソースを破棄する) か、基になるストリームを含めて閉じられる必要があります。これらは、Close() と CloseSelf() などの 2 つの異なる関数呼び出しである必要があります (既存のコードとの下位互換性を維持するように実装する場合)。

2) 既存のストリームから作成されなかった場合 (つまり、コンストラクターが基になるストリームを作成する必要があった場合)、上位レベルの構成を閉じると、基になるストリームも強制的に閉じられる必要があります。上位レベルの構造の暗黙の部分。この場合、CloseSelf() は単純に Close() を呼び出します。

これらのクラスをそのまま実装するのは無駄に思えます。(例として) シリアル入力とシリアル出力に同じファイルを使用することを計画している場合、子孫クラスのより高いレベルの機能にアクセスしたい場合、システムによって事実上、それを 2 つの別個のエンティティとして扱うように強制されます。別の方法は、下位レベルの構成に固執し、上位レベルの機能を自分で実装することです。つまり、既存の子孫クラスの独自の特別なバージョンを効果的に再実装します。

上記のように実行された場合、典型的な機能は現在と同じくらい簡単に実装できますが、より洗練されたアプリケーションでは、ファイルに単一のロックを配置し、必要に応じて必要に応じて再利用する機能を保持します。ロックと関連するすべてのリソースを放棄し、それらを即座に再割り当てしなければならないのではなく、正当な理由なくシステムにオーバーヘッドとメモリの断片化を追加します。

ただし、現在の状況下では、正しいことは明らかです。FileStream は、その一部となるオブジェクトについて何も知らないと想定できないため、最も外側の囲み構造を閉じる必要があります。これは、ブルーノらが指摘したように、どちらの方法でも機能するかどうかに関係なく適用され、その理由は互換性です。仮定は、最も醜いバグのひいおじいちゃんです。

于 2011-07-11T21:02:30.427 に答える