Ответ 1
Вы можете удалить открытый файл?
Это совершенно справедливо, чтобы удалить запись каталога файла, когда файл открыт. В Unix это семантика по умолчанию, и Windows ведет себя FILE_SHARE_DELETE
если FILE_SHARE_DELETE
установлен на всех файловых дескрипторах, открытых для этого файла.
[Редактировать: Спасибо @couling за обсуждения и исправления]
Однако есть небольшая разница: Unix удаляет имя файла немедленно, а Windows удаляет имя файла только тогда, когда последний дескриптор закрыт. Однако он не позволяет открывать файл с тем же именем до тех пор, пока последний дескриптор (удаленного) файла не будет закрыт.
Пойди разберись...
Однако в обеих системах удаление файла не обязательно приводит к его удалению, оно все еще занимает место на диске, пока есть открытый дескриптор. Пространство, занимаемое файлом, освобождается только тогда, когда последний открытый дескриптор закрыт.
Экскурсия: Windows
Необходимость указания флага в Windows заставляет большинство людей думать, что Windows не может удалить открытые файлы, но на самом деле это не так. Это просто поведение по умолчанию.
Позволяет последующим операциям открытия файла или устройства запрашивать доступ для удаления.
В противном случае другие процессы не могут открыть файл или устройство, если они запрашивают доступ для удаления.
Если этот флаг не указан, но файл или устройство были открыты для доступа для удаления, функция завершается ошибкой. Примечание. Доступ к удалению позволяет выполнять операции удаления и переименования.
Функция DeleteFile помечает файл для удаления при закрытии. Следовательно, удаление файла не происходит до тех пор, пока последний дескриптор файла не будет закрыт. Последующие вызовы CreateFile для открытия файла завершаются с ошибкой ERROR_ACCESS_DENIED.
Наличие открытого дескриптора файла без имени является одним из наиболее типичных способов создания неназванных временных файлов: создайте новый файл, откройте его, удалите файл. Теперь у вас есть дескриптор файла, который никто другой не может открыть. В Unix имя файла действительно исчезло, а в Windows вы не можете открыть файл с таким же именем.
Вопрос сейчас:
Есть ли в Files.newOutputStream() значение FILE_SHARE_DELETE
?
Глядя на источник, вы можете увидеть, что shareDelete
действительно имеет значение true
. Единственный способ сбросить его - использовать нестандартный ExtendedOpenOption
NOSHARE_DELETE
.
Так что да, вы можете удалять открытые файлы в Java, если они явно не заблокированы.
Почему я не могу заново создать удаленный файл?
Ответ на этот вопрос скрыт в документации к DeleteFile()
выше: файл помечен только для удаления, файл все еще там. В Windows вы не можете создать файл с именем файла, помеченного для удаления, до тех пор, пока файл не будет удален должным образом, т.е. все дескрипторы файла будут закрыты.
Возможно, путаница в смешивании удаления имени и фактического удаления файла является причиной, по которой Windows в первую очередь не разрешает удалять открытые файлы по умолчанию.
Почему Files.exists()
возвращает false
?
Files.exists()
в глубоком конце Windows открывает этот файл в какой-то момент, и мы уже знаем, что мы не можем повторно открыть удаленный, но все еще открытый файл в Windows.
Подробно: Java-код вызывает FileSystemProvider.checkAccess()
) без аргументов, который вызывает WindowsFileSystemProvider.checkReadAccess()
который сразу же пытается открыть файл и, следовательно, не удается. Из того, что я могу сказать, это путь, используемый при вызове Files.exist()
.
Существует также другой путь кода, который вызывает GetFileAttributeEx()
для получения атрибутов файла. Еще раз, не задокументировано, что происходит, когда вы пытаетесь получить атрибуты удаленного, но еще не удаленного файла, но на самом деле вы не можете получить атрибуты файла, помеченного для удаления.
Догадываясь, я бы сказал, что GetFileAttributeEx()
вызывает GetFileInformationByHandle()
в какой-то момент, к которому он никогда не доберется, потому что он не может получить дескриптор файла в первую очередь.
Таким образом, после DeleteFile()
файл DeleteFile()
для большинства практических целей. Однако у него все еще есть имя, которое отображается в списках каталогов, и вы не можете открыть файл с тем же именем, пока у исходного файла не будут закрыты все его дескрипторы.
Это поведение более или менее согласовано, поскольку использование GetFileAttributes()
для проверки существования файла фактически является проверкой доступности файла, которая интерпретируется как существование файла. FindFirstFile()
(используется проводником Windows для определения списка файлов) находит имена файлов, но ничего не говорит о доступности имен.
Добро пожаловать в еще несколько странных петель в вашей голове.