MS-DOS для программиста© Александр Фролов, Григорий ФроловТом 19, М.: Диалог-МИФИ, 1995, 253 стр. 3.5. Чтение и запись файловПосле того как вы открыли файл, можно выполнять над ним операции чтения или записи. При этом соответствующим функциям необходимо передать идентификатор файла. После завершения операций чтения или записи файл следует закрыть. Запись данных в файлДля записи данных в файл предназначена функция
40h прерывания INT 21h . В качестве параметров для
этой функции необходимо указать идентификатор
файла, полученный при открытии существующего
файла или создании нового, адрес блока памяти,
содержащего данные для записи и размер этого
блока памяти:
При записи данные попадают в то место внутри файла, которое определяется содержимым так называемого файлового указателя позиции. При создании нового файла этот указатель сбрасывается в 0, что соответствует началу файла. При открытии файла с помощью функции 3Dh указатель также устанавливается на начало файла. Операция записи в файл с помощью функции 40h продвигает указатель вперед к концу файла на количество записанных байт. По мере увеличения размера файла ему будут распределяться все новые и новые кластеры из числа отмеченных как свободные. Если вам необходимо перезаписать содержимое файла, а не дописывать данные в конец, необходимо воспользоваться функцией позиционирования. Эта функция будет описана в следующем разделе. Она позволяет управлять содержимым файлового указателя позиции. Следует учитывать, что количество действительно записанных байт может не совпадать с заданным в регистре CX при вызове функции 40h. Такая ситуация возможна, например, при записи в файл, открытый в текстовом режиме, байта 1Ah. Этот байт означает конец текстового файла. Другая возможная причина - отсутствие свободного места на диске. Если функция вызывается с содержимым регистра CX, равным 0, файл будет обрезан или расширен до текущего положения файлового указателя. Разумеется, если программа, выполняющая запись в файл, работает в сети, она должна иметь соответствующие права доступа к каталогу и файлу. Функция 40h может выполнять запись не только в файл, но и в символьное устройство, предварительно открытое функцией 3Dh. Об этом мы говорили в разделах книги, посвященных драйверам. Чтение данных из файлаДля чтения данных из файла (или символьного
устройства) предназначена функция 3Fh прерывания
INT 21h :
Эта функция используется аналогично функции записи. Для нее верны все замечания, касающиеся файлового указателя позиции, количества действительно прочитанных байт и прав доступа. Функции библиотеки Borland C++Если ваша программа составлена на языке программирования С или C++, для записи и чтения данных она может воспользоваться функциями write и read : int write (int handle, void *buffer, unsigned count); int read (int handle, void *buffer, unsigned count); Эти функции работают аналогично функциям 40h и 3Fh прерывания INT 21h . Параметр handle определяет файл, для которого необходимо выполнить операцию записи или чтения. Параметр buffer - указатель на блок памяти, который содержит данные для записи или в который необходимо поместить прочитанные данные. Количество записываемых или читаемых байт определяется третьим параметром - count. После выполнения операции функция возвращает количество действительно записанных или прочитанных байт или -1 при ошибке. Будьте внимательны, если вы записываете или читаете больше 32 Кбайт - вы можете получить признак ошибки, хотя передача данных выполнилась правильно. Большие массивы данных можно записывать по частям. Программа FCOPYВ качестве примера мы приведем программу копирования файлов FCOPY (листинг 3.4), которая пользуется описанными выше функциями. Листинг 3.4. Файл fcopy\fcopy.cpp #include <io.h> #include <conio.h> #include <stdio.h> #include <fcntl.h> #include <sys\types.h> #include <sys\stat.h> #include <malloc.h> #include <errno.h> int main(int argc, char *argv[]) { int source, taget, i; char *buffer; int count; if(argc == 3) { // Открываем исходный файл if((source = open (argv[1], O_BINARY | O_RDONLY )) == - 1) { printf("\nОшибка: %d", errno); return(-1); } // Открываем выходной файл. При необходимости // создаем новый. Если файл уже существует, // выводим на экран запрос на перезапись // содержимого существующего файла taget = open (argv[2], O_BINARY | O_WRONLY | O_CREAT | O_EXCL , S_IREAD | S_IWRITE); if(errno == EEXIST) { printf("\nФайл существует. " "Перезаписать? (Y,N)\n"); // Ожидаем ответ и анализируем его i = getch(); if((i == 'y') || (i == 'Y')) taget = open (argv[2], O_BINARY | O_WRONLY | O_CREAT | O_TRUNC , S_IREAD | S_IWRITE); } // Если выходной файл открыть невозможно, // выводим сообщение об ошибке // и завершаем работу программы if(taget == -1) { printf("\nОшибка: %d", errno); return(-1); } // Будем читать и писать за один раз 10000 байт count = 10000; // Заказываем буфер для передачи данных if((buffer = (char *)malloc(count)) == NULL) { printf("\nМало памяти"); return(-1); } // Копируем исходный файл while(!eof(source)) { // Читаем count байт в буфер buffer if((count = read (source, buffer, count)) == -1) { printf("\nОшибка при чтении: %d", errno); return(-1); } // Выполняем запись count байт // из буфера в выходной файл if((count = write (taget, buffer, count)) == - 1) { printf("\nОшибка при записи: %d", errno); return(-1); } } // Закрываем входной и выходной файлы close (source); close (taget); // Освобождаем память, заказанную под буфер free(buffer); } // Если при запуске программы не были указаны // пути для входного или выходного файла, // выводим сообщение об ошибке else printf("\nЗадайте пути для файлов!\n"); return 0; } Для определения момента достижения конца исходного файла в программе использована функция eof: int eof(int handle); Для файла с идентификатором handle эта функция
возвращает одно из трех значений:
Программа, которая читает файл с помощью функции 3Fh прерывания INT 21h , может определить момент достижения конца файла анализируя код ошибки, передаваемый в регистре AX. |