Является ли "последовательный" файловый ввод-вывод безопасным методом System.IO.File?
Я только что увидел этот вопрос: Можно ли использовать статические методы в классе File в С#?. Подводя итог OP имеет IOException
, потому что файл используется в этом фрагменте кода ASP.NET:
var text= File.ReadAllText("path-to-file.txt");
// Do something with text
File.WriteAllText("path-to-file.txt");
Моя первая мысль была простой проблемой одновременного доступа из-за множественных запросов ASP.NET. Что-то я решил бы централизовать ввод-вывод в синхронизированный потокобезопасный класс (или отбрасывать файлы в пользу чего-то еще). Я прочитал оба ответа, и когда я собирался понизить один из них, я увидел, кто эти пользователи, и я подумал, что это за h * и остановился.
Я приведу их обоих (тогда, пожалуйста, обратитесь к оригинальным ответам для большего контекста).
Для этого пункта OP:
Я предполагаю, что операция чтения файла иногда не закрывает файл до того, как произойдет операция записи [...]
В ответ говорится:
Правильно. Файловые системы хорошо не поддерживают атомные обновления [...] Использование FileStream не помогает [...] У файла нет магии внутри. Он просто использует FileStream, завернутый для вашего удобства.
Однако я не вижу ожиданий для атомной операции (чтение + последующая запись) и параллельной (из-за частично перекрывающихся многопоточных запросов) может вызвать одновременный доступ. Даже операция атомарного ввода-вывода (чтение + запись) будет иметь точно такую же проблему. OK FileStream
может быть асинхронным, но не использовать File.ReadAllText()
и File.WriteAllText()
.
Другой ответ заставил меня гораздо более озадачен, он говорит:
Несмотря на то, что согласно документации файл-дескриптор гарантированно закрывается этим методом, даже если исключения подняты, время закрытия не гарантируется, прежде чем метод вернется: закрытие может выполняться асинхронно.
Что? MSDN говорит, что метод откроет, прочитает и закроет файл (также в случае исключений). Возможно ли, что такой метод будет закрывать файл асинхронно? Остановит ли ОС CloseHandle()
? В каких случаях? Почему?
Короче: это просто недоразумение или CloseHandle()
является асинхронным? Мне не хватает чего-то важного чрезвычайно?
Ответы
Ответ 1
Первые две цитаты в вашем вопросе не должны быть связаны. Когда File.*
выполняется или когда вы закрываете FileStream
, файл разблокируется немедленно. Никогда не бывает "затянувшегося". Если бы вы не могли безопасно получить доступ к тому же файлу без перезагрузки.
Может ответить, что код в вопросе запускается несколько раз параллельно. Если нет, этот код явно безопасен.
Однако я не вижу ожиданий для атомной операции... Даже операция атомарного ввода-вывода (чтение + запись) будет иметь точно такую же проблему.
Это правда. Я не знаю, почему я сделал выражение об этом в своем ответе (это правда, хотя и не актуально).
время закрытия не гарантируется, прежде чем метод вернется: закрытие может выполняться асинхронно.
Я не знаю, почему он сказал это, потому что это не правильно ни при каких обстоятельствах, о которых я могу думать. Закрытие ручки имеет немедленный эффект.
Я думаю, что ваше понимание ситуации абсолютно точно. По-видимому, наши ответы были неясными и слегка вводящими в заблуждение... Извините.
Ответ 2
Если вы посмотрите на документацию CloseHandle
, в нем говорится, что каждый метод, который открывает дескриптор, имеет описание того, как он должен быть закрыт
Документация для функций, которые создают эти объекты указывает, что CloseHandle следует использовать, когда вы закончите с объект и что происходит с ожидающими действиями над объектом после ручка закрыта. В целом, CloseHandle делает недействительными указанный дескриптор объекта, уменьшает количество совпадений объекта и выполняет проверки на сохранение объектов. После последнего дескриптора объекта закрывается, объект удаляется из системы.
Когда вы смотрите CreateFile
документы, это то, что он говорит:
Когда приложение завершено с использованием дескриптора объекта, возвращаемого CreateFile, используйте функцию CloseHandle, чтобы закрыть дескриптор. Это не только освобождает системные ресурсы, но может оказывать более широкое влияние на вещи например, совместное использование файла или устройства и передача данных на диск.
Мне было бы странно, что CloseHandle
приведет к тому, что основной дескриптор будет закрыт при асинхронном сохранении файла для дополнительных проверок. Это ослабит многие гарантии, которые ОС сделает для вызывающих, и будет источником многих ошибок.