Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

PytPajB0Au

.pdf
Скачиваний:
1
Добавлен:
15.04.2023
Размер:
1.54 Mб
Скачать

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

Рассмотрим для примера такую последовательность системных вызовов:

fd1 = open("/etc/passwd",O_RDONLY); pid = fork();

fd2 = open("private",O_RDWR);

Первый вызов open выполняется до вызова fork, он создает записи, относящиеся к файлу /etc/passwd, во всех файловых таблицах. При выполнении вызова fork процесс-потомок получает копию таблицы открытых файлов процесса, а в записях таблиц файлов и описателей файлов счетчики ссылок на файл /etc/passwd увеличиваются и становятся равным 2. Дополнительная запись в таблицу файлов не добавляется, оба процесса имеют доступ к файлу через один указатель чтения/записи. Второй вызов open выполняется после вызова fork, то есть тогда, когда существуют уже два процесса - родитель и потомок. Каждый из них выполняет открытие файла независимо от другого. В связи с этим, новые записи добавляются во все таблицы. Закрытие файла уменьшает число ссылок на файл, и когда оно становится равным 0, происходит удаление соответствующих записей из таблиц.

9.1. ПРОГРАММИРОВАНИЕ ОПЕРАЦИЙ ВВОДА-ВЫВОДА

Системные вызовы представляют собой единственное средство, реализующее интерфейс между пользовательскими программами и ядром ОС UNIX. Всякая операция ввода/вывода для пользователя - это операция ввода/вывода в файл. Рассмотрим наиболее часто используемые из системных вызовов.

OPEN

Открывает или создает файл:

int open(

 

const char *path,

/* полное имя файла */

int flags,

/* флаги */

mode_t perms

/* права доступа (если создается новый

файл) */

 

);

 

70

Возвращает положительное целое число, так называемый пользовательский дескриптор файла, который в дальнейшем используется для обращения к этому файлу. Если нет возможности открыть файл, open возвращает -1.

flags определяет режим открытия файла: O_RDONLY – открыть только для чтения O_WRONLY — открыть только для записи O_RDWR — открыть для чтения и для записи

O_APPEND — открыть для дополнения в конец файла O_CREAT — создать новый, если не существует

O_TRUNC — удалить содержимое файла — усечь его размер

до нуля

O_EXCL — не открывать, если существует (используется в комбинации с O_CREAT)

perms определеяет права доступа к создаваемому файлу.

Принцип именования прав доступа следует шаблону S_Ipwww, где p определяет режим доступа (R, W или Х), а www – кому выдается право на этот режим доступа (USR, GRP или OTH). Например, пусть вывод команды ls следующий:

-rwxr-xr-x 1 tar_stud tar_stud 29880 Aug 4 13:45 hello

Для этого файла вместо восьмеричного числа 755 можно записать:

S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH

Существуют отдельные идентификаторы, описывающие полные права доступа. Именование этих идентификаторов следует форме S_IRWXw, где w определяет, кому выдается полное право доступа к файлу

— U, G или O.

Таким образом, предыдущий пример может быть записан в следующем виде:

S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH

CLOSE

Закрывает файл, уничтожает связь между пользовательским дескриптором файла и самим файлом:

void close(

 

int fd

/* дескриптор файла */

);

Возвращает 0 в случае успеха, -1 в случае ошибки (код ошибки в переменной errno).

STAT и FSTAT

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

71

int stat(char *path, struct stat *statbuf); int fstat(int fd, struct stat *statbuf);

Вызов stat предоставляет информацию по имени файла, а fstat - по номеру дескриптора открытого файла. Информация помещается в структуру, описанную ниже:

struct stat

{

dev_t st_dev;

/* идентификатор устройства файловой

системы */

 

 

 

 

ino_t st_ino;

/* номер индексного узла */

 

ushort st_mode;

/* режим доступа и тип файла */

 

short st_nlink;

/* счетчик числа ссылок на файл */

 

ushort st_uid;

/* идентификатор его владельца */

 

ushort st_gid;

/* идентификатор группы */

 

dev_t st_rdev;

/* тип устройства */

 

off_t st_size;

/* размер файла в байтах */

 

time_t st_atime;

/* дата последнего доступа */

 

time_t st_mtime;

/* дата последней модификации */

 

time_t st_ctime;

/* дата создания */

 

}

 

 

 

 

Для детализации информации в поле st_mode используются следую-

щие макросы:

 

 

 

 

#define S_IFMT

0170000

/* тип файла */

 

#define S_IFDIR

0040000

/* каталог */

 

#define S_IFCHR

0020000

/*

байт-ориентированный

спец.

файл */

 

 

 

 

#define S_IFBLK

0060000

/*

блок-ориентированный

спец.

файл */

 

 

 

 

#define S_IFREG

0100000

/* обычный файл */

 

#define S_IFIFO

0010000

/* дисциплина FIFO */

 

#define S_ISUID

04000

/* идентификатор владельца */

#define S_ISGID

02000

/* идентификатор группы */

 

#define S_ISVTX

01000

/*

сохранить свопируемый текст

*/

 

 

 

 

#define S_IREAD

00400

/* владельцу разрешено чтение */

#define S_WRITE

00200

/* владельцу разрешена запись */

#define S_IEXEC

00100

/* владельцу разрешено исполне-

ние */

 

 

 

 

Пример использования вызова stat: struct stat stbuf;

char *filename = ”myfile”; stat(filename, &stbuf);

72

if ((stbuf.st_mode & S_IFMT) == S_IFDIR) printf("%s является каталогом", filename);

READ

Осуществляет чтение из открытого файла count символов в буфер buffer:

int read(int fd, void *buffer, unsigned count);

Возвращает количество прочитанных байт, 0 (если достигнут конец файла) или -1 (в случае ошибки).

Чтение начинается с текущей позиции в файле и по окончании текущая позиция смещается на количество прочитанных байт.

WRITE

Осуществляет запись в открытый файл (fd) указанного количества

(count) символов из буфера (buffer):

int write(int fd, void *buffer, unsigned count);

Возвращает количество реально записанных байт или -1 в случае ошибки.

Запись начинается с текущей позиции в файле, а по ее окончании текущая позиция смещается на число записанных байт.

LSEEK

Перемещает указатель файла с пользовательским дескриптором fd на offset байт:

long lseek(int fd, long offset, int fromwhere);

Возвращает новую позицию в файле или -1 в случае ошибки. Параметр fromwhere определяет положение указателя файла перед

началом перемещения:

SEEK_SET — от начала файла (=0);

SEEK_CUR — от текущей позиции указателя (=1); SEEK_END — от конца файла (=2).

Результатом работы вызова может быть любое неотрицательное число, даже превышающее размер файла. Если новая текущая позиция оказалась за пределами файла, ближайший вызов write вставит «недостающий» кусок в конец файла и заполнит его байтами со значением 0. Вызов read, с текущей позицией установленной в конец файла или за его пределами, вернет признак конца файла – 0. Попытка чтения из интервала, который заполнил вызов write при вставке «недостающего» куска, увенчается успехом и в вызывающую программу будет возвращен буфер, заполненный нулями, как того и следовало ожидать.

DUP и DUP2

73

Эти системные вызовы дублируют пользовательский дескриптор файла:

int dup(int handle);

int dup2(int oldhandle, int newhandle); fd1 = dup(handle);

fd2 = dup2(oldhandle, newhandle);

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

Вызов dup возвращает первый свободный номер дескриптора fd1 или -1, если указанный дескриптор handle не соответствует открытому файлу или нет свободных номеров.

Вызов dup2 возвращает дескриптор newhandle как копию дескриптора oldhandle или -1, если указанный дескриптор oldhandle не соответствует открытому файлу. Если newhandle до этого указывал на открытый файл, этот файл в результате вызова dup2 будет закрыт.

9.2. КОМПИЛИРОВАНИЕ ИСХОДНОГО КОДА ПРОГРАММЫ НА ЯЗЫКЕ C++

Для того, чтобы ввести код программы и отредактировать его подойдет любой текстовый редактор, доступный в вашей UNIX-подобной операционной системе. При этом, программа на языке C++ может иметь различные расширения (.С; .cxx; .cc)

Чтобы откомпилировать уже набранный и отредактированный в текстовом редакторе код программы можно воспользоваться командой вида:

c++ file_name.cxx.

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

Для запуска на выполнение полученного исполняемого файла с программой следует использовать команду вида:

./a.out [в квадратных скобках через пробел указываются параметры, при необходимости]

Для того, чтобы в результате компиляции получить исполняемый файл с определенным именем, необходимо использовать при компиляции опцию «–o»:

c++ file_name.cxx. –o executable_file_name

Тогда, для запуска программы необходимо использовать команду

вида:

./ executable_file_name [в квадратных скобках через пробел указываются параметры, при необходимости]

74

9.3. ПРИМЕРЫ РАБОТЫ С ФАЙЛАМИ

Пример 1. Запись в файл / чтение из файла.

Обратите внимание на обработку параметров командной строки.

/* Фрагмент программы rw.cxx записи в файл / чтения из файла. Программа воспринимает в качестве параметра командной строки имя рабочего файла. Если файл не существует, он будет создан, если существует, его содержимое будет изменено */

#include <stdio.h> #include <sys/stat.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h>

int fd;

int f1()

{

static int j = 1;

if (j > 10) return 0; write(fd, &j, sizeof(int));

printf("write %d -- %d\n", fd, j++); return 1;

}

void f2()

{

int i; lseek(fd,-sizeof(int), 1); read(fd, &i, sizeof(int));

printf("read %d -- %d\n", fd, i);

}

int main(int argc, char *argv[])

{

if (argc < 2) puts("Format: rw filename"); else

{

fd = open(argv[1], O_CREAT | O_RDWR); while (f1()) f2();

close(fd);

}

return 0;

75

}

Пример 2. Дублирование дескриптора файла.

/* Фрагмент программы dup.cxx - перенаправление стандартного вывода в файл. */

#include <unistd.h> #include <stdio.h> #include <string.h> #include <fcntl.h>

int main(void)

{

int outf, std_out;

char *str1 = "Вывод строки в файл\n", *str2 = "Вывод строки на экран\n", *str3 = "Почему эта строка в файле?\n"; std_out = dup(1);

/* закрытие стандартного вывода */ close(1);

outf = open("1.dat", O_CREAT|O_WRONLY, S_IRWXU); write(outf,str1,strlen(str1));

write(std_out,str2,strlen(str2));

write(1,str3,strlen(str3));

/* восстановление предыдущих значений */ close(outf);

outf = open("dev\tty", O_WRONLY); close(std_out);

return 0;

}

9.4. ВАРИАНТЫ ЗАДАНИЙ ДЛЯ ЗАКРЕПЛЕНИЯ ЗНАНИЙ НА ПРАКТИКЕ

1.Создайте программу, которая будет считывать две последовательности байтов из файла a1 и записывать их в файл a2. Длины последовательностей [х1, х2] и [y1, y2], имена файлов задаются в качестве параметров.

2.Создайте программу, в качестве параметров которой задаются длины последовательностей байтов [х1, х2] и [y1, y2], и имя файла, в котором эти последовательности будут меняться местами.

76

3.Создайте программу, которая в качестве параметров получает имена входного и выходного файлов и натуральной число - х. Программа должна считывать каждый х-й байт из входного файла и записывать его в выходной файл.

4.Создайте программу, которая в качестве параметров получает имена входного и выходного файлов и параметр - x. Если параметр x нечетный, то программа должна считывать каждый x-й байт из входного файла и записывать его в выходной файл, а если параметр x четный, то программа должна переписать побайтово содержимое входного файла в выходной файл.

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

6.Создайте программу, которая в качестве параметров получает имена входного файла и некоторую подстроку. Программа должна осуществлять поиск этой подстроки в файле. В случае обнаружения этой подстроки в файле, необходимо заменить её на другую подстроку, запрашиваемую у пользователя.

7.Создайте программу, которая в качестве параметров получает имя входного файла, производит в нем поиск пробелов и, в случае, если обнаруживает подстроку, состоящую из более чем одного пробела, идущего подряд, заменяет её на один пробел.

8.Используя алгоритм сложения по модулю два, создайте программу, которая в качестве параметров получает имя входного файла и кодовое слово и может осуществлять кодирование и декодирование этого файла.

9.Создайте программу, которая в качестве параметров получает имя входного текстового файла, подсчитывает общее количество строк в нем, и модифицирует его, подставляя число строк в последнюю

строку этого файла.

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

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

12.Создайте программу, которая в качестве параметров получает имя входного текстового файла, подсчитывает общее количество цифр в

77

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

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

14.Создайте программу, которая в качестве параметров получает имя входного файла и диапазон кодов символов [х1, х2], находит в файле все символы, попадающие в указанный диапазон и заменяет их символом, код которого также указывается в качестве параметра.

15.Создайте программу, которая в качестве параметров получает имя входного файла и диапазон кодов символов [х1, х2], находит в файле все символы, попадающие в указанный диапазон и заменяет их пробелами.

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

12).

17.Создайте программу, которая в качестве параметров получает имя входного текстового файла и меняет его формат с формата UNIX на формат DOS. Суть замены заключается в добавлении/удалении специальных символов, используемых для обозначения перевод строки и возврата каретки (10 и 13, соответственно).

18.Создайте программу, которая в качестве параметров получает имя файла a1 и директории d1 и записывает список файлов директории d1 и их параметров в файл a1.

19.Создайте программу, которая в качестве параметров получает имя файла a1 и директории d1, проводит поиск всех файлов в поддереве d1 и записывает количество найденных файлов в файл a1.

20.Создайте программу, которая в качестве параметров получает имя файла a1 и директории d1, проводит поиск всех файлов в поддереве d1 и записывает имена найденных файлов в файл a1.

21.Создайте программу, которая в качестве параметров получает имя файла a1 и директории d1, проводит поиск всех файлов в поддереве d1 и записывает имена и параметры найденных файлов в файл a1.

22.Создайте программу, которая в качестве параметров получает имя директории d1, проводит поиск всех файлов в поддереве d1 и, в случае, если для какого-либо файла разрешено выполнение для какой – либо группы пользователей, устанавливает для этого файла биты разрешения доступа на выполнение.

78

23.Создайте программу, которая в качестве параметров получает имя файла a1, директории d1, и дату t1. Программа должна записать список всех файлов директории d1, которые были созданы в дату t1.

24.Создайте программу, которая в качестве параметров получает имя файла a1, директории d1, и дату t1. Программа должна записать список всех файлов директории d1, которые были модифицированы в дату t1.

25.Создайте программу, которая в качестве параметров получает имя файла a1 и директории d1. Программа должна записать список всех файлов директории d1, которые были созданы в текущую дату.

26.Создайте программу, которая в качестве параметров получает имя файла a1, директории d1, и дату t1. Программа должна записать список всех файлов директории d1, которые были модифицированы в текущую дату.

27.Создайте программу, которая в качестве параметров получает имя файла a1, директории d1 осуществляет определение имен всех владельцев всех файлов в директории d1 и выводит список всех владельцев всех файлов в файл a1.

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

29.Создайте программу, которая в качестве параметров получает имя файла a1, директории d1, искомое количество ссылок файла l1, осуществляет поиск всех файлов из директории d1, которые имеют более чем l1 ссылок и выводит список имен этих файлов в файл a1.

30.Создайте программу, которая в качестве параметров получает имя файла a1, директории d1, искомое количество ссылок файла l1, осуществляет поиск всех файлов из директории d1, которые имеют менее чем l1 ссылок и выводит список имен этих файлов в файл a1.

31.Создайте программу, которая в качестве параметров получает имя файла a1, директории d1, искомое количество ссылок файла l1, осуществляет поиск всех файлов из директории d1, которые имеют количество ссылок равное l1 и выводит список имен этих файлов в файл a1.

32.Создайте программу, которая в качестве параметров получает имя директории d1, искомое количество ссылок файла l1, осуществляет поиск всех файлов из директории d1, которые имеют более чем l1 ссылок и выводит список имен этих файлов на экран.

33.Создайте программу, которая в качестве параметров получает имя директории d1, искомое количество ссылок файла l1, осуществляет поиск всех файлов из директории d1, которые имеют менее чем l1 ссылок и выводит список имен этих файлов на экран.

79

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]