Почему я получаю необработанное исключение: System.IO.IOException при попытке чтения из файла, в который выполняется запись? - PullRequest
3 голосов
/ 06 июля 2010

У меня есть два приложения на C #, одно из которых читает строку (Файл A) построчно и записывает его содержимое в другой файл (Файл 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;

}

Теперь, когда я пытаюсь запустить эти два приложения вместе, я получаю исключение «Необработанное исключение: System.IO.IOException: процесс не может получить доступ к файлу, потому что он используется другим процессом».

У меня есть обе настройки файловых потоков для доступа ReadWrite, и у меня есть одна из настроек файловых потоков для FileAccess.Write, а другая для FileAccess.Read.

Есть какие-нибудь подсказки, почему я получу это исключение?

Спасибо Разрубить.

Ответы [ 4 ]

7 голосов
/ 06 июля 2010

lines = File.ReadAllLines (args [1] + "\ Chat.log"). Длина;

Ваша проблема.Этот метод открывает файл, читает все строки и снова закрывает его.Он использует "нормальные" настройки общего доступа к файлам при открытии файла FileShare.Read.Это запрещает доступ на запись к любому другому процессу, у которого также открыт файл.

Это не может работать здесь, у вас уже открыт файл с правами записи.2-й процесс не может это отрицать.IOException является результатом.

Вы не можете использовать File.ReadAllLines () как есть, вам нужно открыть FileStream с FileShare.ReadWrite, передать его StreamReader и прочитать все строки.

Остерегайтесь очень неприятного гоночного потенциала, который у вас здесь есть, нет гарантии, что последняя прочитанная вами строка - это полная строка.Получение только \ r, а не \ n в конце строки - особенно сложная проблема.Это будет случайно и редко, самые трудные ошибки для устранения.Возможно, ваш вызов Flush () исправляет это, я никогда не был достаточно смел, чтобы проверить это.

4 голосов
/ 06 июля 2010

Разрешение второй программе 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++;
            }
        }
1 голос
/ 06 июля 2010
StreamReader sr = new StreamReader("f:\\watch\\input.txt");

input.txt может быть недоступен для чтения?

Также используйте оператор using вместо Close () в 1-м приложении (в случае возникновения исключения).

В противном случае все в порядке.Для общего файлового ресурса могут потребоваться дополнительные разрешения (на это не может повлиять).

Я пропустил один фрагмент кода:

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

используйте stream с StreamReaderдля этого.

1 голос
/ 06 июля 2010

MSDN предлагает два способа не получить исключительное удержание:

Объект FileStream не будет иметь исключительное удержание на своем дескрипторе, когда к объекту SafeFileHandle обращаются, чтобы открытьдескриптор или объект FileStream получает свойство SafeFileHandle в своем конструкторе.

Документация подразумевает, что обратное истинно:

Открытие FileStream без установки SafeFileHandle означаетFileStream поддерживает исключительное удержание дескриптора файла (который встроен в исключение ввода-вывода, которое должно быть выброшено).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...