Файлы FAT нулями автоматически не инициализируются. Согласно документации Microsoft содержимое вновь созданных файлов не определено, что подтверждается экспериментами. Поэтому, если для корректной работы требуется инициализация файлов, приложения должны это делать самостоятельно путем вызова функции WriteFile. Файлы NTFS будут инициализированы, поскольку уровень безопасности С2, обеспечиваемый Windows, требует, чтобы чтение содержимого удаленных файлов было невозможным.
Обратите внимание, что кроме функции SetEndOfFile существуют и другие способы расширения размера файла. Так, можно расширить файл, используя ряд последовательных операций записи, хотя при этом существует риск увеличения степени фрагментации файла; размещение на диске файлов в виде непрерывных блоков большого размера функция SetEndOfFile отдает на откуп операционной системе.
Пример: обновление записей, находящихся в произвольном месте файла
Программа RecordAccess (программа 3.1) обеспечивает поддержку файлов фиксированного размера, состоящих из записей фиксированного размера. В заголовке файла хранится количество непустых записей, содержащихся в файле, а также емкость файла. Пользователю предоставляется возможность выполнять в интерактивном режиме чтение, запись (обновление) и удаление записей, каждая из которых содержит метки времени, текстовую строку и счетчик, показывающий, сколько раз запись изменялась. В качестве несложного и реалистичного расширения возможностей программы можно было бы добавить в структуру записи ключ и определять местоположение записей в файле путем применения хэш-функции к значениям ключа.
Программа демонстрирует позиционирование указателя файла перед заданной записью, а также выполнение 64-битовых арифметических операций с использованием данных типа LARGE_INTEGER Microsoft С. Чтобы проиллюстрировать логику работы указателей файла, в программу включен код, проверяющий наличие ошибок. Программа в целом иллюстрирует применение файловых указателей и множественных структур OVERLAPPED, а также обновление файлов с использованием 64-битовых файловых указателей.
Общее количество записей в файле указывается в командной строке; при большом количестве записей размеры создаваемых файлов могут быть очень большими и даже гигантскими, поскольку длина одной записи составляет примерно 300 байт. После выполнения нескольких экспериментов вы убедитесь, что большие файлы должны быть разреженным; в противном случае необходимо размещать и инициализировать на диске весь файл целиком, в результате чего может существенно увеличиться время обработки файла и занимаемое им место на диске. Хотя в листинге программы 3.1 это и не отражено, в программе предусмотрен участок кода, обеспечивающий создание разреженных файлов, если в этом возникает необходимость; в некоторых системах, например Windows XP Home, этот код правильно работать не сможет.
На Web-сайте книги предоставляются три дополнительные программы, родственные этой: tail.с — другой пример реализации произвольного доступа к файлу, getn.c — упрощенная версия программы RecordAccess, обеспечивающая лишь чтение записей, и atouMT (включена в программы для главы 14, находящиеся на Web-сайте, однако не включена в программы, приведенные в книге), также иллюстрирующая прямой доступ к файлам.
Программа 3.1. RecordAccess
/* Глава 3. RecordAccess. */
/* Использование: RecordAccess имя файла [количество записей]
Количество записей (nrec) можно не указывать, если файл с указанным именем уже существует. Если количество записей (nrec) задано, создается файл с указанным именем (если файл с таким именем существует, он уничтожается). При большом количестве записей (nrec) файлы рекомендуется создавать как разреженные. */
/* Программа иллюстрирует:
1. Произвольный доступ к файлам.
2. Арифметику данных типа LARGE_INTEGER и использование 64-битовых указателей файла.
3. Обновление записей на месте.
4. Запись в файл нулей во время инициализации (требует использования файловой системы NTFS).
*/
#include "EvryThng.h"
#define STRING_SIZE 256
typedef struct _RECORD { /* Структура записи в файле */
DWORD ReferenceCount; /* 0 означает пустую запись. */
SYSTEMTIME RecordCreationTime;
SYSTEMTIME RecordLastReferenceTime;
SYSTEMTIME RecordUpdateTime;
TCHAR DataString[STRING_SIZE];
} RECORD;
typedef struct _HEADER { /* Дескриптор заголовка файла */
DWORD NumRecords;
DWORD NumNonEmptyRecords;
Читать дальше