Могу ли я узнать, находится ли другой процесс в процессе создания файла? - PullRequest
2 голосов
/ 07 марта 2011

Я пишу службу Windows для обработки файлов, созданных другим процессом, который я не могу контролировать.Эти файлы могут быть очень большими (сотни мегабайт).

Мне нужно обработать, а затем удалить файлы после того, как они были созданы.

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

Что меня беспокоит, так эточто произойдет, если мой сервис запросит каталог во время записи большого файла?Будет ли файл отображаться на моем сервисе?Будет ли он заблокирован, чтобы я не мог получить доступ для чтения?Нужно ли делать что-то особенное, чтобы проверить, закончил ли файл копирование, или я могу просто запросить File.Exists() или попробовать открыть его с помощью FileAccess.Read.Как Windows помечает файл, который находится в процессе копирования?

Ответы [ 3 ]

2 голосов
/ 07 марта 2011

Если бы это был простой win32, вы бы попытались открыть файл с CreateFile() и режимом совместного использования, который запрещал доступ на запись другим. Это может привести к сбою, если другая программа все еще записывает файл, поскольку вы не можете отказать в доступе на запись, когда файл уже открыт с правами на запись. Если это успешно, вы знаете, что другой процесс завершен.

В .net вы можете, например, создать FileStream, используя один из конструкторов, который получает параметр FileShare. Это в конечном итоге будет отображаться на базовый CreateFile() API.

1 голос
/ 07 марта 2011

AFAIK в файле нет специальной метки, указывающей на то, что он копируется, кроме того, что он будет иметь блокировку записи.В этой ситуации стандартной практикой является попытка самостоятельно открыть файл с блокировкой записи (например, FileShare.Read) и перехватить любое исключение IOException, возникающее из-за того, что файл уже заблокирован;в этом случае немного подождите (Thread.Sleep) перед повторной попыткой открыть файл.Возможно, вы захотите ограничить количество повторных попыток (чтобы предотвратить бесконечный цикл в случае, если существующая блокировка файла никогда не снимается).

Вы говорите, что хотите обработать файлы, а затем удалить их?Чтобы избежать гонки с другим процессом / потоком, записывающим в тот же файл во время его обработки / удаления его, вы должны рассматривать свою обработку / удаление как элементарную операцию, например, что-то вроде этого:

string sourcePath = @"C:\temp1\temp.txt";
string targetPath = @"C:\temp2\temp.txt";
int attempt = 0;
const int maxAttempts = 3;
bool moved = false;
do
{
    try
    {
        File.Move(sourcePath, targetPath);
        moved = true;
    }
    catch (IOException)
    {
        if (attempt < maxAttempts)
        {
            System.Threading.Thread.Sleep(1000);
            attempt++;
        }
    }
} while (!moved && attempt < maxAttempts);

if (moved)
{
     ProcessFile(targetPath);
     File.Delete(targetPath);
}
else
{
    throw new InvalidOperationException("Unable to process '" + sourcePath + "'.");
}

Edit: я вижу, вы говорите, что файлы могут быть очень большими, поэтому вы не должны использовать File.ReadAllText.Вместо этого вы можете попытаться переместить файлы в другой каталог - это вызовет исключение, если файл все еще заблокирован другим процессом.Вы обрабатываете файл, только если успешно переместите его.Это также имеет преимущество удаления файла из входного каталога.

0 голосов
/ 07 марта 2011

Напишите файл с временным именем файла, а затем переименуйте файл.

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

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