.NET FileInfo.LastWriteTime & FileInfo.LastAccessTime ошибочны
Когда я вызываю FileInfo(path).LastAccessTime
или FileInfo(path).LastWriteTime
в файл, который находится в процессе записи, он возвращает время создания файла, а не последний раз, когда он был записан (т.е. сейчас).
Есть ли способ получить эту информацию?
Изменить: ко всем ответам до сих пор. Я не пробовал Refresh()
, но это тоже не делается. Мне возвращено время, когда файл был начат для записи. То же самое касается статического метода и создания нового экземпляра FileInfo
.
У Codymanix может быть ответ, но я не использую Windows Server (используя Windows 7), и я не знаю, где будет тестироваться параметр.
Изменить 2: Никто не считает интересным, что эта функция не работает?
Ответы
Ответ 1
Значения FileInfo
загружаются только один раз и затем кэшируются. Чтобы получить текущее значение, вызовите Refresh()
до получения свойства:
f.Refresh();
t = f.LastAccessTime;
Другой способ получить текущее значение - использовать статические методы класса File
:
t = File.GetLastAccessTime(path);
Ответ 2
Из MSDN:
При первом вызове FileSystemInfo вызовы Обновить и вернуть кэшированную информацию об API-интерфейсах атрибуты и т.д. На последующих звоните, вы должны позвонить Refresh, чтобы получить последняя копия информации.
FileSystemInfo.Refresh()
Если вы используете приложение, которое делает запись, я думаю, вам придется "прикоснуться" к файлу, установив свойство LastWriteTime самостоятельно между каждым буфером данных, которые вы пишете. Некоторые psuedocode:
while(bytesWritten < totalBytes)
{
bytesWritten += br.Write(buffer);
myFileInfo.LastWriteTime = DateTime.Now;
}
Я не уверен, как сильно это повлияет на производительность записи.
Ответ 3
В Windows есть настройка, которая иногда устанавливается особенно на серверных системах, так что измененные и доступные времена для файлов не установлены для лучшей производительности.
Ответ 4
Начиная с Windows Vista, последнее время доступа по умолчанию не обновляется. Это улучшает производительность файловой системы. Вы можете найти здесь:
http://blogs.technet.com/b/filecab/archive/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance.aspx
Чтобы повторно использовать последнее время доступа на компьютере, вы можете запустить следующую команду:
набор правил fsutil disablelastaccess 0
Ответ 5
Вы пытались позвонить Refresh()
непосредственно перед доступом к свойству (чтобы избежать получения кешированного значения)? Если это не сработает, посмотрите, что показывает Explorer одновременно? Если Explorer показывает неправильную информацию, то, возможно, это то, что вы действительно не можете адресовать - может быть, информация обновляется только тогда, когда дескриптор файла закрыт, например.
Ответ 6
Как отметил Джеймс, LastAccessTime не обновляется.
LastWriteTime также претерпевает изменения с Vista. Когда процесс имеет файл, все еще открыт, а другой процесс проверяет LastWriteTime, он не увидит новое время записи в течение длительного времени, пока процесс не завершит файл.
В качестве обходного пути вы можете открыть и закрыть файл из внешнего процесса. После этого вы можете попробовать прочитать LastWriteTime, а затем обновить значение.
Если приложение реализует нечто вроде скользящего регистратора, который закрывает файл, а затем переименовывает его в другое имя файла, вы также сталкиваетесь с проблемами, поскольку время создания и размер файла "старого" файла запоминаются ОС, хотя вы создали новый файл. Это включает неправильные отчеты о размере файла, даже если вы повторно создали log.txt с нуля, размер которого по-прежнему равен 0 байтам. Эта функция называется OS File System Tunneling, которая все еще присутствует в Windows 8.1. Пример того, как реализовать эту проблему, проверьте RollingFlatFileTracelistener из Enterprise Library (http://home.elka.pw.edu.pl/~mrudnik/CREAM/Logging/Src/Logging/TraceListeners/RollingFlatFileTraceListener.cs).
Вы можете увидеть эффекты туннелирования файловой системы на вашей собственной машине из командной оболочки cmd.
echo test > file1.txt
ren file1.txt file2.txt
Wait one minute
echo test > file1.txt
dir /tc file*.txt
...
05.07.2015 19:26 7 file1.txt
05.07.2015 19:26 7 file2.txt
Файловая система - это конечный автомат. Правильно синхронизировать состояния хранения сложно, если вы заботитесь о производительности и правильности.
Этот странный туннельный синдром, очевидно, все еще используется приложением, которое, например, автосохранение файла и переместите его в место сохранения, а затем снова создайте файл в том же месте. Для этих приложений он имеет смысл дать файлу новую дату создания, потому что он был только скопирован. Некоторые инсталляторы также делают такие трюки, чтобы временно перемещать файлы в другое место и записывать содержимое позже, чтобы пройти мимо какого-либо файла, существует проверка наличия некоторых крючков установки.
Ответ 7
Ответ Tommy Carlier заставил меня думать...
Хорошим способом визуализации различий является отдельный запуск двух фрагментов (я просто использовал LinqPAD), как показано ниже, а также для запуска монитора процессов sysinternals.
while(true)
File.GetLastAccessTime([file path here]);
и
FileInfo bob = new FileInfo(path);
while(true){
string accessed = bob.LastAccessTime.ToString();
}
Если вы посмотрите на Process Monitor во время запуска первого фрагмента, вы увидите попытки повторного и постоянного доступа к файлу для процесса LinqPAD. Второй фрагмент будет выполнять первоначальный доступ к файлу, для которого вы увидите активность на мониторе процесса, а затем очень мало потом.
Однако, если вы перейдете и измените файл (я только что открыл текстовый файл, который я отслеживал с помощью FileInfo, добавил символ и сохранил), вы увидите последовательность попыток доступа процесса LinqPAD к файлу в мониторе процесса.
Это иллюстрирует не кэшированное и кэшированное поведение двух разных подходов соответственно.
Будет ли не кэшированный подход носить отверстие на жестком диске?!
ИЗМЕНИТЬ
Я ушел, чувствуя себя умным над своим тестированием, а затем использовал поведение кеширования FileInfo в моей службе Windows (в основном, чтобы сидеть в цикле и говорить "Has-file-changed-has-file-changed..." раньше обработка)
Несмотря на то, что этот подход работал в моей dev-блоке, он не работал в рабочей среде, то есть процесс просто продолжал работать независимо от того, был ли файл изменен или нет. Я в конечном итоге изменил свой подход к проверке и просто использовал GetLastAccessTime как часть этого. Не знаю, почему это будет вести себя по-другому на производственном сервере... но я не слишком обеспокоен в этот момент.