LoginSignup
4
3

More than 5 years have passed since last update.

C#でfile_put_contentsしたかった

Posted at

AzureのAppService上でファイルを追記したいだけの人生だった。

    using System.IO;

    /**
    * file_put_contents(FILE_APPEND)
    * @param string ファイル名
    * @param string 書き込み内容
    */
    public static void file_put_contents(string FileName, string SaveText){
        // 実際はフォーマットとか追加があるけど本質的な違いは無いので略
        File.AppendAllText(FileName, SaveText);
    }

という素晴らしく手抜きな関数を使っていたところ、リクエストが重なったときに競合であっさり死亡。

    // わりと頻繁に発生
    System.IO.IOException: The process cannot access the file 'hoge.txt' because it is being used by another process.

PHP脳はマルチスレッドに弱いのだ。

で、これをどうにかしたいと思ったのだが、キューに投げておけば後で勝手に書き込んでくれる、みたいな機能はどうやら用意されていないみたいだ。
ちなみにAppendAllTextのサンプルは、そもそもcatchすらしてないものが大半だった。

しかたないのでTextWriter.Synchronized()を使うことにする。

    public static void file_put_contents(string FileName, string SaveText){
        using(StreamWriter writer = new StreamWriter(FileName, true)){
            // まだ何も書いてない
        }
    }
    // 希に発生
    System.IO.IOException: The process cannot access the file 'hoge.txt' because it is being used by another process.

どうやらファイルをStreamWriterで開くだけで死ぬらしい。
Synchronizedとかする以前の問題だった。
ドキュメントには「ファイル名、ディレクトリ名が正しくないときに出る」としか書いてないのだが、どう見てもロック失敗である。

えっこれどうすんの?
newしただけでExceptionとか聞いてないよ。
WriteをcatchするとかSynchronizedするとかのソリューションはよく見かけるけど、実は解決になっていないということがわかった。

その後もなんか色々調べたりしたんだけどそのあたりは省略して、最終的にできあがったのがこんな。

    public static void file_put_contents(string FileName, string SaveText){
        using(FileStream fs = new FileStream(FileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)){
            using(StreamWriter sw = new StreamWriter(fs)){
                using(TextWriter tw = TextWriter.Synchronized(sw)){
                    tw.Write(SaveText);
                    tw.Flush();
                }
            }
        }
    }

例外は発生せず、動作も安定しているように見えるのだが、本当にこれで合ってるのか???

4
3
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3