Проверить, занят ли файл

Обновлено: 30.06.2024

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

Сегодня мы рассмотрим сценарий, который предоставляет дополнительную информацию о процессах, удерживающих файловую систему, используя fuser для предоставления идентификаторов процессов ps и ps для последующего отображения дополнительной информации о каждом процессе.

Первое, что делает этот конкретный скрипт, — это запрашивает у пользователя выбор файловой системы, которая его интересует. Мы делаем это с помощью оператора select. Однако, чтобы убедиться, что мы смотрим только на локально смонтированные файловые системы, мы направим наш вывод df через команду «grep '^/dev» (т.е. мы укажем сценарию отображать только те записи, которые начинаются с «/dev» ).

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

На этом этапе скрипта пользователь выберет файловую систему. Следующее, что мы делаем, это печатаем баннер с именем файловой системы. Затем мы используем команду fuser, чтобы найти PID процессов, которые используют конкретную файловую систему. Обратите внимание, что мы дважды отправляем стандартную ошибку в /dev/null. В заключенной в скобки части синтаксиса использование /dev/null по существу удаляет буквы (такие как «c», «m», «o» и другие, которые говорят, как каждый процесс использует файловую систему) из выходных данных фьюзера, тем самым предоставив команде ps чистый список PID.

Второе использование /dev/null избавляет наших пользователей от необходимости просматривать уродливый набор ошибок, если команда fuser обнаруживает, что процессы не запущены, а затем представляет пустой список процессов ps.

Команда ps использует параметр -o для выбора ряда переменных процесса, которые мы хотим видеть, и извлекает эту информацию для всех процессов, обнаруженных фьюзером. Запустив этот скрипт, вы увидите что-то вроде этого: В этом примере мы видим, что четыре процесса занимают /export/home. Мы также видим UID, родительский процесс и терминал, время процесса и конкретную команду, которая выполняется.

Мы теряем часть информации, отправляя стандартную ошибку фьюзера в /dev/null. Буквы («с» и подобные), которые были отправлены в битовое ведро, могут помочь пользователю понять, как каждый конкретный процесс использует конкретную файловую систему. Например, "c" указывает, что процесс использует файловую систему в качестве текущего каталога, а "m" указывает, что процесс использует файл, отображаемый с помощью mmap.

Один из способов дать некоторое представление о том, как загружена файловая система, — вставить такой код перед существующей командой fuser:

Команда fuser представляет собой код (да, здесь мы дублируем усилия), который будет хранить буквенные коды, связанные с выходными данными блока fuser, во временном файле, который впоследствии можно будет отобразить, а затем удалить следующим образом:

Этот код также проверяет, пуст ли список PID, печатает "Нет" и закрывает скрипт, если это так. Это позволило бы нам отказаться от второго перенаправления стандартной ошибки на /dev/null в нашей исходной команде fuser. Простой и, возможно, более полезный способ (особенно если мы уже хотим запустить команду fuser во второй раз) — просто добавить эту команду fuser в конец скрипта:

Эта команда распечатает PID вместе с соответствующими буквенными кодами:

Затем пользователь может сравнить эту информацию с уже показанным списком процессов. Если вы сделаете это, вы также можете предоставить следующее объяснение из команды fuser man, чтобы ваши пользователи могли легко интерпретировать коды:

Эта статья "Совет Unix: использование термоблока для определения того, почему файловая система занята" была первоначально опубликована ITworld .

Сандра Генри-Стокер занимается администрированием систем Unix более 30 лет. Она описывает себя как «USL» (Unix как второй язык), но помнит достаточно английского, чтобы писать книги и покупать продукты. Она живет в горах в Вирджинии, где, когда не работает с Unix и не пишет о ней, отгоняет медведей от своих кормушек для птиц.

Этот форум перенесен в раздел вопросов и ответов Майкрософт. Посетите Microsoft Q&A, чтобы публиковать новые вопросы.

Ссылка на главную страницу Visual Studio

Отвечает:

Вопрос

Я до сих пор не могу понять, как это сделать.

У меня есть эта часть:

Затем метод WatchDirectory:

Затем событие OnChanged:

И метод IsFileLocked:

Теперь порядок должен быть таким: сначала он пойдет в WatchDirectory, а затем в цикле while проверит, заблокирован/занят ли файл после того, как файл больше не заблокирован/занят, продолжите с остальной частью кода StreamWriter uploadedFilesList.Add и Youtube_Uploader.

Во-первых, я не уверен, правильно ли использовать цикл While с 100. И, во-вторых, как мне сделать так, чтобы он сначала заканчивал проверку блокировки файла, прежде чем продолжить? Теперь он получает доступ к WatchDirectory, а затем создает StreamWriter. Не тот порядок, в котором я хочу.

Мне посоветовали этот совет по решению:

" Ответ сложнее, чем я хочу написать субботним утром, больным и уставшим. Я скажу, что вам нужно знать следующие вещи: WatchDirectory возвращается немедленно, он не ждет событий. OnChanged событие вызывается в отдельном потоке. Вы должны использовать BackgroundWorker и ManualResetEvent s, чтобы сигнализировать, когда файлы были изменены или разблокированы. Не опрашивайте статус блокировки; либо используйте таймер, либо посмотрите, может ли FileSystemWatcher это сделать. "

Но я не знаю, как это сделать.

Ответы

Ребята. Я правда не понимаю, почему ты ему об этом не скажешь:

Напишите функцию, которая возвращает true или false и имеет аргумент out типа FileStream.

Вы никогда не проверяете, открыт ли файл или что-то еще (как сказали Вик и Кристофер), потому что файл мог измениться, когда ваш метод возвращает значение true или false. Вот почему вы должны использовать в качестве аргумента out FileStream:

этот метод также можно использовать в цикле (ofc):

Все ответы

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

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

С другой стороны, если вы просто ждете завершения операции, то ваша функция IsFileLocked в основном верна, за исключением двух моментов. Вероятно, следует тестировать только Open, а не OpenOrCreate. И функцию обязательно нужно переименовать, потому что, говоря семантически, вы узнаете, только если файл заблокирован во время теста. Что-то внешнее может заблокировать файл после возврата IsFileLocked. Таким образом, он не представляет текущее состояние файла. После завершения теста (после возврата функции) вы не знаете, заблокирован ли файл в данный момент или нет. Предположим, IsFileLocked вернул true — значит ли это, что файл теперь заблокирован? Вы не знаете. Или предположим, что IsFileLocked вернул false. Означает ли это, что файл теперь разблокирован? Вы не знаете (может снова заблокироваться извне).

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

То же самое относится и к таким функциям, как "FileExists". Вы не знаете, существует ли файл после вызова (даже если он возвращает false, возможно, его кто-то только что создал, или если он возвращает true, что-то могло быть только что удалено). это).

В любом случае, мне кажется, что я немного придираюсь. Но я просто очень не хочу, чтобы кто-то заимствовал вашу функцию IsFileLocked и использовал ее, чтобы каким-то образом подумать, что они определили состояние файла. Лучше было бы название, описывающее, что делает функция, а не делающее никаких выводов со словом «Есть». Что-то вроде "TestFileOpen" было бы лучше. Он делает именно это и не дает гарантии того, заблокирован ли файл в данный момент, а только успешность проверки открытия и закрытия файла. Пусть вызывающий его код воплощает в себе логические выводы, которые следует сделать из результатов теста. Эти выводы в значительной степени зависят от внешних знаний о файле и о том, что с ним делает система.

Читайте также: