Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичка по лекциям.doc
Скачиваний:
29
Добавлен:
20.09.2019
Размер:
1.52 Mб
Скачать

2.5. Установка произвольной позиции в файле

Следующей по значимости для работы с файлами после уже рассмотренных системных функций является функция позиционирования в файле. Эта функция обозначается в MS Windows именем SetFilePointer и именем lseek в операционной системе Unix. Функция позиционирования позволяет организовать прямой доступ к данным в файле путем указания места в файле, с которого будет выполняться следующее чтение или запись.

Функция позиционирования SetFilePointer для MS Windows на языке Си имеет прототип

DWORD WINAPI SetFilePointer(HANDLE hFile, LONG ib,

LONG* pDistanceToMoveHigh, DWORD metod),

где hFile – хэндл позиционируемого файла, ib – число байтов, на которое будет перемещена текущая позиция в файле относительно точки отсчета (младшие 32 бита), metod – метод отсчета смещения в файле, pDistanceToMoveHigh – адрес старшего слова размещения количества байт, на которые требуется переместить текущую позицию в файле (при использовании файлов меньше 4 Гбайт этот параметр не используется – задается как NULL). Результирующая позиция после перемещения выдается функцией в качестве значения типа DWORD. При ошибке функция возвращает значение -1. Метод отсчета задается символическими константами FILE_BEGIN, FILE_CURRENT, FILE_END, которые определены в заголовочном файле.

Следующий пример, представленный листингом 2.5.1, демонстрирует использование позиционирования файла в MS Windows.

#include <windows.h>

#include <stdio.h>

void main()

{char buffer[100]="It was readed ";

int len;

DWORD cb, cbw1;

HANDLE hstdout, fhandle;

char fname[ ]="myresult.txt";

BOOL rc;

len = strlen(buffer);

hstdout = GetStdHandle(STD_OUTPUT_HANDLE);

if (hstdout = = INVALID_HANDLE_VALUE) return;

fhandle=CreateFile(fname, GENERIC_READ, FILE_SHARE_READ, 0,

OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);

if (fhandle= = INVALID_HANDLE_VALUE) return;

rc=SetFilePointer(fhandle, 10, 0, FILE_BEGIN);

if (rc= =NULL) return;

rc=ReadFile(fhandle, buffer+len, 80, &cb, NULL);

if (!rc) return;

cb += len;

WriteFile(hstdout, buffer, cb, &cbw1, NULL);

CloseHandle(fhandle);

getchar();

return;

}

Листинг 2.5.1. Программа для Windows

В начале программа получает от ОС хэндл стандартного вывода вызовом функции GetStdHandle. Затем выполняется открытие файла с доступом по чтению и нормальными атрибутами, причем в режиме доступности по чтению другим процессам. Действия по открытию задаются флагом OPEN_EXISTING, т.е. файл, указанный именем myresult.txt, должен уже существовать, иначе возникает ошибка, обнаруживаемая следующими командами. Предполагается использовать эту программу после выполнения программы, описанной листингом 2.3.1, которая и должна была создать файл с именем myresult.txt. Затем указатель текущей записи в файле устанавливается на 10 байт от начала файла, что выполняется вызовом функции SetFilePointer. Далее выполняется чтение из этого файла – с той позиции, которая была только что установлена, и прочитанный текст выводится на стандартный вывод функцией WriteFile. Файл закрывается, а программа завершается.

В операционной системе Unix для установки текущей позиции в файле служит функция с прототипом

off_t lseek (int handle, off_t pos, int whence),

где тип данных off_t совпадает в простейшем применении Unix с типом int (в общем случае тип данных off_t определяется в заголовочном файле sys/types.h). В качестве значения параметра whence следует использовать символические константы SEEK_CUR, SEEK_SET, SEEK_END, определяющие соответственно отсчет изменения позиции от текущего положения, от начала файла и от его конца. Второй параметр – pos определяет относительное смещение позиции в файле от указанной параметром whence точки отсчета. Результирующая позиция файла выдается как значение функции lseek. В случае неудачи функция возвращает значение -1.

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

__off64_t lseek64 (int handle, __off64_t pos, int whence).

Она отличается от своей предшественницы только применением 64-битных значений в качестве смещения в файле, задаваемого вторым аргументом и возвращаемым значением с употреблением соответствующих типов данных для таких значений. Можно и неявно использовать 64-битные смещения в обычных функциях позиционирования lseek (с описываемым обобщенным типом данных off_t), если перед заголовочными файлами программы определить символическую константу __USELARGEFILE64 (которая имеет два символа подчеркивания в начале имени), задав такое определение в виде

#define __USELARGEFILE64

Следующий пример, представленный листингом 2.5.2, демонстрирует использование позиционирования файла в Unix и по своим действиям аналогичен программе из листинга 2.5.1.

#include <stdio.h>

#include <string.h>

#include <fcntl.h>

int main()

{char buffer[100]="Было прочитано ";

int len, cb, cbw1;

int hstdin=0, hstdout=1, fhandle;

char fname[ ]="myresult.txt";

struct flock lock={F_RDLCK, SEEK_SET, 0, 0};

len = strlen(buffer);

fhandle=open(fname, O_RDONLY);

if (fhandle = = -1) exit(1);

lseek(fhandle, 10, SEEK_SET);

fcntl(fhandle, F_SETLKW, &lock);

cb=read(fhandle, buffer+len, 80);

cb += len;

cbw1=write(hstdout, buffer, cb);

lock.l_type=F_UNLCK;

fcntl(fhandle, F_SETLK, &lock);

close(fhandle);

}

Листинг 2.5.2. Программа для Unix

В этой программе сначала открывается файл с именем myresult.txt, причем только для чтения (флаг открытия O_RDONLY), затем позиционируется функцией lseek относительно начала (параметр SEEK_SET) на десятый байт. Потом устанавливается блокировка по чтению от данного процесса на весь файл, из файла читаются данные, которые приписываются к тексту в массиве buffer. Полученный текст выводится функцией write в стандартный файл вывода, снимается блокировка с файла, он далее закрывается, и программа завершается.

Упражнения

1. Разработать программу для Linux, которая открывает файл для записи, вводит со стандартного ввода несколько десятков различных символов и запоминает их в файле, открытом программой.

2. Разработать программу для MS Windows, которая открывает файл для записи, вводит со стандартного ввода несколько десятков различных символов и запоминает их в открытом программой файле.

3. Разработать программу для Linux, которая открывает для чтения файл, созданный в упр. 1, получая значение хэндла. Затем по этому первому хэндлу функцией dup() строится его дубликат – второй хэндл этой программы. Далее выполняется еще одно открытие того же исходного файла для чтения, причем получается третий хэндл. Функцией lseek выполняется позиционирование на 10-й байт открытого файла, используя для этого первый из полученных ранее хэндлов. Затем выполняются три чтения из файла по 7 байтов, используя по очереди все три ранее полученных хэндла и выводя полученные от файла данные через стандартный вывод. Каждый такой вывод следует завершать дополнительным выводом символа перевода на новую строку. В заключение требуется вывести числовые значения всех трех используемых хэндлов и выполнить их закрытие. Результаты вывода объяснить.

4. Разработать программу для MS Windows, которая открывает для чтения файл, созданный в упр. 1, получая значение хэндла. Затем по этому первому хэндлу функцией DuplicateHandle() строится его дубликат – второй хэндл этой программы. Далее выполняется еще одно открытие того же исходного файла для чтения, причем получается третий хэндл. Функцией SetFilePointer выполняется позиционирование на 12-й байт открытого файла, используя для этого первый из полученных ранее хэндлов. Затем выполняются три чтения из файла по 8 байтов, используя по очереди все три ранее полученныѕ0хэндла и выводя полученные от єайла данные через стандартный вывод. Каждый такой вћвод следует завершать дополнительным вћводом0символа перевода на новую строку. В заключение требуется вывести числовые значения всех трех используемых хэндлов и выполнить их закрытие. Результаты вывода объяснить.

5. Разработать программу для MS Windows, осуществляющую вывод на "стандартный файл вывода" содержимого некоторого текстового файла, с запретом совместного чтения другими процессами и организованной задержкой перед прекращением запрета на несколько секунд. Перед открытием файла и после попытки его открытия и анализа ситуации выдавать поясняющие сообщения на экран, отражающие существо происходящего. Запустить в двух экземплярах программу на выполнение, используя для этого либо различные экземпляры командных оболочек, либо системную программу Проводника (Explorer) и пронаблюдать поведение программы. При запущенной на выполнение программе попытаться открыть используемый текстовый файл с помощью системной программы просмотра содержимого файлов (из командной оболочки или иным способом). Результаты объяснить.

6. Разработать программу для Linux, осуществляющую вывод на "стандартный файл вывода" содержимого некоторого текстового файла, с запретом совместного чтения другими процессами и организованной задержкой перед прекращением запрета на несколько секунд. Перед открытием файла и после попытки его открытия и анализа ситуации выдавать поясняющие сообщения на экран, отражающие существо происходящего. Запустить в двух экземплярах программу на выполнение, используя для этого различные виртуальные консоли. Переключение между консолями выполнять нажатием комбинаций клавиш Alt-Fn, где n – номер консоли (находится в пределах от 1 до 6). Пронаблюдать поведение программы. Результаты объяснить.