В большинстве компьютерных систем предусмотрены устройства внешней (вторичной) памяти большой емкости, на которых можно хранить огромные объемы данных. Чтобы повысить эффективность использования этих устройств, был разработан ряд специфичных для них структур данных и алгоритмов.
Ранее прикладная программа сама решала проблемы именования данных и их структуризации во внешней памяти. Это затрудняло поддержание на внешнем носителе нескольких архивов долговременно хранящейся информации. В настоящее время используются централизованные
Файловая система - это часть операционной системы, назначение которой состоит в том, чтобы организовать эффективную работу с данными, хранящимися во внешней памяти, и обеспечить пользователю удобный интерфейс при работе с такими данными. С точки зрения пользователя, файл - единица внешней памяти, то есть данные, записанные на диск, должны быть в составе какого-нибудь файла. В ОС Windows поддерживается представление о файле как о неструктурированной последовательности байтов. Прикладная программа имеет возможность считывать эти байты в произвольном порядке. Обычно хранение файла организовано на устройстве прямого доступа в виде набора блоков фиксированного размера. Основная задача подсистемы управления файлами - связать символьное имя файла с блоками диска, которые содержат данные файла.
В данном курсе основное внимание будет сосредоточено на NTFS - базовой файловой системе ОС Windows. Вначале будет рассмотрен интерфейс, то есть вопросы структуры, именования, защиты файлов; операции над файлами; организация файлового архива при помощи каталогов. В следующей лекции будут проанализированы проблемы реализации файловой системы, способы выделения дискового пространства и связывания его с именем файла, обеспечение производительной работы файловой системы и ряд других вопросов, интересующих разработчиков системы.
Предметное изучение интерфейса файловой системы лучше начать с описания простейшей программы чтения и записи в файл, которая использует основные ( CreateFile, ) операции для работы с файлами.
Следующая программа открывает существующий файл, считывает из него 10 байтов с начала файла и записывает в файл фразу "some bytes to write", начиная с 11-й позиции. Для буфера выделяется память из стандартной кучи процесса (см. лекцию 9).
Варианты использования различных комбинаций параметров функций CreateFile, и WriteFile подробно описаны в MSDN. К счастью, большинство из них имеет вполне отчетливую мнемонику и не вызывает затруднений, см., например, текст программы. Назначение некоторых параметров будет уточняться в последующих разделах. Важным является то, что в случае успешного завершения функции CreateFile в системе создается объект "открытый файл", который управляет операциями, связанными с файлом, контролирует
После приобретения некоторого опыта работы с основными функциями ввода-вывода перейдем к рассмотрению наиболее важных аспектов пользовательского интерфейса файловой системы.
Имя любого абстрактного объекта - одна из его важнейших характеристик. Когда процесс создает файл, он дает ему имя. После завершения процесса файл продолжает существовать и через свое имя может быть доступен другим процессам. Для создания файла и присвоения ему имени в ОС Windows используют Win32-функцию CreateFile.
Имя файла задается параметром lpFileName - указателем на строку, заканчивающуюся нулем. В соответствии со стандартом POSIX ОС Windows оперирует длинными (до 255 символов) именами. Если быть более точным, максимальная длина полного имени файла при создании файла равна MAX_PATH. Значение MAX_PATH определено как 260, но система позволяет преодолеть это ограничение и использовать имена файлов длиной до 32000 символов в формате Unicode.
В системе заложена возможность различать большие и маленькие буквы в названии файла (значение FILE_FLAG_POSIX_SEMANTICS параметра dwFlagsAndAttributes функции CreateFile ). Однако пользоваться этим флагом не рекомендуется, поскольку многие приложения и поисковые программы эту возможность не учитывают, поэтому для них данный файл может быть недоступен.
ОС Windows поддерживает типизацию файлов. Основные типы файлов: регулярные (обычные) файлы и директории (справочники, каталоги).
Обычные файлы содержат пользовательскую информацию. Директории - системные файлы, поддерживающие структуру файловой системы. В каталоге содержится перечень входящих в него файлов и устанавливается соответствие между файлами и их разнообразными атрибутами. Директории будут рассмотрены ниже.
Считается, что пользователь представляет файл в виде линейной последовательности байтов (притом, что реальное хранение файла во внешней памяти организовано совсем по-другому). Такое представление оказалось очень удобным и позволяет использовать абстракцию файла для организации CreateFile. В этом случае параметр lpFileName определяет не только имя, но и тип объекта. Эти объекты рассматриваются в других разделах данного курса.
Далее речь пойдет, главным образом, об обычных файлах.
Прикладные программы, работающие с файлами, как правило, распознают тип файла по его имени в соответствии с общепринятыми соглашениями. Например, файлы с расширениями .c, .pas - текстовые файлы, хранящие программы на Си и Паскале, а файлы с расширениями .exe - исполняемые, и т.д. Связь имен с обрабатывающими программами реализована в реестре.
Кроме имени ОС часто связывает с каждым файлом и другую информацию, например, дату модификации, размер и т.д. Эти другие характеристики файлов называются атрибутами. В ОС Windows понятие атрибута трактуется шире. Считается, что файл - это не просто последовательность байтов, а совокупность атрибутов, и данные файла являются лишь одним из атрибутов - так называемый неименованный поток данных. Есть и другие (именованные) потоки данных, которые нужно указывать через двоеточие. Именованные потоки данных можно "увидеть" при помощи таких команд, как echo и more. Например, если выполнить следующие интерактивные команды
>Echo содержимое файла > MyFile:Stream1 >more < MyFile:Stream1
то на экране должны появиться слова "содержимое файла".
Вот далеко не полный перечень атрибутов файла в NTFS:
Имя файла тоже является одним из атрибутов. Атрибуты хранятся в виде пары: <наименование атрибута, значение атрибута> в записи о файле в главной файловой таблице
Часть атрибутов файла можно определить при его создании (через параметры функции CreateFile ) или позже при помощи SetFileAttributes, сославшись на файл по имени. Можно также специфицировать атрибуты защиты файла при помощи параметра lpSecurityAttributes. Если же значение lpSecurityAttributes равно NULL, то соответствующие атрибуты файла будут содержать параметры так называемой стандартной защиты (подробнее об этом часть V).
В качестве примера рассмотрим простую программу, которая извлекает атрибуты указанного файла с помощью функции GetFileAttributes.
#include <windows.h>
#include <stdio.h>
void main(void) {
DWORD dwFileAttributes;
dwFileAttributes = GetFileAttributes("tmp");
if(dwFileAttributes == -1) printf(" GetFileAttributes Error\n");
if (dwFileAttributes FILE_ATTRIBUTE_NORMAL)
printf("This file is normal\n");
if (dwFileAttributes FILE_ATTRIBUTE_DIRECTORY)
printf("This file is directory\n");
if (dwFileAttributes FILE_ATTRIBUTE_REPARSE_POINT)
printf("This file is reparse point\n");
}
С помощью данной программы можно установить характер файла tmp (каталог, обычный файл или точка повторного разбора).
Рекомендуется самостоятельно написать программу, где применяется функция SetFileAttributes, например, устанавливается флаг "FILE_ATTRIBUTE_READONLY" для атрибутов указанного файла.
Для хранения файлов обычно используются устройства прямого доступа (диски), которые позволяют обращаться напрямую к любому блоку диска. Это обеспечивает произвольный доступ к байтам файла, поскольку номер блока однозначно определяется текущей позицией внутри файла. Таким образом, файловая подсистема ОС Windows имеет дело с файлами, байты которых могут быть считаны в любом порядке. Такие файлы называется файлами прямого доступа. Непосредственное обращение к любому байту внутри файла предполагает наличие операции позиционирования, целью которой является задание текущей позиции для считывания или записи. Поскольку файл может иметь большой размер,
Известно, что операции ввода-вывода являются относительно медленными. Чтобы избавить центральный процессор от ожидания выполнения операции ввода-вывода, в системе организована обработка асинхронных событий, в частности, прерываний, для оповещения процессора о завершении операции ввода-вывода. Однако если на уровне ОС операции ввода-вывода являются асинхронными, на уровне пользовательской программы они еще долго оставались синхронными и блокирующими. В результате процесс, инициировавший операцию ввода-вывода, переходил в состояние ожидания. Примером и WriteFile, не могут выполняться до тех пор, пока операция ввода-вывода не завершена.
Важным достижением разработчиков ОС Windows является предоставление пользователю возможности осуществлять асинхронные операции ввода-вывода наряду с традиционными синхронными. При этом процесс, инициирующий операцию ввода-вывода, не ждет ее окончания, а продолжает вычисления. В распоряжении пользователя имеются средства проконтролировать завершение операции ввода-вывода впоследствии. Асинхронный ввод-вывод позволяет создавать более эффективные приложения за счет планомерного использования ресурсов и в первую очередь - центрального процессора.
Для того чтобы воспользоваться возможностями CreateFile с установленным флагом FILE_FLAG_OVERLAPPED, входящим в состав параметра dwFlagsAndAttrs, и указать: с какой позиции осуществлять чтение (запись), сколько байтов считать (записать) и какое событие должно сигнализировать о том, что операция завершена. Для этого необходимо проинициализировать поля структуры в параметре pOverlapped функций или WriteFile.
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
Параметр Internal используется для хранения кода возможной ошибки, а параметр InternalHigh - для хранения числа переданных байт. Вначале разработчики Windows не планировали делать их общедоступными - отсюда и такие не содержащие мнемоники имена. Offset и OffsetHigh - соответственно младшие и старшие разряды текущей позиции файла. hEvent специфицирует событие, сигнализирующее окончание операции ввода-вывода.
#include <windows.h>
#include <stdio.h>
void main(void) {
HANDLE hFile, hHeap;
int iRet = 0;
void *pMem;
long BufSize = 512;
DWORD iRead = 10;
char * String;
OVERLAPPED ov = {0};
hFile = CreateFile("MYFILE.TXT", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE) printf("Could not open file.");
hHeap = GetProcessHeap();
pMem = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, BufSize);
String = (char *)pMem;
ov.Offset = 3;
ReadFile(hFile, pMem, iRead, iRead, ov);
WaitForSingleObject(hFile, INFINITE);
printf("Read %d bytes: %s\n", iRead, String);
printf("Read %d bytes: %s\n", ov.InternalHigh, String);
HeapFree(hHeap, 0, pMem);
CloseHandle(hFile);
}
В программе проинициализирована структура и передана функции в качестве параметра. Чтение начинается с 3-й позиции. Узнать число прочитанных байтов можно из ov.InternalHigh - компонента структуры . Обратите внимание, что значение переменной iRead, которая должна содержать количество прочтенных байтов, равно 0, так как функция вернула управление до завершения операции ввода-вывода. Обычно это справедливо для первого запуска программы. При последующих запусках, поскольку данные файла находятся в кэше, запрос может успеть выполниться синхронно и значение iRead уже будет равно числу прочитанных байтов.
В программе выбран простейший вариант синхронизации - сигнализация от объекта, управляющего устройством, в данном случае - открытого файла (функции , и .
Результат работы данной программы практически ничем не отличается от обычного синхронного чтения и в таком виде большого смысла не имеет. Однако если между операциями чтения и синхронизации заставить программу выполнять какую-либо полезную работу, то ресурсы компьютера будут использоваться более эффективно, т.к. процессор и устройство ввода будут работать параллельно.
Итак, в случае асинхронного доступа позиция, начиная с которой будет осуществляться операция чтения-записи, содержится в запросе на операцию (параметр структуры ). Рассмотрим теперь особенности позиционирования при обычном CreateFile.
Текущая позиция смещается на конец считанной или записанной последовательности байтов в результате операций чтения или записи. Кроме того, можно установить текущую позицию при помощи Win32-функции SetFilePointer. Например, операция
SetFilePointer(hFile,17 , NULL, FILE_BEGIN);
устанавливает
Тот факт, что
С другой стороны, получив описатель открытого файла, можно его продублировать при помощи Win32- функции DuplicateHandle. В этом случае два разных описателя будут ссылаться на один и тот же объект с одним и тем же
В качестве самостоятельного упражнения рекомендуется написать программу, которая проиллюстрировала бы перемещение
Файловая система на диске представляет собой иерархическую структуру, которая организована за счет наличия специальных файлов - каталогов (директорий). Каталоги имеют один и тот же внутренний табличный формат (рис 11.1) и обеспечивают многоуровневое наименование файлов.
(рис 11.1) Формат каталогаЗапись в каталоге о файле содержит имя файла, некоторые атрибуты (длина имени, временная метка) и ссылку на запись в главной файловой таблице, необходимую для нахождения блоков файла.
В итоге, файловая система на диске образует хорошо известную древовидную структуру (рис 11.2), где нет циклов (если отсутствуют ссылки и точки монтирования) и путь от корня к файлу однозначно определяет файл.
(рис 11.2) Иерархическая древовидная структура файловой системыПоскольку имена файлов, находящихся в разных каталогах, могут совпадать, уникальность имени файла на диске обеспечивается добавлением к собственному имени файла списка \Games\Heroes\heroes.exe. Таким образом, использование древовидных каталогов минимизирует сложность назначения уникальных имен.
Чтобы иметь возможность работать с собственными именами файлов, используют концепцию рабочей или текущей директории, которая обычно входит в состав атрибутов процесса, работающего с данным файлом. Тогда на файлы в такой директории можно ссылаться только по имени. Кроме того ОС поддерживает обозначения '.' - для текущей директории и '..' - для родительской.
В системе поддерживается большое количество Win32-функций для манипуляции с каталогами, их полный перечень имеется в MSDN. В частности, для создания каталогов можно использовать функцию CreateDirectory. Вновь созданная директория включает записи с именами '.' и '..', однако считается пустой. Для работы с текущим каталогом можно использовать функции GetCurrentDirectory и SetCurrentDirectory. Работа с этими функциями проста и не нуждается в специальных разъяснениях.
#include <windows.h>
#include <stdio.h>
void main(void) {
int iRet = 0;
char Buf[512];
int bufSize = 512;
iRet = GetCurrentDirectory(bufSize, Buf);
printf("iRet = %d, current directory %s\n", iRet, Buf);
iRet = CreateDirectory("f:\\tmp1", NULL);
if(!iRet) printf("CreateDirectory error\n");
iRet = SetCurrentDirectory("f:\\tmp1");
if(!iRet) printf("SetCurrentDirectory error\n");
iRet = GetCurrentDirectory(bufSize, Buf);
printf("iRet = %d, current directory %s\n", iRet, Buf);
}
Приведенная программа выводит на экран название текущего каталога, создает каталог "tmp1" на диске "F:" , делает его текущим и выводит на экран его название в качестве текущего каталога.
На основании предыдущей программы рекомендуется написать программу, которая создает каталог в родительской директории и копирует в него какой-либо файл с помощью функции CopyFile.
В ОС Windows принято разбивать диски на логические диски (это низкоуровневая операция), иногда называемые разделами (partitions). Бывает, что, наоборот, объединяют несколько физических дисков в один логический диск. На разделе или логическом диске хранится корневой каталог данного и все вложенные в него каталоги, а задание пути к файлу начинается с имени логического диска или "буквы" диска.
Имена логических дисков хранятся в каталоге "\??" пространства имен объектов, которые и осуществляют связь логического диска и реального устройства. Указав букву диска, прикладная программа получает доступ к его файловой системе.
По аналогии с Unix операционная система Windows позволяет пользователю создать точку монтирования - связать какой-либо пустой каталог с каталогом логического диска. В случае успешного завершения операции содержимое этих каталогов будет соответствовать друг другу.
Чтобы смонтировать логический диск, нужно выполнить команду
>mountvol [<диск>:]<путь> <имя тома>
Здесь параметр <путь> задает имя пустого каталога, а имя тома задается в виде \\?\Volume{код_GUID}\, где GUID - глобальный уникальный идентификатор.
Например
>mountvol f:\tmp1 \\?\Volume\{2eca078d-5cbc-43d3-aff8-7e8511f60d0e}\}
Имена глобальных уникальных идентификаторов и их связь с буквами диска можно узнать, дав команду
>mountvol /?
Монтирование также можно выполнить с помощью панели управления дисками системной панели управления, если выбрать пункт "изменение буквы диска и пути диска".
Наконец, смонтировать диск можно программным образом с помощью Win32-функции SetVolumeMountPoint.
Защита файлов от несанкционированного использования основана на том, что доступ к файлу зависит от идентификатора пользователя. Система контроля доступа предполагает наличие у каждого файла дескриптора защиты, содержащего список прав доступа, который формирует владелец файла и который входит в состав атрибута SecurityAttributes файла. Каждый процесс имеет маркер доступа, который содержит права пользователя, запустившего процесс.
Список прав доступа содержит набор идентификаторов пользователей, имеющих право на доступ к файлу, и их права в отношении этого файла. Маркер доступа содержит идентификатор владельца процесса. Система контроля доступа в момент открытия файла проверяет соответствие прав владельца процесса с теми, которые перечислены в списке прав доступа к файлу. В результате доступ может быть разрешен или отклонен.
Во время выполнения операций чтения, записи и других, проверок прав доступа уже не производится.
В новых версиях NTFS дескрипторы защиты всех файлов хранятся в отдельном файле метаданных \$Secure, который описывается 9-й записью главной файловой таблицы тома
Более подробно защита от несанкционированного доступа описана в части V данного курса.
Файл - единица внешней памяти, поэтому обычно данные, записанные на диск, находятся в составе какого-нибудь файла. Файловая система решает задачи именования и типизации файлов, организации доступа к файлам, защиты, поиска файлов и ряд других. В системе на каждом разделе диска поддерживается иерархическая система каталогов. Для эффективного доступа к файлам могут быть организованы
В большинстве компьютерных систем предусмотрены устройства внешней (вторичной) памяти большой емкости, на которых можно хранить огромные объемы данных. Чтобы повысить эффективность использования этих устройств, был разработан ряд специфичных для них структур данных и алгоритмов.
Ранее прикладная программа сама решала проблемы именования данных и их структуризации во внешней памяти. Это затрудняло поддержание на внешнем носителе нескольких архивов долговременно хранящейся информации. В настоящее время используются централизованные
Файловая система - это часть операционной системы, назначение которой состоит в том, чтобы организовать эффективную работу с данными, хранящимися во внешней памяти, и обеспечить пользователю удобный интерфейс при работе с такими данными. С точки зрения пользователя, файл - единица внешней памяти, то есть данные, записанные на диск, должны быть в составе какого-нибудь файла. В ОС Windows поддерживается представление о файле как о неструктурированной последовательности байтов. Прикладная программа имеет возможность считывать эти байты в произвольном порядке. Обычно хранение файла организовано на устройстве прямого доступа в виде набора блоков фиксированного размера. Основная задача подсистемы управления файлами - связать символьное имя файла с блоками диска, которые содержат данные файла.
В данном курсе основное внимание будет сосредоточено на NTFS - базовой файловой системе ОС Windows. Вначале будет рассмотрен интерфейс, то есть вопросы структуры, именования, защиты файлов; операции над файлами; организация файлового архива при помощи каталогов. В следующей лекции будут проанализированы проблемы реализации файловой системы, способы выделения дискового пространства и связывания его с именем файла, обеспечение производительной работы файловой системы и ряд других вопросов, интересующих разработчиков системы.
Предметное изучение интерфейса файловой системы лучше начать с описания простейшей программы чтения и записи в файл, которая использует основные ( CreateFile, ) операции для работы с файлами.
Следующая программа открывает существующий файл, считывает из него 10 байтов с начала файла и записывает в файл фразу "some bytes to write", начиная с 11-й позиции. Для буфера выделяется память из стандартной кучи процесса (см. лекцию 9).
Варианты использования различных комбинаций параметров функций CreateFile, и WriteFile подробно описаны в MSDN. К счастью, большинство из них имеет вполне отчетливую мнемонику и не вызывает затруднений, см., например, текст программы. Назначение некоторых параметров будет уточняться в последующих разделах. Важным является то, что в случае успешного завершения функции CreateFile в системе создается объект "открытый файл", который управляет операциями, связанными с файлом, контролирует
После приобретения некоторого опыта работы с основными функциями ввода-вывода перейдем к рассмотрению наиболее важных аспектов пользовательского интерфейса файловой системы.
Имя любого абстрактного объекта - одна из его важнейших характеристик. Когда процесс создает файл, он дает ему имя. После завершения процесса файл продолжает существовать и через свое имя может быть доступен другим процессам. Для создания файла и присвоения ему имени в ОС Windows используют Win32-функцию CreateFile.
Имя файла задается параметром lpFileName - указателем на строку, заканчивающуюся нулем. В соответствии со стандартом POSIX ОС Windows оперирует длинными (до 255 символов) именами. Если быть более точным, максимальная длина полного имени файла при создании файла равна MAX_PATH. Значение MAX_PATH определено как 260, но система позволяет преодолеть это ограничение и использовать имена файлов длиной до 32000 символов в формате Unicode.
В системе заложена возможность различать большие и маленькие буквы в названии файла (значение FILE_FLAG_POSIX_SEMANTICS параметра dwFlagsAndAttributes функции CreateFile ). Однако пользоваться этим флагом не рекомендуется, поскольку многие приложения и поисковые программы эту возможность не учитывают, поэтому для них данный файл может быть недоступен.
ОС Windows поддерживает типизацию файлов. Основные типы файлов: регулярные (обычные) файлы и директории (справочники, каталоги).
Обычные файлы содержат пользовательскую информацию. Директории - системные файлы, поддерживающие структуру файловой системы. В каталоге содержится перечень входящих в него файлов и устанавливается соответствие между файлами и их разнообразными атрибутами. Директории будут рассмотрены ниже.
Считается, что пользователь представляет файл в виде линейной последовательности байтов (притом, что реальное хранение файла во внешней памяти организовано совсем по-другому). Такое представление оказалось очень удобным и позволяет использовать абстракцию файла для организации CreateFile. В этом случае параметр lpFileName определяет не только имя, но и тип объекта. Эти объекты рассматриваются в других разделах данного курса.
Далее речь пойдет, главным образом, об обычных файлах.
Прикладные программы, работающие с файлами, как правило, распознают тип файла по его имени в соответствии с общепринятыми соглашениями. Например, файлы с расширениями .c, .pas - текстовые файлы, хранящие программы на Си и Паскале, а файлы с расширениями .exe - исполняемые, и т.д. Связь имен с обрабатывающими программами реализована в реестре.
Кроме имени ОС часто связывает с каждым файлом и другую информацию, например, дату модификации, размер и т.д. Эти другие характеристики файлов называются атрибутами. В ОС Windows понятие атрибута трактуется шире. Считается, что файл - это не просто последовательность байтов, а совокупность атрибутов, и данные файла являются лишь одним из атрибутов - так называемый неименованный поток данных. Есть и другие (именованные) потоки данных, которые нужно указывать через двоеточие. Именованные потоки данных можно "увидеть" при помощи таких команд, как echo и more. Например, если выполнить следующие интерактивные команды
>Echo содержимое файла > MyFile:Stream1 >more < MyFile:Stream1
то на экране должны появиться слова "содержимое файла".
Вот далеко не полный перечень атрибутов файла в NTFS:
Имя файла тоже является одним из атрибутов. Атрибуты хранятся в виде пары: <наименование атрибута, значение атрибута> в записи о файле в главной файловой таблице
Часть атрибутов файла можно определить при его создании (через параметры функции CreateFile ) или позже при помощи SetFileAttributes, сославшись на файл по имени. Можно также специфицировать атрибуты защиты файла при помощи параметра lpSecurityAttributes. Если же значение lpSecurityAttributes равно NULL, то соответствующие атрибуты файла будут содержать параметры так называемой стандартной защиты (подробнее об этом часть V).
В качестве примера рассмотрим простую программу, которая извлекает атрибуты указанного файла с помощью функции GetFileAttributes.
#include <windows.h>
#include <stdio.h>
void main(void) {
DWORD dwFileAttributes;
dwFileAttributes = GetFileAttributes("tmp");
if(dwFileAttributes == -1) printf(" GetFileAttributes Error\n");
if (dwFileAttributes FILE_ATTRIBUTE_NORMAL)
printf("This file is normal\n");
if (dwFileAttributes FILE_ATTRIBUTE_DIRECTORY)
printf("This file is directory\n");
if (dwFileAttributes FILE_ATTRIBUTE_REPARSE_POINT)
printf("This file is reparse point\n");
}
С помощью данной программы можно установить характер файла tmp (каталог, обычный файл или точка повторного разбора).
Рекомендуется самостоятельно написать программу, где применяется функция SetFileAttributes, например, устанавливается флаг "FILE_ATTRIBUTE_READONLY" для атрибутов указанного файла.
Для хранения файлов обычно используются устройства прямого доступа (диски), которые позволяют обращаться напрямую к любому блоку диска. Это обеспечивает произвольный доступ к байтам файла, поскольку номер блока однозначно определяется текущей позицией внутри файла. Таким образом, файловая подсистема ОС Windows имеет дело с файлами, байты которых могут быть считаны в любом порядке. Такие файлы называется файлами прямого доступа. Непосредственное обращение к любому байту внутри файла предполагает наличие операции позиционирования, целью которой является задание текущей позиции для считывания или записи. Поскольку файл может иметь большой размер,
Известно, что операции ввода-вывода являются относительно медленными. Чтобы избавить центральный процессор от ожидания выполнения операции ввода-вывода, в системе организована обработка асинхронных событий, в частности, прерываний, для оповещения процессора о завершении операции ввода-вывода. Однако если на уровне ОС операции ввода-вывода являются асинхронными, на уровне пользовательской программы они еще долго оставались синхронными и блокирующими. В результате процесс, инициировавший операцию ввода-вывода, переходил в состояние ожидания. Примером и WriteFile, не могут выполняться до тех пор, пока операция ввода-вывода не завершена.
Важным достижением разработчиков ОС Windows является предоставление пользователю возможности осуществлять асинхронные операции ввода-вывода наряду с традиционными синхронными. При этом процесс, инициирующий операцию ввода-вывода, не ждет ее окончания, а продолжает вычисления. В распоряжении пользователя имеются средства проконтролировать завершение операции ввода-вывода впоследствии. Асинхронный ввод-вывод позволяет создавать более эффективные приложения за счет планомерного использования ресурсов и в первую очередь - центрального процессора.
Для того чтобы воспользоваться возможностями CreateFile с установленным флагом FILE_FLAG_OVERLAPPED, входящим в состав параметра dwFlagsAndAttrs, и указать: с какой позиции осуществлять чтение (запись), сколько байтов считать (записать) и какое событие должно сигнализировать о том, что операция завершена. Для этого необходимо проинициализировать поля структуры в параметре pOverlapped функций или WriteFile.
typedef struct _OVERLAPPED {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
Параметр Internal используется для хранения кода возможной ошибки, а параметр InternalHigh - для хранения числа переданных байт. Вначале разработчики Windows не планировали делать их общедоступными - отсюда и такие не содержащие мнемоники имена. Offset и OffsetHigh - соответственно младшие и старшие разряды текущей позиции файла. hEvent специфицирует событие, сигнализирующее окончание операции ввода-вывода.
#include <windows.h>
#include <stdio.h>
void main(void) {
HANDLE hFile, hHeap;
int iRet = 0;
void *pMem;
long BufSize = 512;
DWORD iRead = 10;
char * String;
OVERLAPPED ov = {0};
hFile = CreateFile("MYFILE.TXT", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE) printf("Could not open file.");
hHeap = GetProcessHeap();
pMem = HeapAlloc(hHeap, HEAP_ZERO_MEMORY, BufSize);
String = (char *)pMem;
ov.Offset = 3;
ReadFile(hFile, pMem, iRead, iRead, ov);
WaitForSingleObject(hFile, INFINITE);
printf("Read %d bytes: %s\n", iRead, String);
printf("Read %d bytes: %s\n", ov.InternalHigh, String);
HeapFree(hHeap, 0, pMem);
CloseHandle(hFile);
}
В программе проинициализирована структура и передана функции в качестве параметра. Чтение начинается с 3-й позиции. Узнать число прочитанных байтов можно из ov.InternalHigh - компонента структуры . Обратите внимание, что значение переменной iRead, которая должна содержать количество прочтенных байтов, равно 0, так как функция вернула управление до завершения операции ввода-вывода. Обычно это справедливо для первого запуска программы. При последующих запусках, поскольку данные файла находятся в кэше, запрос может успеть выполниться синхронно и значение iRead уже будет равно числу прочитанных байтов.
В программе выбран простейший вариант синхронизации - сигнализация от объекта, управляющего устройством, в данном случае - открытого файла (функции , и .
Результат работы данной программы практически ничем не отличается от обычного синхронного чтения и в таком виде большого смысла не имеет. Однако если между операциями чтения и синхронизации заставить программу выполнять какую-либо полезную работу, то ресурсы компьютера будут использоваться более эффективно, т.к. процессор и устройство ввода будут работать параллельно.
Итак, в случае асинхронного доступа позиция, начиная с которой будет осуществляться операция чтения-записи, содержится в запросе на операцию (параметр структуры ). Рассмотрим теперь особенности позиционирования при обычном CreateFile.
Текущая позиция смещается на конец считанной или записанной последовательности байтов в результате операций чтения или записи. Кроме того, можно установить текущую позицию при помощи Win32-функции SetFilePointer. Например, операция
SetFilePointer(hFile,17 , NULL, FILE_BEGIN);
устанавливает
Тот факт, что
С другой стороны, получив описатель открытого файла, можно его продублировать при помощи Win32- функции DuplicateHandle. В этом случае два разных описателя будут ссылаться на один и тот же объект с одним и тем же
В качестве самостоятельного упражнения рекомендуется написать программу, которая проиллюстрировала бы перемещение
Файловая система на диске представляет собой иерархическую структуру, которая организована за счет наличия специальных файлов - каталогов (директорий). Каталоги имеют один и тот же внутренний табличный формат (рис 11.1) и обеспечивают многоуровневое наименование файлов.
(рис 11.1) Формат каталогаЗапись в каталоге о файле содержит имя файла, некоторые атрибуты (длина имени, временная метка) и ссылку на запись в главной файловой таблице, необходимую для нахождения блоков файла.
В итоге, файловая система на диске образует хорошо известную древовидную структуру (рис 11.2), где нет циклов (если отсутствуют ссылки и точки монтирования) и путь от корня к файлу однозначно определяет файл.
(рис 11.2) Иерархическая древовидная структура файловой системыПоскольку имена файлов, находящихся в разных каталогах, могут совпадать, уникальность имени файла на диске обеспечивается добавлением к собственному имени файла списка \Games\Heroes\heroes.exe. Таким образом, использование древовидных каталогов минимизирует сложность назначения уникальных имен.
Чтобы иметь возможность работать с собственными именами файлов, используют концепцию рабочей или текущей директории, которая обычно входит в состав атрибутов процесса, работающего с данным файлом. Тогда на файлы в такой директории можно ссылаться только по имени. Кроме того ОС поддерживает обозначения '.' - для текущей директории и '..' - для родительской.
В системе поддерживается большое количество Win32-функций для манипуляции с каталогами, их полный перечень имеется в MSDN. В частности, для создания каталогов можно использовать функцию CreateDirectory. Вновь созданная директория включает записи с именами '.' и '..', однако считается пустой. Для работы с текущим каталогом можно использовать функции GetCurrentDirectory и SetCurrentDirectory. Работа с этими функциями проста и не нуждается в специальных разъяснениях.
#include <windows.h>
#include <stdio.h>
void main(void) {
int iRet = 0;
char Buf[512];
int bufSize = 512;
iRet = GetCurrentDirectory(bufSize, Buf);
printf("iRet = %d, current directory %s\n", iRet, Buf);
iRet = CreateDirectory("f:\\tmp1", NULL);
if(!iRet) printf("CreateDirectory error\n");
iRet = SetCurrentDirectory("f:\\tmp1");
if(!iRet) printf("SetCurrentDirectory error\n");
iRet = GetCurrentDirectory(bufSize, Buf);
printf("iRet = %d, current directory %s\n", iRet, Buf);
}
Приведенная программа выводит на экран название текущего каталога, создает каталог "tmp1" на диске "F:" , делает его текущим и выводит на экран его название в качестве текущего каталога.
На основании предыдущей программы рекомендуется написать программу, которая создает каталог в родительской директории и копирует в него какой-либо файл с помощью функции CopyFile.
В ОС Windows принято разбивать диски на логические диски (это низкоуровневая операция), иногда называемые разделами (partitions). Бывает, что, наоборот, объединяют несколько физических дисков в один логический диск. На разделе или логическом диске хранится корневой каталог данного и все вложенные в него каталоги, а задание пути к файлу начинается с имени логического диска или "буквы" диска.
Имена логических дисков хранятся в каталоге "\??" пространства имен объектов, которые и осуществляют связь логического диска и реального устройства. Указав букву диска, прикладная программа получает доступ к его файловой системе.
По аналогии с Unix операционная система Windows позволяет пользователю создать точку монтирования - связать какой-либо пустой каталог с каталогом логического диска. В случае успешного завершения операции содержимое этих каталогов будет соответствовать друг другу.
Чтобы смонтировать логический диск, нужно выполнить команду
>mountvol [<диск>:]<путь> <имя тома>
Здесь параметр <путь> задает имя пустого каталога, а имя тома задается в виде \\?\Volume{код_GUID}\, где GUID - глобальный уникальный идентификатор.
Например
>mountvol f:\tmp1 \\?\Volume\{2eca078d-5cbc-43d3-aff8-7e8511f60d0e}\}
Имена глобальных уникальных идентификаторов и их связь с буквами диска можно узнать, дав команду
>mountvol /?
Монтирование также можно выполнить с помощью панели управления дисками системной панели управления, если выбрать пункт "изменение буквы диска и пути диска".
Наконец, смонтировать диск можно программным образом с помощью Win32-функции SetVolumeMountPoint.
Защита файлов от несанкционированного использования основана на том, что доступ к файлу зависит от идентификатора пользователя. Система контроля доступа предполагает наличие у каждого файла дескриптора защиты, содержащего список прав доступа, который формирует владелец файла и который входит в состав атрибута SecurityAttributes файла. Каждый процесс имеет маркер доступа, который содержит права пользователя, запустившего процесс.
Список прав доступа содержит набор идентификаторов пользователей, имеющих право на доступ к файлу, и их права в отношении этого файла. Маркер доступа содержит идентификатор владельца процесса. Система контроля доступа в момент открытия файла проверяет соответствие прав владельца процесса с теми, которые перечислены в списке прав доступа к файлу. В результате доступ может быть разрешен или отклонен.
Во время выполнения операций чтения, записи и других, проверок прав доступа уже не производится.
В новых версиях NTFS дескрипторы защиты всех файлов хранятся в отдельном файле метаданных \$Secure, который описывается 9-й записью главной файловой таблицы тома
Более подробно защита от несанкционированного доступа описана в части V данного курса.
Файл - единица внешней памяти, поэтому обычно данные, записанные на диск, находятся в составе какого-нибудь файла. Файловая система решает задачи именования и типизации файлов, организации доступа к файлам, защиты, поиска файлов и ряд других. В системе на каждом разделе диска поддерживается иерархическая система каталогов. Для эффективного доступа к файлам могут быть организованы
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.