Как я могу прочитать файл, даже если получено исключение "используется другим процессом"?

В VB.NET или C# я пытаюсь прочитать содержимое текстового файла, который используется другой программой (в этом-то и дело, на самом деле, я не могу остановить программу или она прекращает запись в текстовый файл, и Я хочу периодически читать то, что в настоящее время находится в текстовом файле в другой программе).

Это код, который я использую (VB.NET)

Dim strContents As String
Dim objReader As StreamReader
objReader = New StreamReader(FullPath)
strContents = objReader.ReadToEnd()
objReader.Close()

Или в C#:

var objReader = new StreamReader(FullPath);
var strContents = objReader.ReadToEnd();
objReader.Close();

Выше, однако, выдает исключение ввода-вывода "Процесс не может получить доступ к файлу file.txt, потому что он используется другим процессом". Есть ли обходные пути в этом сценарии?

5 ответов

Решение
FileStream logFileStream = new FileStream("c:\test.txt", FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader logFileReader = new StreamReader(logFileStream);

while (!logFileReader.EndOfStream)
{
    string line = logFileReader.ReadLine();
    // Your code here
}

// Clean up
logFileReader.Close();
logFileStream.Close();

Исходный код

Я сделаю рыбу. Режим FileShare является критическим, вы должны разрешить совместное использование записи. Это нельзя отрицать, так как процесс, который записывает файл, уже получил доступ на запись. Конструктор StreamReader() использует FileShare.Read и не имеет возможности использовать другое значение. Использование конструктора StreamReader(Stream) вместо этого - действительно обходной путь.

Однако помните, что этот режим совместного использования также имеет значение для вашего кода. Вы не можете предсказать, когда другой процесс сбросит файл. Последняя прочитанная строка может содержать только часть строки текста. Когда он сбрасывает файловый буфер снова, позже вы получите остаток строки. Очевидно, это может испортить вашу логику.

Это зависит от FileShare режим, в котором файл был открыт другим приложением, добавляющим файл. Когда другое приложение открывало файл, оно указывало FileShare режим для других приложений для доступа к файлу. это FileShare Режим мог быть прочитан, записать, оба, удалить, все это, или ни одного.

Вы должны указать то же самое FileShare режим, указанный другим приложением. Если в другом приложении разрешено только чтение, используйте FileShare.Read; если это позволило и чтение и письмо, используйте FileShare.ReadWrite,

StreamReader использует только FileShare.Read режим, так что вы уже можете предположить, что это не правильно. Итак, попробуйте ReadWrite, вот так:

FileStream fs = new FileStream(FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader reader = new StreamReader(fs);

Не уверен, как это будет вести себя с уже открытым файлом, но это не позволит вашему приложению заблокировать его:

FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader sr = new StreamReader(fs);

Надеюсь, поможет!

Я извлек этот код из ChatGPT, и он работает! Сначала я запросил решение на C#, но безуспешно, затем попросил C++, удачи, затем попросил сделать то же самое на C#, вот нетронутый код. Изменить: принятый ответ также работает, странно, что я попробовал это.

      using System;
using System.IO;
using System.Runtime.InteropServices;

class Program
{
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr CreateFile(
        string lpFileName,
        FileAccess dwDesiredAccess,
        FileShare dwShareMode,
        IntPtr lpSecurityAttributes,
        FileMode dwCreationDisposition,
        FileAttributes dwFlagsAndAttributes,
        IntPtr hTemplateFile
    );

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadFile(
        IntPtr hFile,
        byte[] lpBuffer,
        uint nNumberOfBytesToRead,
        out uint lpNumberOfBytesRead,
        IntPtr lpOverlapped
    );

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool CloseHandle(IntPtr hObject);

    static void Main()
    {
        IntPtr fileHandle = CreateFile(
            "path/to/file.txt",
            FileAccess.Read,
            FileShare.ReadWrite,
            IntPtr.Zero,
            FileMode.Open,
            FileAttributes.Normal,
            IntPtr.Zero
        );

        if (fileHandle != IntPtr.Zero && fileHandle != new IntPtr(-1))
        {
            try
            {
                FileInfo fileInfo = new FileInfo("path/to/file.txt");
                byte[] buffer = new byte[fileInfo.Length];

                if (ReadFile(fileHandle, buffer, (uint)fileInfo.Length, out uint bytesRead, IntPtr.Zero))
                {
                    string content = System.Text.Encoding.Default.GetString(buffer, 0, (int)bytesRead);
                    Console.WriteLine(content);
                }
            }
            finally
            {
                CloseHandle(fileHandle);
            }
        }
        else
        {
            Console.WriteLine("Failed to open file");
        }
    }
}
Другие вопросы по тегам