3

2 つの C# アプリケーションがあり、1 つはファイル (ファイル A) を 1 行ずつ読み取り、その内容を別のファイル (ファイル B) に書き込みます。

2 番目のアプリケーションは、ファイル B の FileSystemWatcher を使用してファイル B が更新されたことを確認し、プログラムが開始されたときとファイルが変更されたときの行番号の違いを報告しています。

今のところやろうとしているのはそれだけです。最終的には、ファイルが最後に読み取られたときと現在の読み取りの間の行を読み取りたいのですが、保留中の行の違いを取得できるまでです。

アプリケーション 1 のコードは次のとおりです。

        static void Main(string[] args)
    {
        String line;

        StreamReader sr = new StreamReader("f:\\watch\\input.txt");

        FileStream fs = new FileStream("f:\\watch\\Chat.log", FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
        StreamWriter sw = new StreamWriter(fs);

        while ((line = sr.ReadLine()) != null)
        {
            sw.WriteLine(line);
            Thread.Sleep(200);
            Console.WriteLine(line);
            sw.Flush();

        }

        sw.Close();
        sr.Close();

    }

アプリケーション 2 のコードは次のとおりです。

        public static int lines = 0;

    public static void Main()
    {
        Run();
    }

    public static void Run()
    {
        string[] args = System.Environment.GetCommandLineArgs();

        if (args.Length != 2)
        {
            Console.WriteLine("Usage: Watcher.exe (directory)");
            return;
        }

FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = args[1];

watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite 
   | NotifyFilters.FileName | NotifyFilters.DirectoryName;

watcher.Filter = "Chat.log";

watcher.Changed += new FileSystemEventHandler(OnChanged);

watcher.EnableRaisingEvents = true;

lines = File.ReadAllLines(args[1] + "\\Chat.log").Length;

Console.WriteLine("File lines: " + lines);

while(Console.Read()!='q');
}

private static void OnChanged(object source, FileSystemEventArgs e)
{
    Linework(e.FullPath);
    Console.WriteLine("File: " +  e.FullPath + " " + e.ChangeType);
}

public static string Linework(string path)

{



   string newstring = " ";

using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    int newlines = File.ReadAllLines(path).Length;
    Console.WriteLine("Lines now: " + newlines);
}

return newstring;

}

これら 2 つのアプリケーションを一緒に実行しようとすると、「未処理の例外: System.IO.IOException: 別のプロセスで使用されているため、プロセスはファイルにアクセスできません」という例外が発生します。

私は両方のファイル ストリームを ReadWrite アクセス用にセットアップしており、ファイル ストリームの 1 つを FileAccess.Write 用にセットアップし、もう 1 つを FileAccess.Read 用にセットアップしています。

なぜこの例外が発生するのかについての手がかりはありますか?

ありがとうございます。

4

4 に答える 4

7

行 = File.ReadAllLines(args[1] + "\Chat.log").Length;

問題があります。そのメソッドはファイルを開き、すべての行を読み取り、再度閉じます。ファイル FileShare.Read を開くときに、「通常の」ファイル共有設定を使用します。これにより、ファイルが開かれている他のプロセスへの書き込みアクセスが 拒否されます。

ここでは機能しません。すでにファイルが書き込みアクセスで開かれています。2番目のプロセスはそれを否定できません。IOException が結果です。

ここでは File.ReadAllLines() をそのまま使用することはできません。FileShare.ReadWrite で FileStream を開き、それを StreamReader に渡してすべての行を読み取る必要があります。

あなたがここに持っている非常に厄介な競争の可能性に注意してください.あなたが読む最後の行が完全な行であるという保証はありません. 行末の \n ではなく \r のみを取得することは、特にトリッキーな問題です。これはランダムかつまれに発生し、トラブルシューティングが最も困難なバグです。多分あなたの Flush() 呼び出しはそれを修正します、私はこれをテストするほど勇気がありませんでした.

于 2010-07-06T19:41:27.107 に答える
4

この場合、ファイルに対する2 番目のプログラムのReadWriteアクセスを許可すると機能します。

//lines = File.ReadAllLines(args[1] + "\\Chat.log").Length;
//Commenting the above lines as this would again open a new filestream on the chat.log
//without the proper access mode required.


    using (FileStream fsReader = new FileStream(args[1] + "\\Chat.log", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
        {
            using (StreamReader sr = new StreamReader(fsReader))
            {
                while (sr.ReadLine() != null)
                    lines++;
            }
        }
于 2010-07-06T18:35:21.280 に答える
1

MSDNには、排他的保留を取得しない2つの方法があります。

SafeFileHandleプロパティにアクセスしてハンドルを公開するか、FileStreamオブジェクトにコンストラクターでSafeFileHandleプロパティが指定されている場合、FileStreamオブジェクトはそのハンドルを排他的に保持しません。

ドキュメントは、その逆が真であることを示唆しています。

SafeFileHandleを設定せずにFileStreamを開くということは、FileStreamがファイルハンドルの排他的保持を維持することを意味します(これは、スローされるはずのIO例外とインラインです)。

于 2010-07-06T18:28:01.100 に答える
1
StreamReader sr = new StreamReader("f:\\watch\\input.txt");

input.txt を読み取れない可能性がありますか?

またusing、最初のアプリケーションで Close() の代わりにステートメントを使用します (例外がスローされる場合)。

それ以外は問題ありません。ただし、ファイル共有には追加のアクセス許可が必要になる場合があります (実際には影響しません)。

私はコードを1つ見逃しました:

int newlines = File.ReadAllLines(path).Length;

streamそのために a と一緒に使用StreamReaderします。

于 2010-07-06T18:32:16.170 に答える