C fopen не открывает файл. Пример работы программы. Пример: исходный код программы

Функция fopen() открывает файл, имя которого указано аргументом fname, и возвращает свя­занный с ним указатель. Тип операций, разрешенных над файлом, определяется аргументом mode. Разрешенные для mode значения показаны в таблице.

Таблица: Допустимые значения для mode
Режим Значение
"r"
"w" Создает файл для записи (по умолчанию файл открывается как текстовый).
"а" Дописывает информацию к концу файла (по умолчанию файл открывается как текстовый).
"rb" Открывает двоичный файл для чтения.
"wb" Создает двоичный файл для записи.
"ab" Дописывает информацию к концу двоичного файла.
"r+" Открывает файл для чтения/записи (по умолчанию файл открывается как текстовый).
"w+" Создает файл для чтения/записи (по умолчанию файл открывается как текстовый).
"а+" Дописывает информацию к концу файла или создает файл для чтения/записи (по умолчанию открывается как текстовый файл).
"r+b" Открывает двоичный файл для чтения / записи.
"w+b" Создает файл для чтения / записи.
"а+b" Дописывает информацию к концу файла или создает двоичный файл для чтения.
"rt" Открывает текстовый файл для чтения.
"wt" Открывает текстовый файл для записи.
"at" Дописывает информацию к концу текстового файла.
"r+t" Открывает текстовый файл для чтения/записи.
"w+t" Создает текстовый файл для чтения/записи.
"a+t" Открывает или создает текстовый файл для чтения/записи.

Аргумент fname должен быть строкой символов, образующей действительное имя файла, куда может входить путь к файлу.

Если функции fopen() удалось открыть указанный файл, возвращается указатель на FILE. Если же файл не может быть открыт, возвращается NULL.

Как показано в таблице, файл может быть открыт либо в двоичном, либо в текстовом режиме. В текстовом режиме возврат каретки и последовательности перевода строки при вводе транслируется в символы «новая строка». При выводе - наоборот: символ новой строки транс­лируются в возврат каретки и перевод строки. Такого рода трансляция не производится при работе с двоичными файлами.

Если строка mode не задает ни b (для двоичных), ни t (для текстовых файлов), то тип открыва­емого файла определяется значением встроенной глобальной переменной _fmoae. По умолчанию _fmode принимает значение O_ТЕХТ, что означает текстовый режим. Она может быть установле­на и в O_BINARY, что означает двоичный режим. Эти макросы определены в fcntl.h.

При открытии файла этот метод контролирует возможность ошибок при открытии, например, проверяет наличие защиты от записи или отсутствие места на диске перед попыткой записи на диск. NULL, т.е. 0, используется потому, что указатели файлов никогда не принимают этого значения. NULL определен в stdio.h.

Если при операции записи для открытия файла используется функция fopen(), то любой файл, уже имевший такое же имя, будет стерт и на его месте будет создан новый файл. Если файла с таким именем не существовало, он будет создан. Если необходимо дописать что-нибудь в конец файла, то необходимо использовать режим а. Если файл не существует, будет возвращена ошиб­ка. При открытии файла для операций чтения необходимо, чтобы он уже существовал. В против­ном случае будет возвращена ошибка. И наконец, если файл открывается для операций чтения/ записи, то он не стирается, если он уже существует, а если такого файла нет, он создается.

resource fopen (string filename, string mode [, bool use_include_path [, resource zcontext]])

fopen() закрепляет именованый ресурс, указанный в аргументе filename , за потоком. Если filename передан в форме "scheme://...", он считается URL"ом и PHP проведёт поиск обработчика протокола (также известного как "обвёртка") для этой схемы. Если ни одна обвёртка не закреплена за протоколом, PHP выдаст замечание чтобы помочь вам отследить потенциальную проблему в вашем скрипте и продолжит выполнение, будто filename указывает на обыкновенный файл.

Если PHP решил, что filename указывает на локальный файл, тогда он попытается открыть поток к этому файлу. Файл должен быть доступен PHP, так что вам следует убедиться, что права доступа на файл разрешают это. Если вы вкдючили безопасный режим или open_basedir , накладываются дальнейшие ограничения.

Если PHP решил, что filename указывает на зарегистрированный протокол и этот протокол зарегистрирован как сетевой URL, PHP проверит состояние директивы allow_url_fopen . Если она выключена, PHP выдаст предупреждение и вызов fopen закончится неудачей.

Замечание: Некоторые протоколы поддерживают context и/или опции php.ini . Обратитесь к соответствующей странице с описанием используемого протокола для получения списка опций, которые могут быть установлены. (например, значение php.ini user_agent используется обвёрткой http). Для получения описания параметров contexts и zcontext , обратитесь к разделу Stream Functions .

Замечание: Поддержка контекста была добавленав PHP 5.0.0 .

Замечание: Начиная с версии PHP 4.3.2, бинарный режим является режимом по умолчанию для всех платформ, которые различают бинарный и текстовый, режимы. Если у вас возникли проблемы после обновления, попробуйте использовать флаг "t" в качестве обходного пути до тех пор, пока вы не измените свои скрипты для достижения большей портируемости, как отмечено выше.

Параметр mode указывает тип доступа, который вы запрашиваете у потока. Он может быть одним из следующих:

Если открыть файл не удалось, функция вернёт FALSE и сгенерирует ошибку уровня E_WARNING . Вы можете использовать для того, чтобы подавить это предупреждение.


Пример 1. Примеры использования функции fopen()

$handle = fopen ("/home/rasmus/file.txt" , "r" );
$handle = fopen ("/home/rasmus/file.gif" , "wb" );
$handle = fopen ("http://www.example.com/" , "r" );
$handle = fopen ("ftp://user:[email protected]/somefile.txt" , "w" );
?>

Если вы сталкиваетесь с проблемами во время чтения или записи файлов, и вы используете PHP в виде серверного модуля, убедитесь в том, что процесс сервера имеет доступ к файлам и директориям, которые вы используете.

] FOPEN #include FILE *fopen(pathname, type); char *pathname; path-имя файла. char *type; разрешенный тип доступа. Описание. Функция fopen открывает файл, определяемый path-именем. Символы в строке type определяют тип доступа, требуемый для фай- ла, следующим образом. РЕЖИМ ОПИСАНИЕ "r" открыть файл для чтения.(Этот файл должен существовать). "w" открыть пустой файл для записи; если этот файл ранее существовал, его содержимое уничтожается. "a" открыть файл для записи (добавления) в конец. Если данного файла нет, то вначале он создается. "r+" открыть файл одновременно для чтения и записи. Файл должен существовать. "w+" открыть пустой файл для чтения и записи. Если этот файл ранее существовал, его сожержимое уничтожается. "a+" открыть файл для чтения и добавления. Если файла нет, вначале он создается. Замечание! Нужно внимательно применять режимы "w", "w+", так как они могут уничтожить существующие файлы. Если файл открыт при помощи типа "a" или "a+", все операции записи выполняются в конец файла. При использовании функций fseek или rewind возможно перепозиционирование указателя на файл; нес- мотря на это, указатель на файл перед выполнением любых операций записи всегда возвращается в конец файла. Таким образом, сущест- вующие данные не будут перезаписаны. При использовании типов "r+", "w+", "a+" допускается одновременно чтение и запись. (Гово- рится, что файл открывается для обновления). Поэтому, при перек- лючении чтения на запись и наоборот нужно использовать функции fseek или rewind. Для функции fseek (при необходимости) может быть точно определена текущая позиция. Дополнительно к значениям, описанным выше, может быть до- бавлен в строке type один из следующих символов, чтобы специфици- ровать способ преобразования символа новой строки. Символ Значение t открыть в текстовом (преобразующем) режиме; при вводе комбинация "Возврат каретки - перевод строки" преобразовывается к единственному символу "перевода строки". При выводе символ перевода строки преобразовывается в комбинацию ВК-ПС. b открыть в двоичном (непреобразующем) режиме; выше описанные преобразования не осуществляются. Если t или b в строке type не задается, режим преобразова- ния определяется переменной _fmode и режимом, устанавливаемым по умолчанию. Возвращаемое значение. Функция fopen возвращает указатель на открытый файл. Значе- ние указателя NULL свидетельствует об ошибке. См.также fclose, fcloseall, fdopen , ferror , fileno , freopen , open , setmode. Пример: #include main (argc, argv) int argc; char *argv; { FILE *stream; /* применение fopen позволяет открыть файл, имя которого хранится в указателе argv; если это не удается, программа распечатывает сообщение об ошибке */ if ((stream= fopen(argv), "r"))==NULL) { fprintf (stderr, "%s не может открыть файл %s\n", argv, argv); exit(1); } /* Замечание! Имя программы хранится в argv только для версий MS DOS 3.0 и последующих; в предыдущих версиях MS DOS, argv содержится в строке "Си" */ Образец командной строки: update employ.dat На выходе будет сообщение: "C:\BIN\UPDATE.EXE не может открыть файл employ.dat ". FP_OFF - FR_SEG #include unsigned FP_OFF(longptr); unsigned FP_SEG(lohgptr); char far *longptr; long-указатель на адрес памяти. Описание. Макро FP_OFF и FP_SEG могут использоваться соответственно для установки разветвления или взятия сегмента посредством long-указателя longptr. Возвращаемое значение. Макро FP_OFF возвращает беззнаковое целое значение, предс- тавляющее разветвление. Макро FP_SEG возвращает беззнаковое целое значение, предс- таляющее адрес сегмента. См.также segread. Пример. #include char far *p; unsigned int seg_val; unsigned int off_val; . . . seg_val=FP_SEG(p); off_val=FP_OFF(p); _FPRESET #include void _fpreset(); переинициализирует математиче- ский пакет с плавающей точкой. Описание: Функция _fpreset переинициализирует математический пакет с плавающей точкой. Эта функция обычно используется с процедурами signal , system или с семейством процедур exec, spawn. Если программа вместе с функцией signal захватывает сигналы ошибок с плавающей точкой (SIGFPE), то она при вызове _fpreset благополучно восстанавливается из ошибок с плавающей точкой и вы- полняет longjmp. Замечание! В версиях MS DOS, более ранних чем 4.0, child-процесс, выполнимый в exec, spawn или system , может воздей- ствовать на состояние с плавающей точкой parent-процесса, если используется 8087 или 80287 сопроцессор. Поэтому, если использу- ется сопроцессор 8087 либо 80287, рекомендуются помнить, что: * exec, spawn, system не могут вызываться в процессе вычис- ления выражения с плавающей точкой; * _fpreset должна быть вызвана после этих процедур, если child-процесс может выполнить требуемую операцию. Возвращаемое значение: Возвращаемого значения нет. См.также execl, execle, execlp, execlpe, execv, execve, execvp, execvpe, signal , spawnl, spawnle, spawnlp, spawnlpe, spawnv, spawnve, spawnvp, spawnvpe. Пример. #include #include #include #include int fphandler (); jmp_buf mark; double a = 1.0, b = 0.0, c; main() { if(signal(SIGFPE, fphandler)==(int(*)())-1) abort(); if(setjmp(mark)==0) { c = a/b; printf("Should never get here\n"); } printf("Recovered from floating-point error\n"); } int fphandler(sig,num) int sig,num; { printf("signal=%d subcode =%d\n",sig,num); _fpreset(); /* переинициализирует пакет с плавающей точкой */ longjmp(mark,-1); }

В лекции рассмотрен классический способ работы с файлами в C/C++, основанный на библиотеке stdio.h и доступе к данным через структуру FILE . Альтернативный современный механизм работы с файлами в языке C++ на основе потоков и библиотек , , будет изучен .

Базовые функции для работы с файлами описаны в библиотеке stdio.h . Вся работа с файлом выполняется через файловую переменную - указатель на структуру типа FILE , определённую в стандартной библиотеке:

FILE *fp;

Открыть файл можно функцией fopen , имеющей 2 параметра:

FILE *fopen (char *имя_файла, char *режим_доступа)

Параметр имя_файла может содержать относительный или абсолютный путь к открываемому файлу:

1) "data.txt" - открывается файл data.txt из текущей папки

Важно : при запуске exe-файла "текущая папка" – та, где он находится; при отладке в IDE папка может быть иной, например, в Visual Studio при открытом консольном решении с именем Console файл следует разместить в папке Console/Console , а при запуске исполняемого файла не из IDE – в папке Console/Debug .

2) "f:\\my.dat" - открывается файл my.dat из головной папки диска f:

3) имя файла запрашивается у пользователя:

Char buf; printf ("\nвведите имя файла:"); fflush (stdin); gets (buf);

Параметр режим_доступа определяет, какие действия будут разрешены с открываемым файлом, примеры его возможных значений:

1) "rt" - открываем для чтения текстовый файл;

2) "r+b" - открываем для произвольного доступа (чтение и запись) бинарный файл;

3) "at" – открываем текстовый файл для добавления данных в конец файла;

4) "w" - открываем файл для записи без указания того, текстовый он или бинарный.

Фактически, указание "r" или "t" не накладывает каких-либо ограничений на методы, которые мы будем применять для чтения или записи данных.

После открытия файла следует обязательно проверить, удалась ли эта операция. Для этого есть 2 основных подхода:

1) стандартный обработчик ferror (см. пособиe, п.8.7);

2) сравнить указатель, который вернула fopen , с константой NULL (nullptr) из стандартной библиотеки:

Fp = fopen ("text.txt","r+b"); if (fp==NULL) { //Обработка ситуации "Не удалось открыть файл" }

Пример . Приложение проверяет, удалось ли открыть файл из текущей папки, имя файла запрашивается у пользователя (Visual Studio)

#include #include #include #include int main(void) { setlocale(LC_ALL,"Rus"); SetConsoleCP(1251); SetConsoleOutputCP(1251); FILE *fp; char buf; printf ("\nвведите имя файла:"); fflush (stdin); gets (buf); fp = fopen (buf,"r+b"); if (fp==NULL) { printf ("\nне удалось открыть файл"); getchar(); exit (1); //Выйти с кодом завершения 1 } fflush(stdin); getchar(); return 0; }

Важно ! Функции, возвращающие указатель, в том числе, fopen , считаются небезопасными в ряде новых компиляторов, например, Visual Studio 2015. Если их использование приводит не просто к предупреждению, а к генерации ошибок, есть 2 основных способа решения проблемы:

FILE *out; fopen_s(&out,"data.txt", "wt");

FILE *out = fopen_s("data.txt", "wt");

2) в начало файла (до всех #include) включить директиву

#define _CRT_SECURE_NO_WARNINGS

Если используется предкомпиляция, то можно определить этот макрос в заголовочном файле stdafx.h .

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

Если файл форматированный , то есть, является текстовым и состоит из лексем, разделённых стандартными разделителями (пробел, табуляция, перевод строки), обмен данными с ним можно выполнять методами:

  • fscanf - для чтения
  • fprintf - для записи

Первым параметром этих функций указывается файловая переменная, в остальном работа совпадает со стандартными scanf и printf .

Пример . Файл text.txt в текущей папке приложения имеет следующий вид:

1 1.5 -3.5 2 3.5

Прочитаем его как последовательность вещественных чисел.

FILE *fp = fopen ("text.txt","r"); if (fp==NULL) { printf ("\nне удалось открыть файл"); getchar(); exit (1); } float a; while (1) { fscanf (fp,"%f",&a); if (feof(fp)) break; //Если файл кончился, выйти из цикла //здесь выполняется обработка очередного значения a, например: printf ("%.2f ",a); } fclose(fp);

Важно !

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

Int i=fscanf (fp,"%f",&a); if (i!=1) { //не удалось получить 1 значение }

2. На "восприятие" программой данных может влиять установленная в приложении локаль. Например, если до показанного кода выполнен оператор

Setlocale(LC_ALL,"Rus"); результат работы кода может измениться (для русской локали разделителем целой и дробной части числа является запятая, а не точка).

3. Очередное чтение данных изменяет внутренний файловый указатель . Этот указатель в любой момент времени, пока файл открыт, показывает на следующее значение, которое будет прочитано. Благодаря этому наш код с "бесконечным" while не зациклился.

5. Распространённый в примерах из Сети код вида

While (!feof(fp)) { fscanf (fp,"%f",&a); //обработка числа a }

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

В качестве примера форматной записи в файл сохраним массив a из 10 целочисленных значений в файле с именем result.txt по 5 элементов в строке:

Const int n=10; int a[n],i; FILE *fp=fopen ("result.txt","wt"); if (fp==NULL) { puts ("не удалось открыть файл на запись"); getchar(); exit (1); } else { for (i=0; i

Важно ! Ввод/вывод функциями библиотеки stdio.h буферизован , то есть, данные "пропускаются" через область памяти заданного размера, обмен данными происходит не отдельными байтами, а "порциями". Поэтому перед чтением данных желательно очищать буфер от возможных "остатков" предыдущего чтения методом fflush , а после записи данных следует обязательно закрывать файл методом fclose , иначе данные могут быть потеряны. Заметим, что консольный ввод/вывод "обычными" методами scanf и printf также буферизован.

Теперь рассмотрим текстовый файл, состоящий из неструктурированных строк (абзацев) текста, разделённых символами перевода строки. При работе с такими данными могут потребоваться следующие функции:

  • fgetc и fputc - для посимвольного чтения и посимвольной записи данных;
  • fgets и fputs - для чтения и записи строк с указанным максимальным размером.

Как и в случае с функциями для чтения форматированных данных, у всех этих методов имеются аналоги для работы со стандартным вводом/выводом.

Пример . Читая файл, определить длину каждой строки в символах. Для решения задачи воспользуемся тем фактом, что строки завершаются символом "перевод строки" ("\n"). Предполагается, что файл уже открыт для чтения.

Int c; int len=0,cnt=0; while (1) { c=fgetc(fp); if (c=="\n") { printf ("\nString %d, length=%d",++cnt,len); len=0; } else len++; if (feof(fp)) break; } if (len) printf ("\nString %d, length=%d",++cnt,len);

Важно ! Из-за особенностей реализации fgetc , без последней проверки за телом цикла код мог "не обратить внимания", например, на последнюю строку файла, состоящую только из пробелов и не завершающуюся переводом строки.

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

Char buf; while (1) { fgets(buf,127,fp); if (feof(fp)) break; int len = strlen(buf); if (buf=="\n") buf="\0"; puts (buf); //Вывести прочитанные строки на экран }

Важно ! Без дополнительной обработки прочитанные из файла строки при выводе будут содержать лишние пустые строки между строками данных. Это происходит потому, что функция fgets читает строку файла вместе с символом перевода строки (точней, под Windows - с парой символов \r\n , интерпретируемых как один), а puts добавляет к выводимой строке ещё один перевод строки.

Если максимальная длина строки принципиально не ограничена, помочь может либо предварительное посимвольное чтение файла для её определения, либо работа с файлом как с бинарными данными. Бинарный файл отличается от текстового тем, что необязательно состоит из печатаемых символов со стандартными разделителями между ними. Соответственно, для него не имеет смысла понятие "строки данных", а основной способ работы с ним – чтение и запись наборов байт указанного размера. Основные функции для чтения и записи бинарных данных – fread и fwrite соответственно. В базовой реализации они имеют по 4 параметра:

  • void *buffer - нетипизированный указатель на место хранения данных;
  • size_t (unsigned) size - размер элемента данных в байтах.
  • size_t count - максимальное количество элементов, которые требуется прочитать (записать);
  • FILE *stream - указатель на структуру FILE

Пример . Целочисленный массив a запишем в двоичный файл.

FILE *fp=fopen ("data.dat","wb"); if (fp==NULL) { puts ("не удалось открыть файл"); getchar(); exit (1); } const int n=10; int a[n]; for(int i=0; i

Учитывая, что данные массива хранятся в последовательно идущих адресах памяти, цикл for для записи мы могли заменить одним оператором:

Fwrite (&a,sizeof(int),n,fp);

Подход к чтению данных с помощью fread аналогичен. Например, если файл уже открыт для чтения в режиме "rb":

Unsigned char c; //… fread (&c,1,1,fp); //читаем по 1 байту unsigned char buf; //… fread (&buf,1,512,fp); //читаем по 1 сектору - по 512 байт

Для файлов, открытых в режиме "r+b", разрешены и чтение, и запись (произвольный доступ). Поэтому при работе с такими файлами нужны функции позиционирования файлового указателя:

  • функции fgetpos и ftell позволяют выполнить чтение текущей позиции указателя в файле;
  • функции fseek и fsetpos позволяют осуществить переход к нужной позиции в файле.

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

Fseek (fp, 0, SEEK_END); //Встали на 0 байт от конца файла long int pos; pos = ftell (fp); //Получили текущую позицию в файле if (pos<0) puts ("\nОшибка"); else if (!pos) puts ("\nФайл пуст"); else printf ("\nВ файле %ld байт",pos);

Материал для чтения из пособия: пп. 8.6-8.11 . Обратите внимание на таблицы с описанными прототипами функций ввода/вывода.

Рекомендуемые задачи : базовое задание включает две задачи, первая из которых предполагает обработку файла как текстовых данных, вторая – как бинарных. В качестве дополнительной третьей задачи может быть предложена реализация одной из задач 1, 2, содержащая консольный интерфейс и меню.

Про conio.h и почему его не надо использовать:

Для ввода/вывода через цветную консоль во многих источниках используются методы библиотеки conio.h . Следует учитывать, что её реализации в компиляторах от Borland и Microsoft значительно отличаются, а в компиляторах под Unix/Linux реализации conio.h могут отсутствовать.

Как вариант, в компиляторах Visual Studio можно использовать аналоги conio.h от сторонних разработчиков, например, открытый проект . Законченный пример кода, реализующего несложное консольное меню для Visual Studio, есть . Предполагается, что к проекту подключены заголовочный файл coniow.h и файл исходного кода coniow.c .




Top