Есть блог MSDN, описывающий, почему Windows ведет себя так, как вы это описываете.
Сначала отметим, что вы видите только NTFS.
Чтобы проверить, что вы сказали, я написал небольшую программу, которая записывает 40 КБ в файл каждые 5 секунд. Файл остается открытым между каждой записью. Вторая программа использует FindFirstFileEx
чтобы получить текущий размер файла. В качестве третьего я использую dir
в cmd.exe. С этой настройкой я могу точно видеть, что вы описываете.
Причиной этой проблемы является проектное решение, принятое в NTFS. В NTFS (как и в файловой системе Unix) один и тот же файл может находиться в двух каталогах - это называется жесткой ссылкой. Это означает, что у вас есть две директории, каждая из которых имеет запись для файла, и у вас есть сам файл с его свойствами. Размер файла - это свойство, которое принадлежит файлу, поэтому оно хранится там. Но если кто-то захочет получить список файлов в каталоге со свойствами, такими как размер файла, производительность будет очень низкой, если вы будете не только читать сам каталог, но и читать информацию из каждого файла. Данные для одного каталога, вероятно, будут храниться последовательно, но данные для разных файлов, вероятно, будут разбросаны по всему диску. Поэтому NTFS хранит копию размера файла в записи / записи каталога.
Вы, возможно, догадались, это также имеет удар по производительности. Подумайте о 10 жестких ссылках на один файл. Хотите, чтобы NTFS обновляла 10 записей каталога каждый раз, когда вы записываете в файл? Нет. Итак, второе решение о дизайне было принято после Vista: данные в записи каталога обновляются только при закрытии файла.
Вы можете легко это проверить: запустить программу, которая пишет в файл и сохраняет его открытым. Запустите dir
и вы не увидите обновленный размер. Или напишите файл с помощью Блокнота (который закрывает файл в конце), и сразу же новый размер файла отобразится в dir
или проводнике.
Почему F5 помогает обновить размер файла? Explorer вызывает GetNamedSecurityInfo, который внутренне открывает файл и закрывает его (вы можете проверить это в SysInternals Process Monitor). Если я вызываю GetNamedSecurityInfo
в моей собственной программе, а затем вызываю FindFirstFileEx
я сразу вижу новый размер файла. Таким образом, наблюдаемое поведение в точности соответствует теории.
Но почему вы не видите новый размер файла сразу в проводнике? Кажется, что Explorer сначала вызывает FindFirstFileEx
а затем GetNamedSecurityInfo
. Таким образом, Explorer получает старый размер и затем запускает обновление записи каталога. Если вы запустите dir
в cmd.exe, вы увидите, что запись в каталоге теперь имеет новый размер файла. Это только, что Explorer еще не знает это. Проводнику требуется второй F5, чтобы получить последний размер, а затем снова вызвать обновление.
С точки зрения разработчиков приложений, я бы не стал рассматривать это как ошибку Explorer - это особый случай для одной из поддерживаемых файловых систем, и приложение должно абстрагироваться от файловых систем. Но так как Explorer является частью Windows, я склонен думать, что Microsoft могла бы сделать лучше и изменить порядок вызовов функций, чтобы улучшить взаимодействие с пользователем.
Кстати, спасибо за этот очень интересный вопрос! Мне нравится изучать такие NTFS interna.