Обратите внимание, что тот факт, что вы используете Exists () для проверки имени файла или каталога при использовании , зависит от условий гонки.
В любой момент после того, как ваш Exists () тест пройден, что-то могло создать файл с таким именем до того, как ваш код достигнет точки, где вы создаете файл, например.
(я предполагаю, что это исключительное условие для того, чтобы файл уже существовал).
Надежнее просто открыть файл, указав соответствующий параметр FileShare.
Пример:
using System;
using System.IO;
static class FileNameInUse
{
static void Main(string[] args)
{
string path = args[0];
using (var stream = File.Open(path, FileMode.CreateNew, FileAccess.Write, FileShare.None))
{
// Write to file
}
}
}
Таким образом, простая обработка IOException при сбое может привести к тому, что более простой код будет менее подвержен условиям гонки, потому что теперь:
- Если что-то еще уже создало файл,
FileMode.CreateNew
вызовет выброс IOException
- Если открытие и создание завершилось успешно из-за
FileShare.None
, никакой другой процесс не сможет получить доступ к файлу, пока вы не закроете его.
К сожалению, невозможно проверить, используется ли файл в данный момент , и не выдать исключение, без какого-либо уродливого P / Invoke:
bool IsFileInUse(string fileName)
{
IntPtr hFile = Win32.CreateFile(fileName, Win32.FILE_READ_DATA, 0, IntPtr.Zero, Win32.OPEN_EXISTING, Win32.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
if (hFile.ToInt32() == Win32.INVALID_HANDLE_VALUE)
return true;
Win32.CloseHandle(hFile);
return false;
}
class Win32
{
const uint FILE_READ_DATA = 0x0001;
const uint FILE_SHARE_NONE = 0x00000000;
const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
const uint OPEN_EXISTING = 3;
const int INVALID_HANDLE_VALUE = -1;
[DllImport("kernel32.dll", SetLastError=true)]
internal static extern IntPtr CreateFile(string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile);
[DllImport("kernel32.dll")]
internal static extern bool CloseHandle(IntPtr hObject);
}
И эта быстрая проверка также подвержена условиям гонки, если вы не вернете из нее дескриптор файла и не передадите его соответствующему конструктору FileStream
.