Размер файла - штука вовсе не однозначная. Давайте посмотрим, как он может меняться...

Прежде всего скажем, что речь здесь пойдет о файловых системах FAT и NTFS, как наиболее распространенных, и ничего не будет сказано о файловых системах, используемых в не-Windows системах, поскольку такие системы лежат вне сферы интересов автора. А теперь – к делу.

Казалось бы, какая неоднозначность может быть, если говорить о размере файла. Сколько в него данных записали, такой и размер (или длина). Сколько в нем есть байтов от начала до конца (и это число записано в файловой системе в качестве размера файла), такой и размер, не так ли? Как говорил Шельменко-денщик, так то оно так, да только трошечки не так.



Проведите эксперимент. Возьмите любой исполняемый файл  и выполните его копирование командой
copy что-то.exe что-то-другое.exe
 

Если вы раньше с этим сталкивались, то уже знаете, что результирующий файл получится намного короче исходного и не будет копией. Причина простая: программа copy, запущенная без параметра  /b,  копирует файл до тех пор, пока не встретит байт с кодом 27h, этот символ называется «конец файла».

Итак, у нас уже есть два разных признака конца файла – по числу, записанному в файловой системе, и по специальному байту в теле файла. Правда, стоит отметить, что второй признак остался с тех времен, когда файлы были преимущественно текстовыми и сейчас практически не применяется.

В файловых системах, использующих кластеры, а FAT и NTFS относятся именно к таким ФС, есть еще третий размер – размер файла на диске, то есть суммарный размер кластеров, отведенных этому файлу. В файловых системах FAT этот размер больше размера собственно файла или равен ему. Разница между размерами, если она есть, – так называемый хвост файла – это напрасно пропадающее место на диске, плата за размещение файлов по кластерам, а не встык друг за другом, хотя файловые системы с таким размещением файлов тоже существуют.

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

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

Максимальный размер такого файла зависит от размера записи и составляет примерно 600 байтов для записи мелкого размера (1 Кб) и 3600 – для записи крупного размера (4 Кб). Следует, впрочем, отметить, что до недавнего времени Windows показывала размер такого файла на диске равным одному кластеру, хотя фактически ни одного кластера файлу не выделено.

Если файл сжат, то его размер на диске может быть заметно меньше собственно длины файла (количества данных в нем).

Дополнительно усложняют картину так называемые разреженные файлы. В них полезные данные содержаться только в определенных участках файла, а остальная часть файла не используется вовсе. Возьмем в качестве примера файл журнала изменений \$Extend\$UsnJrnl, имеющийся почти на каждом компьютере (не пытайтесь увидеть его в проводнике или других диспетчерах файлов, не получится).

Он может иметь длину несколько гигабайт, но значимых данных содержит при этом обычно только 32 мегабайта в самом конце. А остальная часть вообще никаких данных не содержит, места на диске не занимает, и при попытке прочитать данные из этой части система выдаст набор нулей, даже не обращаясь к диску.
Если у читателя возникнет желание поэкспериментировать с разреженными файлами, такой файл можно создать с помощью команды fsutil sparse. А на досуге можно обдумать, какова же настоящая длина файла, если система записала в соответствующую графу число 4 Гб, а реальных данных в файле только 32 Мб и на диске он занимает тоже 32 Мб.

И, наконец, расскажем еще об одной длине: длине действительных данных (valid data). Эта длина и устанавливающие ее функции представляют интерес почти исключительно для программистов, тем не менее изредка с ней могут столкнуться и обычные пользователи.

В файловых системах FAT такого понятия не существует, и функции, которые используют эту величину, записывают в тело файла на соответствующих местах нули. В NTFS эта длина является характеристикой файла.

Попробуем пояснить, о чем идет речь, на примере. Возьмите флешку (флешка используется для наглядности, поскольку она медленнее жесткого диска работает с большими объемами данных) размером от гигабайта, отформатированную в FAT32, и создайте на ней большой файл командой
fsutil file createnew k:\пробный.txt 900000000

Если буква, присвоенная флешке, отличается от К, то исправьте команду соответствующим образом.
Вы увидите, что процедура создания файла окажется довольно продолжительной, полминуты или даже больше (хотя сообщение «файл создан» появится сразу же, появления приглашения командной строки придется подождать). Это совсем не удивительно, ведь в описании команды (https://technet.microsoft.com/en-us/library/cc788058.aspx) сказано, что создаваемый файл состоит из нулей. А файл у нас получился 858 мегабайт, так что его запись и должна занять не такое уж малое время.

Теперь отформатируйте флешку в NTFS, для чистоты эксперимента лучше взять ту же самую, и повторите создание файла. На этот раз операция пройдет практически моментально. Записывать нули в тело файла уже не надо, достаточно распределить место под файл и установить для него длину действительных данных равной нулю. В теле файла останется «мусор», который был записан в этих секторах, но при чтении данных обращения к этим данным не произойдет – обнаружив, что длина действительных данных равна нулю, все, что дальше этого нуля, система читать не станет – ведь эти данные недействительны. Их можно сделать действительными, если изменить значение длины действительных данных.

Рассмотрим это на примере. Создайте новый файл на одном из рабочих дисков, отформатированном в NTFS. Сотни мегабайт совершенно не обязательны, десятка-другого килобайт будет вполне достаточно:
fsutil file createnew C:\пробный.txt 10000

Теперь откройте его с помощью любого просмотрщика файлов, например FAR.

Как видим, в файле действительно нули. Но если посмотреть на этот файл с помощью какого-либо редактора дисков, обращающегося к секторам напрямую, например dmde, то картина будет другая.

Если мы откроем том С как логическое устройство и посмотрим на содержимое файла, то увидим те же самые нули.

Но если открыть диск как физическое устройство, то в том же самом секторе (обратите внимание на номера LBA – разница в 63 возникла из-за того, что начало раздела сдвинуто относительно начала диска) увидим данные, которые ранее были записаны в какой-то позже удаленный файл.

И если мы увеличим длину действительных данных, то увидим эти данные в файле. Установим эту длину равной 300 байт:

fsutil file setvaliddata C:\пробный.txt 300

Обратите внимание что параметр в этой команде нельзя задавать произвольно, но должен быть не меньше текущего значения длины действительных данных и не больше размера файла. Уменьшить длину действительных данных этой командой нельзя.

Теперь снова посмотри на содержимое файла. Заметьте, что никаких данных мы в него не записывали!

Чисто случайно получилось, что в этом файле довольно много осмысленного текста, что делает картину более наглядной. 300 десятичных байтов – это 12c шестнадцатиричных, и как раз на этом байте обрывается текст и начинаются нули. Если сдвинуть границу действительных данных еще дальше, то «проявятся» и следующие строки.

Подведем итоги


Имеется две физических длины файла – это размер файла, записанный в файловой системе и место, занимаемое на диске. Также имеется две логических длины файла – это признак конца файла (байт EOF – 27h) и длина действительных данных. Как составную часть логической длины можно рассматривать и пустые области в разреженных файлах – вспомните \$Extend\$UsnJrnl, где большой массив отсутствующих данных завершается тридцатью двумя мегабайтами действительных.

Итак, обычно, когда говорят о длине файла, имеют в виду число, хранящееся в файловой системе. Но, как видите, возможны варианты!

Вы можете выразить свою благодарность автору и стимулировать его на дальнейшее творчество, переведя небольшую сумму  с помощью пейпала http://paypal.me/Leyko, переводом на карту сбербанка 6390 0238 9021 6390 91 или через яндекс-деньги. 

0 0 21835 14
Автор Игорь Лейко Рейтинг +0.06 Сила 0.16
Блог Программы, ПО, сайты 75 87 RSS

14 комментариев

mcto
Чего-то я не понял смысла написания этой статьи.
Игорь Лейко
Нет, не забыл. Это отдельная тема. Тем более что потоки в общий объем файла не считаются.
Лев Серебряков
Ну, в том-то и дело, что не считаются. А место на FS занимают. Делаем файл в килобайт и 20 гигабайт недефолтного потока рядом. Удаляем такой файл — 20 гигов места освободилось. Если не знать про потоки, то хорошая задачка — что случилось?
Последний раз редактировалось
ИС
27h это апостроф, а конец текстового файла – 26 без всякого h. Чтобы понять смысл статьи, надо дочитать ее до конца. Он раскроется в последнем абзаце.
Игорь Лейко
Спасибо за уточнение. Склероз таки подвел. :(
Wapr Old
Windows показывала размер такого файла на диске равным одному кластеру, хотя фактически ни одного кластера файлу не выделено.
Неужто в астрале хранится? Или может надо стоит сказать, что windows заранее зарезервировала кластеры под кучу таких файлов? И также упомянуть, что произойдёт, когда это место закончится.
Игорь Лейко
В статье написано, где хранится. Не надо ничего похожего говорить, потому что такое утверждение было бы ложным.
Vladimir Lyagera
Одного не понял, у меня
copy что-то.exe что-то-другое.exeдает полную копию файла. Без ключа /b
Да и вообще, никогда в командной строке при копировании /b не задавал — всегда копировалось нормально...

Про validdata интересно, только непонятно — зачем???
Игорь Лейко
Значит, поведение по умолчанию изменилось. Давно ей не пользовался, поэтому не уследил за изменением. Надо будет проверить, в какой версии оно произошло.
Vladimir Lyagera
Походу, очень давно изменилось. :-)
MS-DOS 6.22 и новее копируют без /b нормально.
Более ранними не пользовался, аж интересно стало…
Alx_n
«Жениться вам, барин, пора».
220376291@vkontakte
ni dam denig :D
Последний раз редактировалось

Добавить комментарий