kzen.dev
  • Вопросы
  • Метки
  • Пользователи
Оповещения
Вознаграждения
Регистрация
После регистрации, сможете получать уведомления об ответах и комментариях на Ваши вопросы.
Вход
Если у Вас уже есть аккаунт, войдите чтобы проверить новые уведомления.
Тут будут вознаграждения за добавленные вопросы, ответы и комментарий.
Дополнительно
Источник
Редактировать
 ricree
ricree
Вопрос

Как проверить блокировку файла?

Есть ли способ проверить, заблокирован ли файл, не используя блок try/catch?

Сейчас единственный известный мне способ - просто открыть файл и перехватить любое System.IO.IOException.

246 2008-08-04T14:56:57+00:00 12
Hossein  Narimani Rad
Hossein Narimani Rad
Редактировал вопрос 30-го апреля 2015 в 10:33
Программирование
.net
c#
io
filelock
 DixonD
DixonD
8-го июля 2010 в 9:12
2010-07-08T09:12:36+00:00
Дополнительно
Источник
Редактировать
#8407445

Когда я сталкивающийся с подобной проблемой, я закончил со следующим кодексом:

public bool IsFileLocked(string filePath)
{
    try
    {
        using (File.Open(filePath, FileMode.Open)){}
    }
    catch (IOException e)
    {
        var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);

        return errorCode == 32 || errorCode == 33;
    }

    return false;
}
172
0
Eric J.
Eric J.
16-го декабря 2013 в 11:47
2013-12-16T23:47:30+00:00
Дополнительно
Источник
Редактировать
#8407451

Другие ответы полагаются на старую информацию. Этот предоставляет лучшее решение.

Давно было невозможно надежно получить список процессов, запирающих файл, потому что Windows просто не отслеживал ту информацию. Чтобы поддержать менеджер по Перезапуску API, та информация теперь прослежена. Менеджер по Перезапуску API является доступным началом с Windows Vista и Windows Server 2008 ([менеджер по Перезапуску: Требования во время выполнения] [2]).

Я соединил кодекс, который берет путь файла и возвращает 'List< Process&gt'; из всех процессов, которые захватывают тот файл.

static public class FileUtil
{
    [StructLayout(LayoutKind.Sequential)]
    struct RM_UNIQUE_PROCESS
    {
        public int dwProcessId;
        public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
    }

    const int RmRebootReasonNone = 0;
    const int CCH_RM_MAX_APP_NAME = 255;
    const int CCH_RM_MAX_SVC_NAME = 63;

    enum RM_APP_TYPE
    {
        RmUnknownApp = 0,
        RmMainWindow = 1,
        RmOtherWindow = 2,
        RmService = 3,
        RmExplorer = 4,
        RmConsole = 5,
        RmCritical = 1000
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    struct RM_PROCESS_INFO
    {
        public RM_UNIQUE_PROCESS Process;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)]
        public string strAppName;

        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)]
        public string strServiceShortName;

        public RM_APP_TYPE ApplicationType;
        public uint AppStatus;
        public uint TSSessionId;
        [MarshalAs(UnmanagedType.Bool)]
        public bool bRestartable;
    }

    [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
    static extern int RmRegisterResources(uint pSessionHandle,
                                          UInt32 nFiles,
                                          string[] rgsFilenames,
                                          UInt32 nApplications,
                                          [In] RM_UNIQUE_PROCESS[] rgApplications,
                                          UInt32 nServices,
                                          string[] rgsServiceNames);

    [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)]
    static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);

    [DllImport("rstrtmgr.dll")]
    static extern int RmEndSession(uint pSessionHandle);

    [DllImport("rstrtmgr.dll")]
    static extern int RmGetList(uint dwSessionHandle,
                                out uint pnProcInfoNeeded,
                                ref uint pnProcInfo,
                                [In, Out] RM_PROCESS_INFO[] rgAffectedApps,
                                ref uint lpdwRebootReasons);

    /// <summary>
    /// Find out what process(es) have a lock on the specified file.
    /// </summary>
    /// <param name="path">Path of the file.</param>
    /// <returns>Processes locking the file</returns>
    /// <remarks>See also:
    /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx
    /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing)
    /// 
    /// </remarks>
    static public List<Process> WhoIsLocking(string path)
    {
        uint handle;
        string key = Guid.NewGuid().ToString();
        List<Process> processes = new List<Process>();

        int res = RmStartSession(out handle, 0, key);

        if (res != 0)
            throw new Exception("Could not begin restart session.  Unable to determine file locker.");

        try
        {
            const int ERROR_MORE_DATA = 234;
            uint pnProcInfoNeeded = 0,
                 pnProcInfo = 0,
                 lpdwRebootReasons = RmRebootReasonNone;

            string[] resources = new string[] { path }; // Just checking on one resource.

            res = RmRegisterResources(handle, (uint)resources.Length, resources, 0, null, 0, null);

            if (res != 0) 
                throw new Exception("Could not register resource.");                                    

            //Note: there's a race condition here -- the first call to RmGetList() returns
            //      the total number of process. However, when we call RmGetList() again to get
            //      the actual processes this number may have increased.
            res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons);

            if (res == ERROR_MORE_DATA)
            {
                // Create an array to store the process results
                RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
                pnProcInfo = pnProcInfoNeeded;

                // Get the list
                res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);

                if (res == 0)
                {
                    processes = new List<Process>((int)pnProcInfo);

                    // Enumerate all of the results and add them to the 
                    // list to be returned
                    for (int i = 0; i < pnProcInfo; i++)
                    {
                        try
                        {
                            processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
                        }
                        // catch the error -- in case the process is no longer running
                        catch (ArgumentException) { }
                    }
                }
                else
                    throw new Exception("Could not list processes locking resource.");                    
            }
            else if (res != 0)
                throw new Exception("Could not list processes locking resource. Failed to get size of result.");                    
        }
        finally
        {
            RmEndSession(handle);
        }

        return processes;
    }
}

ОБНОВЛЕНИЕ

Вот является другой [обсуждением с типовым кодексом] [3] о том, как использовать менеджера по Перезапуску API.

[2]: https://msdn.microsoft.com/en-us/library/windows/desktop/cc948910 (v=vs.85) .aspx [3]: https://blogs.msdn.microsoft.com/oldnewthing/20120217-00/? p=8283

137
0
Решение / Ответ
angry person
angry person
4-го августа 2008 в 2:59
2008-08-04T14:59:24+00:00
Дополнительно
Источник
Редактировать
#8407439

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

Почему именно вам нужно знать, заблокирован ли файл? Зная это, мы могли бы дать вам хороший совет.

Если бы ваш код выглядел следующим образом:

if not locked then
    open and update file

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

131
0
 Aralmo
Aralmo
1-го апреля 2011 в 11:19
2011-04-01T11:19:20+00:00
Дополнительно
Источник
Редактировать
#8407447

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

public static string GetFileProcessName(string filePath)
{
    Process[] procs = Process.GetProcesses();
    string fileName = Path.GetFileName(filePath);

    foreach (Process proc in procs)
    {
        if (proc.MainWindowHandle != new IntPtr(0) && !proc.HasExited)
        {
            ProcessModule[] arr = new ProcessModule[proc.Modules.Count];

            foreach (ProcessModule pm in proc.Modules)
            {
                if (pm.ModuleName == fileName)
                    return proc.ProcessName;
            }
        }
    }

    return null;
}
Markus Safar
Markus Safar
Редактировал ответ 7-го февраля 2016 в 12:30
19
0
Sergio Vicente
Sergio Vicente
8-го марта 2010 в 5:09
2010-03-08T17:09:15+00:00
Дополнительно
Источник
Редактировать
#8407444

Вместо того, чтобы использовать interop Вы можете использовать Замок методов.NET FileStream класса и Открыть:

FileStream. Замок http://msdn.microsoft.com/en-us/library/system.io.filestream.lock.aspx

FileStream. Открыть http://msdn.microsoft.com/en-us/library/system.io.filestream.unlock.aspx

15
0
Sam Saffron
Sam Saffron
24-го июля 2009 в 6:42
2009-07-24T06:42:10+00:00
Дополнительно
Источник
Редактировать
#8407443

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

7
0
 Tristan
Tristan
3-го января 2013 в 3:41
2013-01-03T03:41:42+00:00
Дополнительно
Источник
Редактировать
#8407448

Изменение DixonD' s превосходный ответ (выше).

public static bool TryOpen(string path,
                           FileMode fileMode,
                           FileAccess fileAccess,
                           FileShare fileShare,
                           TimeSpan timeout,
                           out Stream stream)
{
    var endTime = DateTime.Now + timeout;

    while (DateTime.Now < endTime)
    {
        if (TryOpen(path, fileMode, fileAccess, fileShare, out stream))
            return true;
    }

    stream = null;
    return false;
}

public static bool TryOpen(string path,
                           FileMode fileMode,
                           FileAccess fileAccess,
                           FileShare fileShare,
                           out Stream stream)
{
    try
    {
        stream = File.Open(path, fileMode, fileAccess, fileShare);
        return true;
    }
    catch (IOException e)
    {
        if (!FileIsLocked(e))
            throw;

        stream = null;
        return false;
    }
}

private const uint HRFileLocked = 0x80070020;
private const uint HRPortionOfFileLocked = 0x80070021;

private static bool FileIsLocked(IOException ioException)
{
    var errorCode = (uint)Marshal.GetHRForException(ioException);
    return errorCode == HRFileLocked || errorCode == HRPortionOfFileLocked;
}

Использование:

private void Sample(string filePath)
{
    Stream stream = null;

    try
    {
        var timeOut = TimeSpan.FromSeconds(1);

        if (!TryOpen(filePath,
                     FileMode.Open,
                     FileAccess.ReadWrite,
                     FileShare.ReadWrite,
                     timeOut,
                     out stream))
            return;

        // Use stream...
    }
    finally
    {
        if (stream != null)
            stream.Close();
    }
}
Markus Safar
Markus Safar
Редактировал ответ 7-го февраля 2016 в 12:32
7
0
 live-love
live-love
24-го сентября 2013 в 6:34
2013-09-24T18:34:18+00:00
Дополнительно
Источник
Редактировать
#8407449

Here' s изменение DixonD' s кодекс, который добавляет число секунд, чтобы ждать файла, чтобы открыть, и попробовать еще раз:

public bool IsFileLocked(string filePath, int secondsToWait)
{
    bool isLocked = true;
    int i = 0;

    while (isLocked &&  ((i < secondsToWait) || (secondsToWait == 0)))
    {
        try
        {
            using (File.Open(filePath, FileMode.Open)) { }
            return false;
        }
        catch (IOException e)
        {
            var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
            isLocked = errorCode == 32 || errorCode == 33;
            i++;

            if (secondsToWait !=0)
                new System.Threading.ManualResetEvent(false).WaitOne(1000);
        }
    }

    return isLocked;
}

if (!IsFileLocked(file, 10))
{
    ...
}
else
{
    throw new Exception(...);
}
Markus Safar
Markus Safar
Редактировал ответ 7-го февраля 2016 в 12:35
7
0
Brian  R. Bondy
Brian R. Bondy
9-го марта 2009 в 12:54
2009-03-09T12:54:57+00:00
Дополнительно
Источник
Редактировать
#8407442

Вы можете проверить, заблокирован ли файл, попытавшись сначала прочитать или заблокировать его самостоятельно.

Для получения дополнительной информации см. мой ответ здесь.

 Community
Community
Редактировал ответ 23-го мая 2017 в 12:34
6
0
S&#246;ren Kuklau
Sören Kuklau
17-го августа 2008 в 6:17
2008-08-17T18:17:12+00:00
Дополнительно
Источник
Редактировать
#8407441

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

Однако, таким образом, вы будете знать, что проблема временная, и сможете повторить попытку позже. (Например, вы можете написать поток, который, столкнувшись с блокировкой при попытке записи, будет повторять попытку до тех пор, пока блокировка не исчезнет).

С другой стороны, исключение IOException само по себе не является достаточно специфичным, чтобы считать блокировку причиной сбоя ввода-вывода. Могут быть причины, которые не являются временными.

6
0
thom schumacher
thom schumacher
23-го декабря 2015 в 2:24
2015-12-23T14:24:09+00:00
Дополнительно
Источник
Редактировать
#8407452

То же самое, но в Powershell

function Test-FileOpen
{
    Param
    ([string]$FileToOpen)
    try
    {
        $openFile =([system.io.file]::Open($FileToOpen,[system.io.filemode]::Open))
        $open =$true
        $openFile.close()
    }
    catch
    {
        $open = $false
    }
    $open
}
Markus Safar
Markus Safar
Редактировал ответ 7-го февраля 2016 в 12:33
1
0
Bart Calixto
Bart Calixto
16-го декабря 2013 в 7:19
2013-12-16T19:19:18+00:00
Дополнительно
Источник
Редактировать
#8407450

То, что я закончил тем, что делал:

internal void LoadExternalData() {
    FileStream file;

    if (TryOpenRead("filepath/filename", 5, out file)) {
        using (file)
        using (StreamReader reader = new StreamReader(file)) {
         // do something 
        }
    }
}

internal bool TryOpenRead(string path, int timeout, out FileStream file) {
    bool isLocked = true;
    bool condition = true;

    do {
        try {
            file = File.OpenRead(path);
            return true;
        }
        catch (IOException e) {
            var errorCode = Marshal.GetHRForException(e) & ((1 << 16) - 1);
            isLocked = errorCode == 32 || errorCode == 33;
            condition = (isLocked && timeout > 0);

            if (condition) {
                // we only wait if the file is locked. If the exception is of any other type, there's no point on keep trying. just return false and null;
                timeout--;
                new System.Threading.ManualResetEvent(false).WaitOne(1000);
            }
        }
    }
    while (condition);

    file = null;
    return false;
}
Markus Safar
Markus Safar
Редактировал ответ 7-го февраля 2016 в 12:34
0
0
Похожие сообщества 16
DotNetRuChat
DotNetRuChat
6 652 пользователей
Чат русскоязычного .NET сообщества http://dotnet.ru/ Правила: https://t.me/DotNetRuChat/704399 Вам могут быть интересны: @dotnetchat, @cilchat, @fsharp_chat, @pro_net, @AvaloniaRU, @xamarin_russia, @DotNetRuJobs, @uwp_ru Флуд в @dotnettalks
Открыть telegram
Вакансии .NET
Вакансии .NET
3 530 пользователей
Правила: https://t.me/DotNetRuJobs/123 Канал с вакансиями - https://t.me/DotNetRuJobsFeed Вам могут быть интересны: @dotnetruchat, @cilchat, @fsharp_chat, @pro_net, @AvaloniaRU, @xamarin_russia Флуд в @dotnettalks
Открыть telegram
Microsoft Stack Jobs
Microsoft Stack Jobs
2 414 пользователей
Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks
Открыть telegram
С#
С#
2 330 пользователей
Стараемся не флудить. Пишем по делу. Правила: https://t.me/professorweb/430450 Для флуда @svoboda_obsh
Открыть telegram
pro.net
pro.net
1 820 пользователей
Обсуждение .NET и всего, что с ним связано. Правила: не флудить не по теме, уважать ваших коллег и никакой рекламы (объявления о вакансиях можно согласовать с @AlexFails). https://t.me/pro_net/34653 Флудилка: @dotnettalks
Открыть telegram
CODE BLOG / C#
CODE BLOG / C#
1 772 пользователей
Чат для .NET разработчиков и C# программистов. По всем вопросам: @shwanoff Youtube-канал: https://youtube.com/codeblog Основной канал: @codeblog Вконтакте: https://vk.com/codeblog Правила: https://t.me/codeblog_csharp/246972 Вакансии по тегу #work
Открыть telegram
Добавить вопрос
Категории
Все
Технологий
Культура / Отдых
Жизнь / Искусство
Наука
Профессии
Бизнес
Пользователи
Все
Новые
Популярные
1
Ilya Smirnov
Зарегистрирован 5 дней назад
2
Денис Васьков
Зарегистрирован 1 неделю назад
3
Dima Patrushev
Зарегистрирован 1 неделю назад
4
sirojidddin otaboyev
Зарегистрирован 2 недели назад
5
Елена Гайдамамакинат
Зарегистрирован 2 недели назад
ID
JA
KO
RO
RU
© kzen.dev 2023
Источник
stackoverflow.com
под лицензией cc by-sa 3.0 с атрибуцией