Я считаю, что делаю это очень просто, чтобы гарантировать, что имя файла не используется. Есть ли лучший способ?
Directory.Exists(name) || File.Exists(name)
Я считаю, что делаю это очень просто, чтобы гарантировать, что имя файла не используется. Есть ли лучший способ?
Directory.Exists(name) || File.Exists(name)
Конечно:)
internal static bool FileOrDirectoryExists(string name)
{
return (Directory.Exists(name) || File.Exists(name));
}
Обратите внимание, что тот факт, что вы используете 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
.
Я думаю, что единственный способ. Обычно у меня есть класс "FileManager", у которого есть статические методы, инкапсулирующие методы ввода-вывода, включая те, которые вы указали, и затем используйте этот "FileManager" для всех приложений в виде библиотеки.
Другой способ проверить, существует ли файл.
FileInfo file = new FileInfo("file.txt");
if (file.Exists)
{
// TO DO
}
Мой способ проверить это с помощью FileSystemInfo, вот мой код:
FileSystemInfo info =
File.GetAttributes(data.Path).HasFlag(FileAttributes.Directory) ?
new DirectoryInfo(data.Path) : (FileSystemInfo)new FileInfo(data.Path);
return info.Exists;
Вы можете использовать следующую функцию:
[DllImport("shlwapi", EntryPoint = "PathFileExists", CharSet = CharSet.Unicode)]
public static extern bool PathExists(string path);
bool FileOrDirectoryExists(string path)
{
try
{
File.GetAttributes(_source);
}
catch (FileNotFoundException)
{
return false;
}
return true;
}