web-dev-qa-db-ja.com

FileStream「閉じたファイルにアクセスできません」

using (fileStream = new FileStream(path, FileMode.Append, FileAccess.Write))を使用すると上記のエラーメッセージが表示されるのに、fileStream = File.Create(path);に置き換えるとプログラムが完全に実行されるのはなぜですか?

コンソール出力を外部ファイルに追加したい。これが私のコードです:

_ //copy console output to file in bin\Debug folder
    class ConsoleCopy : IDisposable
    {
        FileStream fileStream;
        StreamWriter fileWriter;
        TextWriter doubleWriter;
        TextWriter oldOut;
        class DoubleWriter : TextWriter
        {
            TextWriter one;
            TextWriter two;
            public DoubleWriter(TextWriter one, TextWriter two)
            {
                this.one = one;
                this.two = two;
            }
            public override Encoding Encoding
            {
                get { return one.Encoding; }
            }
            //Clears all buffers for the current writer
            public override void Flush()
            {
                one.Flush();

                two.Flush();
            }
            public override void Write(char value)
            {
                **one.Write(value);**//error thrown here
                two.Write(value);
            }
        }
        public ConsoleCopy(string path)
        {
            oldOut = Console.Out;
            try
            {
                **//fileStream = File.Create(path);** //runs alright with this line
                fileWriter = new StreamWriter(fileStream);
                fileWriter.AutoFlush = true;
                doubleWriter = new DoubleWriter(fileWriter, oldOut);
            }
            catch (Exception e)
            {
                Console.WriteLine("Cannot open file for writing");
                Console.WriteLine(e.Message);
                return;
            }
            Console.SetOut(doubleWriter);
        }
        public void Dispose()
        {
            Console.SetOut(oldOut);
            if (fileWriter != null)
            {
                fileWriter.Flush();
                fileWriter.Close();
                fileWriter = null;
            }
            if (fileStream != null)
            {
                fileStream.Close();
                fileStream = null;
            }
        }
    }//end of consoleCopy
_

私はこのメソッドをメインメソッドで次のように呼び出します。

_ //pass output to ConsoleCopy method for copying to .txt file
        using (var cc = new ConsoleCopy("mylogfile.txt"))
        {
           DateTime theDate = DateTime.UtcNow;

            string custom = theDate.ToString("d");

            Console.WriteLine("User has logged in on " + custom);
        }
_

更新:

エラーは以前はone.Write(value)で示されていました。ピーターのおかげでなんとか解決できました。あなたの貢献と助けをみんなに感謝します:)

7
iNeedHelp

編集:書く前にそれを取得している場合、それは私が質問を読み間違えたためであり、ConsoleCopyコンストラクターにusingステートメントを置くことは、ConsoleCopyの作成が終了するとFileStreamが閉じられることを意味します。あなたがそれに書き込もうとする時までに、それはすでに閉じられているので、あなたはその例外を受け取ります。同じ解決策が適用されます。FileStreamを開いたままにして、Dispose()で閉じます。ここで、mainメソッドのusingステートメントを使用します。

私が正しく理解していれば、処分時にその例外が発生しますよね?もしそうなら、それはあなたがそのストリームを2回閉じているということが本質的に起こっているからです。

using (var cc = new ConsoleCopy("mylogfile.txt"))
{
    // At this time, your filestream is created with the using statement.
    // Writing happens here.
    // Your filestream is closed at the end of the using statement inside of the ConsoleCopy constructor.
} 
// At this point, ConsoleCopy tries to call Dispose(), which flushes and closes everything again. However, this throws an exception because the using statement already closed the FileStream.

ファイルの末尾に追加することが目標であり、Dispose()メソッドがすべてを内部的に閉じる場合は、単に置き換えるだけではどうでしょうか。

**//fileStream = File.Create(path);** //runs alright with this line

fileStream = File.Open(path, System.IO.FileMode.Append, System.IO.FileAccess.Write);

メインのusingステートメントでストリームを内部的に閉じますか?

8
Peter Luu

usingステートメントの外で書き込みコードを実行していますか?ストリームを操作する前に、ストリームを閉じている可能性があります。

これを実行するとどうなりますか:

using (fileStream = new FileStream(path, FileMode.Append, FileAccess.Write))
{
  fileWriter = new StreamWriter(fileStream);
  fileWriter.AutoFlush = true;
  doubleWriter = new DoubleWriter(fileWriter, oldOut);
}
1
Colin