C fopen не открывает файл. Пример работы программы. Пример: исходный код программы
Функция fopen() открывает файл, имя которого указано аргументом fname, и возвращает связанный с ним указатель. Тип операций, разрешенных над файлом, определяется аргументом 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()
|
Если вы сталкиваетесь с проблемами во время чтения или записи файлов, и вы используете PHP в виде серверного модуля, убедитесь в том, что процесс сервера имеет доступ к файлам и директориям, которые вы используете.
]
FOPEN
#include
В лекции рассмотрен классический способ работы с файлами в 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
Важно ! Функции, возвращающие указатель, в том числе, 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 также буферизован. Теперь рассмотрим текстовый файл, состоящий из неструктурированных строк
(абзацев) текста, разделённых символами перевода строки. При работе с такими данными могут потребоваться следующие функции: Как и в случае с функциями для чтения форматированных данных, у всех этих методов имеются аналоги для работы со стандартным вводом/выводом. Пример
. Читая файл, определить длину каждой строки в символах. Для решения задачи воспользуемся тем фактом, что строки завершаются символом "перевод строки" ("\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 параметра: Пример
. Целочисленный массив 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", разрешены и чтение, и запись (произвольный доступ). Поэтому при работе с такими файлами нужны функции позиционирования файлового указателя: Пример
. Определить размер файла в байтах, предположим, что файл уже открыт в режиме чтения или произвольного доступа. 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 .