Основные функции обработки файлов

Функция удаления файла

Синтаксис:

int remove(const char *filename);

Эта функция удаляет с диска файл, указатель на который хранится в файловой переменной filename. Функция возвращает ненулевое значение, если файл невозможно удалить.

Функция переименования файла

Синтаксис:

int rename(const char *oldfilename, const char *newfilename);

Функция переименовывает файл; первый параметр – старое имя файла, второй – новое. Возвращает 0 (NULL) при неудачном выполнении.

Функция контроля конца файла

Для определения конца файлового потока используется функция feof(), прототип которой описан в заголовочном файле <stdio.h>. Функция возвращает истину (1), если внутренний указатель заданного файлового потока находится за последним байтом файла (достигнут конц файла – EOF), и ложь (0), если внутренний указатель находится не в конце файла.

int feof(FILE * filename);

Пример: определить количество отрицательных элементов в файле Neg.dat

#include <stdio.h>

#include <stdlib.h>

void main(){

FILE *f_n;

int kol_vo = 0; // количество «-« элементов

int value;

randomize();

f_n = fopen(“Neg.dat”, ”rb) // чтение в двоичном режиме

if(!f_n) // если указатель равен 0 (не связался)

{puts(“Нельзя открыть файл!\n”);

exit(1);

}

while (!foef(f_n)); // пока не конец файла

{fread(&value, sizeof(int), 1, f_n);

if(value < 0) kol_vo++;

}

printf(“Количество «-« элементов = %d\n”, kol_vo);

fclose(f_n);

}

Функции ввода-вывода данных файла

Для использования функций ввода/вывода в стиле С необходимо подключить к программе заголовочный файл <stdio.h> или <cstdio>, в которых описан формат стандартных файлов ввода/вывода. Имена стандартных файлов ввода/вывода для языка представлены в табл.2. При вводе/выводе данные рассматриваются как поток байтов. В момент начала выполнения программы на языке С автоматически открываются три потока: stdin, stdout, stderr.

Таблица 2. Потоки, определяемые в языке С.

Имя стандартного файла Описание
stdaux Последовательный ввод/вывод
stderr Выходной поток ошибок
stdin Стандартный ввод
stdout Стандартный вывод
stdprn Вывод на принтер

По умолчанию стандартному потоку ввода stdin ставится в соответствие клавиатура, а потокам stdout и stderr соответствует экран монитора.

Ввод/вывод в поток можно осуществлять различными способами:

- в виде последовательности байтов;

- в виде символов и строк;

- с использованием форматных преобразований.

Для каждого вида операций определен свой набор функций.

Операции ввода/вывода выполняются начиная с текущей позиции потока, определяемой положением указателя потока. Указатель устанавливается при открытии на начало или конец файла (в соответствии с режимом открытия) и изменяется автоматически после каждой операции ввода/вывода. Текущее положение указателя можно получить с помощью функций ftell()и fgetpos()и задать явным образом с помощью функций fseek()и fsetpos().Эти функции нельзя использовать для стандартных потоков. Ниже перечислены основные функции ввода/вывода потока (см. табл.3).

Таблица 3. Основные функции ввода/вывода потока.

Название Назначение
В виде последоватеьности байтов
fread Чтение потока байтов
fwrite Запись потока байтов
В виде символов и строк
getc, fgetc Чтение символа из потока
getchar Чтение символа из стандартного потока stdin
putc, fputc Запись символа в поток
putchar Запись символа в стандартный поток stdout
fgets Чтение строки из потока
gets Чтение строки из стандартного потока stdin
fputs Запись строки в поток
puts Запись строки в стандартный поток stdout
С форматированием
fscanf Форматированный ввод из потока
scanf Форматированный ввод из стандартного потока stdin
sscanf Форматированный ввод из строки
fprintf Форматированный вывод в поток
printf Форматированный вывод в стандартный поток stdout
sprintf Форматированный вывод в строку

1) Символьный ввод-вывод

Для символьного ввода-вывода используются функции:

int fgetc(FILE *fp);

где fp – указатель на поток, из которого выполняется считывание.

Функция возвращает очередной символ в формате int из потока fp. Если символ не может быть прочитан, то возвращается значение EOF.

int fputc(int c, FILE*fp);

где fp– указатель на поток, в который выполняется запись;

c – переменная типа int, в которой содержится записываемый в поток символ.

Функция возвращает записанный в поток fp символ в формате int. Если символ не может быть записан, то возвращается значение EOF.

Пример.

#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ FILE *f; int c; char *filename="t.txt"; if ((f=fopen(filename,"r"))==0) perror(filename); else while((c = fgetc(f)) != EOF) putchar(c); //вывод с на стандартное устройство вывода fclose(f); system("pause"); return 0;}

2) Строковый ввод-вывод

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

char *fgets(char *s, int n, FILE *f);

где char *s– адрес, по которому размещаются считанные байты;

int n– количество считанных байтов;

FILE *f– указатель на файл, из которого производится считывание.

Прием байтов заканчивается после передачи (n-1) байтов или при получении управляющего символа '\n'. Управляющий символ тоже передается в принимающую строку. Строка в любом случае заканчивается '\0'. При успешном завершении считывания функция возвращает указатель на прочитанную строку, при неуспешном – 0.

int fputs(char *s, FILE *f);

где char *s– адрес, из которого берутся записываемые в файл байты;

FILE *f– указатель на файл, в который производится запись.

Символ конца строки ( '\0' ) в файл не записывается. Функция возвращает EOF, если при записи в файл произошла ошибка, при успешной записи возвращает неотрицательное число.

Пример. Построчное копирование данных из файла f1.txtв файл f2.txt.

#include "stdafx.h"#include <iostream>using namespace std;#define MAXLINE 255 //максимальная длина строкиint _tmain(int argc, _TCHAR* argv[]){//копирование файла in в файл out FILE *in, //исходный файл *out; //принимающий файл char buf[MAXLINE]; //строка, с помощью которой выполняется копирование in=fopen("f1.txt","r"); //открыть исходный файл для чтения out=fopen("f2.txt","w"); //открыть принимающий файл для записи while(fgets(buf, MAXLINE, in)!=0) //прочитать байты из файла in в строку buf fputs(buf, out); //записать байты из строки buf в файл out fclose(in); //закрыть исходный файл fclose(out);//закрыть принимающий файл system("pause"); return 0;}

3) Ввод-вывод блоками

Для блокового ввода-вывода используются функции:

int fread(void *ptr, int size, int n, FILE *f);

где void *ptr– указатель на область памяти, в которой размещаются считанные из файла данные;

int size– размер одного считываемого элемента;

int n– количество считываемых элементов;

FILE *f– указатель на файл, из которого производится считывание.

В случае успешного считывания функция возвращает количество считанных элементов, иначе – EOF.

int fwrite(void *ptr ,int size, int n, FILE *f);

где void *ptr– указатель на область памяти, в которой размещаются считанные из файла данные;

int size– размер одного записываемого элемента;

int n– количество записываемых элементов;

FILE *f– указатель на файл, в который производится запись.

В случае успешной записи функция возвращает количество записанных элементов, иначе – EOF.

Пример.

#include "stdafx.h"#include <iostream>using namespace std;struct Employee {char name[30]; char title[30]; float rate; };int _tmain(int argc, _TCHAR* argv[]){ Employee e; FILE *f; if((f=fopen("text.dat","w"))==NULL) { printf("\nФайл не открыт для записи"); } int n; //запись в файл printf("\nВведите количество записей N="); scanf("%d",&n); for(int i=0;i<n;i++) { //формируем структуру е printf("имя:");scanf("%s",&e.name); printf("наименование:");scanf("%s",&e.title); printf("налог:");scanf("%f",&e.rate); //записываем е в файл fwrite(&e,sizeof(Employee),1,f); } fclose(f); //чтение из файла if((f=fopen("text.dat","rb"))==NULL) printf("\nФайл не открыт для чтения"); while(fread(&e,sizeof(Employee),1,f)) printf("%s, %s, %f;\n", e.name, e.title, e.rate); fclose(f); system("pause"); return 0;}

4) Форматированный ввод-вывод

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

int fprintf(FILE *f, const char *fmt, par1, par2, ...);

где FILE*f– указатель на файл, в который производится запись;

const char *fmt– форматная строка;

par1, par2, ... – список переменных, в которые заносится информация из файла.

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

int fscanf(FILE *f, const char *fmt, &par1, &par2, ...);

где FILE*f– указатель на файл, в который производится запись;

const char *fmt– форматная строка;

par1, par2, ... – список переменных, из которых считывается информация в файл.

Пример.

#include "stdafx.h"#include <iostream>using namespace std;int _tmain(int argc, _TCHAR* argv[]){ FILE *f; int n, nn,m; if((f=fopen("int.dat","w"))==0) perror("int.dat"); for(n=1;n<11;n++) fprintf(f, "\n%d %d", n, n*n); fclose(f); if ((f=fopen("int.dat","r"))==0) perror("int.dat"); m=1; while(fscanf(f, "%d %d",&n, &nn)&& m++<11) printf("\n%d %d",n,nn); fclose(f); system("pause"); return 0;

3.2.2 Особенности работы с текстовыми файлами:

Текстовый файл состоит из последовательности символов, разбитой на строки путем использования управляющего символа \n.

Способы обработки:

- посимвольная

- или построчная обработка.

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

Основные методы обработки текстовых файлов.

Используется только последовательный метод доступа, который обеспечивается функциями fprintf() и fscanf()

Файловые функции ввода/вывода fprintf() и fscanf() работают аналогично printf() и scanf(), но имеют дополнительный аргумент, являющийся указателем на файловый поток.

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

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

void main(){

FILE *f;

int dig;

if (f = fopen(“inp_f”, ”r”) == NULL) //открыть файл для чтения

{ printf(“Невозможно открыть файл!\n”);

exit(0);

}

fscanf(f, “%d”, &dig); // считать значение dig из файла

fclose(f); // закрыть файл

f = fopen(“out_f”, “w”);// открыть др. файл для записи

fprintf(f, “Прочитано число %d”, dig);

fclose(f); // закрыть файл

}

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

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

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#include <string.h>

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

FILE *f_in, *f_out;

int ch;

char *name; // имя входного файла

int count = 0; // счетчик элементов

if (argc<2) // в командной строке нет имени

{ printf(“Введите имя входного файла”);

gets(name);

}

else name = argv[1]; // взять имя из командной строки

if ((f_in = fopen(name, ”r”))!= NULL) //открыть файл для чтения

{ strcat(name, “.out”); // добавляет расширение .out к

// имени файла

f_out = fopen(name, ”w”); // открывает файл для записи

while((ch = fgetc(f_in)!=EOF)

if(count++%3 == 0)

fputc(ch, f_out); // выводит каждый 3-й символ

fclose(f_in);

fclose(f_out);

}

else printf(“Невозможно открыть файл!\n”);

}

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

Рассмотрим построчное чтение информации из входного файла и вывод ее на экран как на стандартное устройство вывода.

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#include <string.h>

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

FILE *f_in;

char buffer[256]; // максимальная длина строки - 255 символов

char *name; // имя входного файла

if (argc<2) // в командной строке нет имени

{ printf(“Введите имя входного файла”);

gets(name);

}

else name = argv[1]; // взять имя из командной строки

if ((f_in = fopen(name, ”r”))!= NULL) //открыть файл для чтения

{ while(fgets(buffer, 255, f_in))!= NULL)

{fputs(buffer, stdout);

fputs(‘\n’, stdout);

}

fclose(f_in);

else printf(“Невозможно открыть файл!\n”);

}

В цикле while присутствуют две файловые функции работы со строками: fgets() – для чтения строки символов и fputs() – для записи содержимого буфера в файл

Кроме того, вывод текстового файла буферизован. Это значит, что в тот момент, когда работает оператор записи в файл, фактическая запись может не происходить, поскольку реально сначала идет заполнение данными текстового буфера, а потом его содержимое записывается на диск. Запись буфера происходит как только он окажется полностью заполненным или при выполнении специальных команд принудительной записи на диск. Процесс записи недозаполненнгого буфера на диск называется флэшированием и обычно выполняется с помощью функции fflush(f_out).При необходимости завершить работу сразу со всеми открытыми файлами пользуются функцией flushall().

Закрытие файла посредством функции fclose(f_out) также включает процесс флэширования, т.е. перенос информации из буфера на диск.

Пример. Допустим, что в файле хранятся сведения о мониторах. В каждой строке указан тип, оптовая и розничная цены и примечание. Для простоты данные в каждой строке записаны единообразно (совокупность строк – таблица): первые 20 символов занимает тип монитора, далее по 5 символов целые числа, представляющие цены, затем примечание длиной не более 40 символов.

Приведенная ниже программа построчно считывает данные из текстового файла в буферную переменную s, затем формирует из них структуру mon (таблицу) и записывает ее в двоичном режиме в выходной файл. Далее производится считывание из этого файла произвольной записи.

#include <iostream.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

int main()

FILE *fi, *fo;

if ((fi = fopen(“d:\\c\\file.txt”, “r”)) == 0){

cout << “Ошибка открытия входного файла”; return 1;}

if ((fo = fopen(“d:\\c\\binfile.out”, “w+b”)) == 0){

cout << “Ошибка открытия выходного файла”; return 1;}

const int dl = 80;

char s [dl];

struct{

char type [20];

int opt, rozn;

char comm[40];} mon;

int kol = 0; // количество записей в файле

while (fgets (s, dl, fi)){

// преобразование строки в структуру

strcnpy(mon.type, s, 19);

mon.type[19]=’\0’;

mon.opt = atoi(&s[20]);

mon.rozn = atoi(&s[25]);

strcnpy(mon.comm, &s[30], 40);

fwrite(&mon, sizeof mon, 1, fo);

kol++;

}

fclose(fi);

int i; cin >>i; // номер записи

if (i >= kol){ cout << “Запись не существует”; return 1;}

// установка указателя текущей позиции файла на запись i:

fseek (fo, (sizeof mon)*i, SEEK_SET);

fread (&mon, sizeof mon,1, fo);

cout << “type” << mon.type <<”opt” << mon.opt

<< “rozn” << mon.rozn << endl;

flose (fo);

return 0;

}

Наши рекомендации