Как файлы копируются на низком уровне?

У меня небольшой вопрос:

Например, я использую метод System.IO.File.Copy() из .NET Framework. Этот метод является управляемой оболочкой для функции CopyFile() из WinAPI. Но как работает функция CopyFile? Он взаимодействует с прошивкой HDD или может какие-то другие операции выполняются через Ассемблер или еще что-то...

Как это выглядит от высшего уровня к низшему?


person Laserson    schedule 25.12.2009    source источник


Ответы (3)


Лучше начать снизу и продвигаться вверх.

Дисководы организованы на самом низком уровне в виде набора секторов, дорожек и головок. Секторы — это сегменты дорожки, а дорожки — это области на самих дисках, представленные положением головок при вращении пластин под ними, а головка — это фактический элемент, который считывает данные с пластины.

Поскольку дорожки измеряются на основе расстояния, на котором головка находится от центра диска, вы можете видеть, как ближе к центру диска «длина» дорожки короче, чем у внешнего края диска.

Секторы — это части дорожки, обычно фиксированной длины. Таким образом, внутренняя дорожка будет содержать меньше секторов, чем внешняя дорожка.

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

Электроника дисковода и драйверы диска совместно пытаются представить диск в виде последовательного ряда блоков фиксированной длины.

Итак, вы можете видеть, что если у вас есть диск объемом 10 МБ и вы используете дисковые блоки размером 512 байт, то этот диск будет иметь емкость 20 480 «блоков».

Эта блочная организация является фундаментом, на котором строится все остальное. Когда у вас есть эта возможность, вы можете через драйвер диска и контроллер диска указать диску перейти к определенному блоку на диске и прочитать/записать этот блок с новыми данными.

Файловая система организует эту кучу блоков в свою собственную структуру. ФС должна отслеживать, какие блоки используются и какими файлами.

У большинства файловых систем есть фиксированное местоположение, «откуда они начинаются», то есть какое-то место, куда при запуске они могут отправиться, чтобы попытаться узнать информацию о структуре диска.

Рассмотрим грубую файловую систему, которая не имеет каталогов и поддерживает файлы с 8-буквенными именами и 3-буквенным расширением, плюс 1 байт информации о состоянии и 2 байта для номера блока, в котором файл начинается на диске. Также можно предположить, что в системе установлено жесткое ограничение в 1024 файла. Наконец, он должен знать, какие блоки на диске используются. Для этого он будет использовать 1 бит на блок.

Эта информация обычно называется «метаданные файловой системы». Когда диск «форматируется», в настоящее время это просто вопрос записи новых метаданных файловой системы. В старые времена это было вопросом фактического написания меток секторов и другой информации на пустых магнитных носителях (широко известный как «формат низкого уровня»). Сегодня большинство накопителей уже имеют низкоуровневый формат.

В нашем грубом примере мы должны выделить место для каталога и место для «Оглавления», данных, которые говорят, какие блоки используются.

Мы также скажем, что файловая система должна начинаться с 16-го блока, чтобы ОС могла использовать первые 16 блоков, скажем, для «загрузочного сектора».

Итак, в блоке 16 нам нужно хранить 14 байт (каждая запись файла) * 1024 (количество файлов) = 12К. Разделите это на 512 (размер блока) и получите 24 блока. Для нашего 10-мегабайтного диска это 20 480 блоков. 20 480/8 (8 бит/байт) — это 2 560 байт/512 = 5 блоков.

Из 20 480 блоков, доступных на диске, метаданные файловой системы составляют 29 блоков. Добавьте 16 для ОС, что 45 блоков из 20 480, оставив 20 435 «свободных блоков».

Наконец, каждый из блоков данных резервирует последние 2 байта, чтобы указать на следующий блок в файле.

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

Код файловой системы скрывает детали указателей в конце и просто загружает блоки в память для использования программой. Если программа выполнит чтение (буфер, 10000), вы увидите, как это приведет к чтению нескольких блоков данных с диска до тех пор, пока буфер не будет заполнен или не будет достигнут конец файла.

Чтобы записать файл, система должна сначала найти свободное место в каталоге. Получив это, он находит свободный блок в растровом изображении TOC. Наконец, он берет данные, записывает запись каталога, устанавливает свой первый блок в доступный блок из растрового изображения, переключает бит на растровом изображении, а затем берет данные и записывает их в правильный блок. Система будет буферизовать эту информацию, так что в идеале ей нужно будет записывать блоки только один раз, когда они будут заполнены.

Когда он записывает блоки, он продолжает потреблять биты из TOC и по мере продвижения связывает блоки вместе.

Кроме того, «копирование файла» — это простой процесс, когда система использует код файловой системы и драйверы дисков. Копия файла просто считывает буфер, заполняет его, записывает буфер.

Файловая система должна поддерживать все метаданные, отслеживать, где вы читаете из файла или где вы пишете. Например, если вы читаете только 100 байт из файла, очевидно, что системе потребуется прочитать весь блок данных размером 512 байт, а затем «узнать», что он находится в байте 101, когда вы попытаетесь прочитать еще 100 байтов из файла.

Кроме того, я надеюсь, что это очевидно, это очень, очень грубая структура файловой системы с множеством проблем.

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

person Will Hartung    schedule 26.12.2009

Это вопрос, требующий или очень длинный ответ, но я пытаюсь сделать его кратким.

По сути, .NET Framework оборачивает некоторые «собственные» вызовы, то есть вызовы, которые обрабатываются в библиотеках более низкого уровня. Эти низкоуровневые вызовы часто оборачивают в логику буфера, чтобы скрыть от вас сложные вещи, такие как синхронизация содержимого файла.

Ниже находится нативный уровень, взаимодействующий с ядром ОС. Ядро, ядро ​​любой операционной системы, переводит ваши высокоуровневые инструкции в то, что может понять ваше оборудование. Windows и Linux, например, используют уровень аппаратной абстракции, систему, которая скрывает конкретные детали оборудования за общим интерфейсом. В таком случае написание драйвера для конкретного устройства — это всего лишь задача реализации всех методов, которые должно предоставить это устройство.

Прежде чем что-либо будет вызвано на вашем оборудовании, в дело вступает файловая система, а сама файловая система также много буферизует и кэширует, но опять же прозрачно, так что вы даже этого не замечаете. Последним элементом в очереди вызовов является само устройство, и опять же, большинство устройств соответствуют какому-либо стандарту (например, SATA или IDE) и, таким образом, могут быть подключены аналогичным образом.

Надеюсь, это поможет :-)

person moritz    schedule 25.12.2009

Платформа .NET вызывает API Windows.

Windows API имеет функции для управления файлами в различных файловых системах.

Тогда это зависит от рассматриваемой файловой системы. Помните, что это не обязательно «нормальная» файловая система на жестком диске; Это может быть даже расширение оболочки, которое просто эмулирует диск и хранит данные в вашей учетной записи gmail или что-то еще. Дело в том, что одни и те же функции манипулирования файлами в Windows API используются в качестве абстракции над многими возможными нижними уровнями данных.

Так что ответ действительно зависит от того, какая файловая система вас интересует.

person Assaf Lavie    schedule 25.12.2009