
книги / Программирование на языке Си
..pdf372 |
Программирование на языке Си |
Третий параметр - права доступа должен применяться толь ко в режиме открытия файла 0_CREAT, т.е. только при созда нии нового файла.
В операционных системах MS-DOS и Windows для задания параметра правадоступа используются следующие предопре деленные константы:
S_IWRITE - разрешить запись в файл;
S_IREAD - разрешить чтение из файла;
S_IREAD|S_IWRITE - разрешить и чтение, и запись (совпа дает с SJWRITE).
Перечисленные константы размещены в заголовочном файле stat.h, находящемся в каталоге sys системы программирования Си. Обычно его подключение осуществляется директивой #include <sys\stat.h>.
Если параметр права_доступа не указан, то устанавливается разрешение только на чтение из файла. Чаще всего в операци онных системах MS-DOS и Windows этот параметр не исполь зуется.
В UNIX в силу того, то она является многопользовательской, система защиты файлов более развита. Права доступа к файлам устанавливаются для трех категорий пользователей:
•владелец файла;
•участник группы пользователей;
•прочие пользователи.
Права доступа к конкретному файлу устанавливаются вла дельцем файла специальными командами. Права доступа ото бражаются при просмотре оглавления каталога командой Is -I в виде символьной строки, которая формируется по следующему правилу: для каждой группы пользователей в строке прав дос тупа выделяется 3 символа, каждый из которых может прини мать следующие значения:,
г - разрешено чтение из файла; w - разрешена запись в файл;
х- разрешено выполнение файла (для файлов, хранящих исполняемую программу).
Глава 7. Ввод и вывод |
373 |
Символы г, w, х задаются строго на своих местах в указан ном порядке (rwx). Если какой-либо из типов доступа к файлу запрещен, на месте соответствующего символа записывается символ (минус). Таким образом, если для владельца файла разрешены все виды доступа к файлу (rwx), для участника группы пользователей - только чтение и выполнение (r-х), а для прочих пользователей - только выполнение (~х), то строка прав доступа будет выглядеть так:
rwxr-x— X
От этой строки символов легко перейти к собственно пара метру правадоступа, являющемуся целым числом. Если на соответствующем месте в строке указан символ, отличный от то записывают Т , иначе - записывают '0'. Получившееся двоич ное число (111101001) переводят в восьмеричное, записав в ви де восьмеричной цифры каждую группу из трех двоичных цифр, начиная с самой правой группы: 0751. Это число и следует ука зать в качестве параметра права доступа в функции ореп().
Приведем несколько примеров открытия файла. 1. Открыть файл для чтения:
fd = open("t.txt", 0_RD0NLY);
2. Открыть существующий файл для записи новых данных:
fd = open("new.txt", OJWRONLY|0_CREAT|0_TRUNC,0600);
Параметр права доступа, заданный восьмеричной константой 0600 (для UNIX), в символьном изображении имеет вид rw------, т.е. для владельца файла разрешены чтение и запись, для двух других категорий пользователей не разрешен ни один из видов доступа к файлу. Если файл с именем new.txt существует, то перед записью новых данных он будет усечен до нулевого раз мера (очищен). При открытии файла с указанными параметрами в других ОС параметр права доступа опускается.
3. Открыть файл для добавления:
fd=open("t.txt",
О WRONLY|О APPEND|О CREAT,0600);
374 |
Программирование на языке Си |
4.Открыть файл для чтения и записи: fd = open("t.txt", 0_RDWR);
5.Создать новый файл для записи:
if ((fd = open("tmpfile", 0_WR0NLY|0_CREAT| 0_EXCL, 0666)) == -1)
puts("tmpfile уже существует\п");
В операционной системе UNIX такая последовательность опе раторов открывает новый файл для записи. Если файл не суще ствует, то он создается. Иначе функция завершается неудачей. Флаг O EXCL специально задан для предотвращения непредна меренного уничтожения уже существующего файла. Этот флаг используется совместно с O CREAT. Права доступа (rw-rw-rw-) разрешают чтение и запись в файл для всех категорий пользова телей. В других ОС параметр права доступа должен быть опу щен.
Приведем более полный пример создания файла (MS-DOS,
Windows):
#include <stdio.h> #include <stdlib.h> #include <io.h> #include <errno.h> #include <fcntl.h> #include <sys\stat.h> void main( )
{
int fd; /* Дескриптор файла */ if ((fd = open("tmpfile",
0_RDWR|0_CREAT|0_EXCL,
S_IREAD |S_IWRITE)) < 0)
{.
if (errno == EEXIST) fprintf(stderr, "файл tempfile"
" уже' существует\п") ;
exit(errno);
}
}
Глава 7. Ввод и вывод |
375 |
Создаваемый файл в соответствии с выбранными флагами открывается для чтения и записи. Права доступа (rw-------) по зволяют только владельцу работать с файлом (читать и писать).
Для идентификации ошибок, возникающих при открытии файла, используется именующее выражение (переменная) errno, определенное в заголовочном файле errno.h. При выпол нении функций стандартной библиотеки в область памяти, име нуемой errno, записываются коды ошибок. Предопределенная в errno.h константа EEXIST означает, что файл, указанный в функции ореп( ), уже существует. В этом примере для вывода сообщения об ошибке применена функция форматного вывода в файл fprintf(), в которой использован предопределенный деск риптор файла stderr стандартного потока для вывода сообще ний об ошибках. ' {
Кроме функции ореп( ), для открытия файла можно исполь зовать функцию creat(), упомянутую в начале параграфа. Функция creat( ) полностью эквивалентна такому вызову функ ции ореп():
open (имя файла, 0_CREAT|0_TRUNC|0_WR0NLY);
Функция creat() создает новый файл и открывает его для за писи. Наличие в библиотеке наряду с функцией ореп( ) функции creat() вызвано требованиями совместимости с ранними вер сиями UNIX, имевшими только три основных режима открытия файла (O RDONLY, O WRONLY, 0_RDWR), что вынуждало использовать для создания нового файла специальную функцию creat().
Так же как и при использовании потоков, в начале работы каждой программы автоматически открываются файлы стан дартного ввода, стандартного вывода и стандартного вывода сообщений об ошибках. Эти файлы имеют значения дескрипто ров файлов 0, 1 и 2, которые можно использовать при обменах на нижнем уровне со стандартными файлами.
Необходимо иметь в виду, что в каждой операционной сис теме имеется ограничение на количество одновременно откры тых в программе файлов. Обычно их число устанавливается от
376 |
Программирование на языке Си |
20 до 40. Во время работы программы, в которой обрабатывает ся большое количество файлов, необходимо своевременно за крывать ненужные файлы. Для закрытия файла на нижнем уровне служит функция close(), прототип которой имеет вид:
int close {дескриптор_фаша)\
Функция cIose() при успешном завершении возвращает 0. В случае ошибки возвращается -1.
При завершении программы все открытые файлы автомати чески закрываются.
7.2.2. Ч тение и запись данны х
Ввод-вывод данных на нижнем уровне осуществляется функциями read() и write( ). Прототипы этих функций имеют следующий вид:
int read(int fd, char *buffer, unsigned int count);
int write(int fd, char *buffer, unsigned int count);
Обе функции возвращают целое число - количество действи тельно прочитанных или записанных байтов,.
Функция read( ) читает количество байтов, заданное третьим параметром count, из файла, открытого с дескриптором файла fd, в буфер, определенный указателем buffer. При достижении конца файла функция read() возвращает значение 0. В случае возникновения ошибки при чтении из файла функция read() возвращает значение -1.
Операция чтения, так же как и для потокового ввода-вывода, начинается с текущей позиции в файле. После завершения опе рации чтения текущая позиция будет определять первый непро читанный символ.
Если файл открыт в текстовом режиме, то происходят точно такие же преобразования при вводе последовательности симво лов CR и LF в символ '\n' (LF), как и при работе с потоком. Ука занное преобразование приводит к тому, что в возвращаемом
Глава 7. Ввод и вывод |
377 |
значении вместо двух символов CR и LF учитывается только один символ '\n' (LF).
Функция write( ) записывает последовательность байтов, ко личество которых задано третьим параметром count, в файл, ''от крытый с дескриптором файла fd, из буфера, определенного указателем buffer. Запись производится с текущей позиции. Ес ли файл открыт в текстовом режиме, то количество реально за писанных байтов может превышать count за счет преобразова ний всех символов 'V в последовательности символов CR, LF. Таким образом, count будет содержать только количество сим волов, взятых из буфера.
Если при выполнении операции записи возникла ошибка, то функция w rite() возвращает значение -1, а глобальная пере менная errno получает одно из следующих значений, заданных предопределенными константами в заголовочном файле errno.h:
EACCES - файл защищен для записи (доступен только для чтения);
ENOSPC - исчерпано свободное пространство на внешнем устройстве;
EBADF - недействительный дескриптор файла.
Приведем два примера применения функций низкоуровнево го ввода-вывода.
П рим ер 1.
Копирование последовательности отдельных символов iA стандартного ввода в стандартный вывод:
#include <io.h> int main( )
{
char c[2];
while ((read(0, c, 1)) > 0) write(1, c, 1);
return 0 ;
}
В текст программы включается заголовочный файл io.h, со держащий прототипы функций read() и w rite(). При вызове
Глава 7. Ввод и вывод |
|
|
379 |
int п; /* Количество прочитанных байтов */ |
|||
char buff[BUFSIZ]; |
|
|
|
if ( argc != 3) |
|
|
|
{ |
|
|
|
printf("Формат вызова программы:"); |
|
||
printf("\n |
%s файл_источник файл_приемник", |
||
argv[0]) ; |
|
|
|
return 1; |
|
|
|
> |
open(argv[l], 0_RD0NLY)) == |
-1) |
|
if ((fdin = |
|||
{ |
|
|
|
perror(argv[1]); |
|
|
|
return 1; |
|
|
|
} |
open(argv[2], |
|
|
if ((fdout = |
|
||
0_WR0NLY|0_CREAT|0_TRUNC)) == -1) |
|
||
( |
|
|
|
perror(argv[2]); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
/* Файлы открыты - можно копировать */ |
> 0 ) |
||
while ((n = |
read(fdin, |
buff, BUFSIZ)) |
|
write(fdout, buff, |
n); |
|
|
return 0; |
|
|
|
} |
|
|
|
Константа BUFSIZ (размер буфера для потокового вводавывода) определена в заголовочном файле stdio.h. Ее значение для MS-DOS равно 512 байт.
Для применения этой программы в ОС MS-DOS необходимо вначале построить исполняемую программу (см. гл. 9), напри мер, copyf.exe. Вызов программы из командной строки будет иметь вид:
>copyf f1.dat |
f2 .dat |
где f1.dat - файл-источник; f2.dat - файл-приемник.
Если ошибок при исполнении программы нет, файл будет скопирован, но никаких сообщений на экране дисплея не поя вится..
Глава 7. Ввод и вывод |
381 |
П р и м ер 2.
Установка текущей позиции для последующего добавле ния данных в файл (позиция в конце файла):
lseek(fd, OL, SEEK_END);
П рим ер 3.
Модификация записей в существующем файле
В качестве еще одного примера использования функции Iseek() приведем фрагмент программы, производящей модифи кацию записей в существующем файле. Запись - это объект (последовательность байтов) в файле, являющаяся сложным структурным элементом в контексте программы, обрабатываю щей эти записи. Логическая структура записи может быть лю бой: некоторой последовательностью байтов, строкой, структурой и т.д. В следующем фрагменте программы предпо лагается, что все записи имеют одинаковый размер (в байтах) и размещены в файле подряд.
/* Прочитать запись в буфер */ read(fd, buff, sizeof ( запись, ));
/* Вернуть указатель в файле на место, с которого начиналось чтение записи */
lseek(fd, -sizeof( запись ), SEEK_CUR); /* Откорректировать запись в буфере */
/* Поместить запись на прежнее место */ write(fd, buff, sizeof( запись ));
Буфер buff может быть определен как массив символов, дос таточный для размещения одной записи.