Как задать текстовый файл в c
Перейти к содержимому

Как задать текстовый файл в c

  • автор:

Как задать текстовый файл в c

Потоки для работы с текстовыми файлами представляют объекты, для которых не задан режим открытия ios::binary .

Запись в файл

Для записи в файл к объекту ofstream или fstream применяется оператор
#include #include int main() < std::ofstream out; // поток для записи out.open("hello.txt"); // открываем файл для записи if (out.is_open()) < out out.close(); std::cout

Здесь предполагается, что файла «hello.txt» располагается в одной папке с файлом программы. Данный способ перезаписывает файл заново. Если надо дозаписать текст в конец файла, то для открытия файла нужно использовать режим ios::app :

std::ofstream out("hello.txt", std::ios::app); if (out.is_open()) < out out.close();

Чтение из файла

Если надо считать всю строку целиком или даже все строки из файла, то лучше использовать встроенную функцию getline() , которая принимает поток для чтения и переменную, в которую надо считать текст:

#include #include #include // для std::getline int main() < std::string line; std::ifstream in("hello.txt"); // окрываем файл для чтения if (in.is_open()) < while (std::getline(in, line)) < std::cout > in.close(); // закрываем файл >

Также для чтения данных из файла для объектов ifstream и fstream может применяться оператор >> (также как и при чтении с консоли):

#include #include #include struct Point < Point(double x, double y): x, y <> double x; double y; >; int main() < std::vectorpoints< Point, Point, Point>; std::ofstream out("points.txt"); if (out.is_open()) < // записываем все объекты Point в файл for (const Point& point: points) < out > out.close(); std::vector new_points; std::ifstream in("points.txt"); // окрываем файл для чтения if (in.is_open()) < double x, y; while (in >> x >> y) < new_points.push_back(Point); > > in.close(); for (const Point& point: new_points) < std::cout >

Здесь вектор структур Point записывается в файл.

for (const Point& point: points)

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

0 0 4 5 -5 7

Используя оператор >>, можно считать последовательно данные в переменные x и y и ими инициализировать структуру.

double x, y; while (in >> x >> y) < new_points.push_back(Point); >

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

  • Глава 1. Введение в С++
    • Язык программирования С++
    • Первая программа на Windows. Компилятор g++
    • Первая программа на Windows. Компилятор Clang
    • Первая программа на Windows. Компилятор Microsoft Visual C++
    • Первая программа на Linux. Компилятор g++
    • Первая программа на MacOS. Компилятор Clang
    • Настройка параметров компиляции
    • Локализация и кириллица в консоли
    • Структура программы
    • Переменные
    • Типы данных
    • Константы
    • Ввод и вывод в консоли
    • using. Подключение пространств имен и определение псевдонимов
    • Арифметические операции
    • Статическая типизация и преобразования типов
    • Поразрядные операции
    • Операции присваивания
    • Условные выражения
    • Конструкция if-else и тернарный оператор
    • Конструкция switch-case
    • Циклы
    • Ссылки
    • Массивы
    • Многомерные массивы
    • Массивы символов
    • Введение в строки
    • Что такое указатели
    • Операции с указателями
    • Арифметика указателей
    • Константы и указатели
    • Указатели и массивы
    • Определение и объявление функций
    • Область видимости объектов
    • Параметры функции
    • Передача аргументов по значению и по ссылке
    • Константные параметры
    • Оператор return и возвращение результата
    • Указатели в параметрах функции
    • Массивы в параметрах функции
    • Параметры функции main
    • Возвращение указателей и ссылок
    • Перегрузка функций
    • Рекурсивные функции
    • Рекурсия на примере быстрой сортировки
    • Указатели на функции
    • Указатели на функции как параметры
    • Тип функции
    • Указатель на функцию как возвращаемое значение
    • Разделение программы на файлы
    • Внешние объекты
    • Динамические объекты
    • Динамические массивы
    • unique_ptr
    • shared_ptr
    • Определение классов
    • Конструкторы и инициализация объектов
    • Управление доступом. Инкапсуляция
    • Объявление и определение функций класса
    • Конструктор копирования
    • Константные объекты и функции
    • Ключевое слово this
    • Дружественные функции и классы
    • Статические члены класса
    • Деструктор
    • Структуры
    • Перечисления
    • Наследование
    • Управление доступом в базовых и производных классах
    • Скрытие функционала базового класса
    • Множественное наследование
    • Виртуальные функции и их переопределение
    • Преобразование типов
    • Динамическое преобразование
    • Особенности динамического связывания
    • Чистые виртуальные функции и абстрактные классы
    • Перегрузка операторов
    • Операторы преобразования типов
    • Оператор индексирования
    • Переопределение оператора присваивания
    • Пространства имен
    • Вложенные классы
    • Обработка исключений
    • Вложенные try-catch
    • Создание своих типов исключений
    • Тип exception
    • Типы исключений
    • Шаблоны функций
    • Шаблон класса
    • Специализация шаблона класса
    • Наследование и шаблоны классов
    • Типы контейнеров
    • Вектор
    • Итераторы
    • Операции с векторами
    • Array
    • List
    • Forward_list
    • Deque
    • Стек std::stack
    • Очередь std::queue
    • Очередь приоритетов std::priority_queue
    • Множества
    • Словарь std::map
    • Span
    • Определение строк
    • Строки с поддержкой Unicode
    • Преобразование типов и строки
    • Сравнение строк
    • Получение подстроки и проверка начала и конца строки
    • Поиск подстроки
    • Изменение строки
    • Операции с символами
    • Программа подсчета слов
    • Тип std:string_view
    • rvalue
    • Конструктор перемещения
    • Оператор присваивания с перемещением
    • Роль noexcept при перемещении
    • Объекты функций
    • Лямбда-выражения
    • Захват внешних значений в лямбда-выражениях
    • Шаблон std::function<>
    • Минимальный и максимальный элементы
    • Поиск элементов
    • Копирование элементов
    • Удаление элементов и идиома Remove-Erase Idiom
    • Сортировка
    • Представления. Фильтрация
    • Проекция данных
    • Пропуск элементов. drop_view и drop_while_view
    • Извлечение диапазона элементов. take_view и take_while_view
    • Цепочки представлений
    • Оператор requires
    • Концепты
    • Выражение requires
    • Ограничения типа для auto
    • Базовые типы для работы с потоками
    • Файловые потоки. Открытие и закрытие
    • Чтение и запись текстовых файлов
    • Переопределение операторов ввода и вывода
    • Математические константы и операции
    • Форматирование строк и функция format
    • std::optional
    • Управление ресурсами. Идиома RAII
    • Идиома копирования и замены
    • Идиома Move-and-Swap
    • Первая программа в Visual Studio
    • Первая программа в Qt Creator

    Помощь сайту
    410011174743222
    Перевод на карту
    Номер карты:
    4048415020898850

    Контакты для связи: metanit22@mail.ru

    Copyright © metanit.com, 2024. Все права защищены.

    Как задать текстовый файл в c

    Хотя функции getc()/putc() позволяют вносить в файл отдельные символы, но фактически мы имеем дело с бинарными файлами. Если мы записываем в файл строку, то в принципе мы даже можем открыть записанный файл любом текстовом редакторе и понять, что там было записано. Но не всегда данные могут представлять строки. И чтобы более наглядно разобраться с работой с бинарными файлами, рассмотрим еще одни пример - с записью-чтением структуры из файла.

    #include #include struct person < char name[16]; int age; >; int save(char * filename, struct person *p); int load(char * filename); int main(void) < char * filename = "person.dat"; struct person tom = < "Tom Smith", 21 >; save(filename, &tom); load(filename); return 0; > // запись структуры в файл int save(char * filename, struct person *p) < FILE * fp; char *c; int size = sizeof(struct person); // количество записываемых байтов fp = fopen(filename, "wb"); //открываем файл для бинарной записи if (!fp) // если не удалось открыть файл < printf("Error occured while opening file \n"); return 1; >// устанавливаем указатель на начало структуры c = (char *)p; // посимвольно записываем в файл структуру for (int i = 0; i < size; i++) < putc(*c++, fp); >fclose(fp); return 0; > // загрузка из файла структуры int load(char * filename) < FILE * fp; char *c; int i; // для считывания одного символа // количество считываемых байтов int size = sizeof(struct person); // выделяем память для считываемой структуры struct person * ptr = malloc(size); fp = fopen(filename, "rb"); // открываем файл для бинарного чтения if (!fp) < printf("Error occured while opening file \n"); return 1; >// устанавливаем указатель на начало блока выделенной памяти c = (char *)ptr; // считываем посимвольно из файла while ((i = getc(fp))!=EOF) < *c = i; c++; >fclose(fp); // вывод на консоль загруженной структуры printf("%-20s %5d \n", ptr->name, ptr->age); free(ptr); return 0; >

    В данном случае запись и чтение структуры выделены в отдельные функции: save() и load() соответственно.

    Для записи в функции save() через параметр struct person *p получаем указатель на сохраняемую структур. Фактически его значением является начальный адрес блока памяти, где располагается структура.

    Функция putc записывает отдельный символ в файл, однако нам надо записать структуру. Для этого мы создаем указатель на символ (который по сути представляет один байт) и устанавливаем этот указатель на начало блока памяти, выделенного для структуры.

    c = (char *)p;

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

    for (int i = 0; i

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

    При чтении файла в функции load() используется похожий принцип только в обратную сторону.

    Во-первых, для считывания структуры из файла мы выделяем блок динамической памяти для хранения прочитанных данных:

    struct person * ptr = (struct person *) malloc(size);

    После этого указатель ptr будет указывать на первый адрес блока из 20 байт (наша структура занимает 20 байт = 16 символов и 4 байта для числа int ).

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

    c = (char *)ptr; // считываем посимвольно из файла while ((i = getc(fp))!=EOF)

    Здесь стоит обратить внимание на то, что в данном случае на самом деле считываем даже не символ, а числовой код символа в переменную типа int и только потом передаем значение указателю c. Это сделано для корректной обработки окончания файла EOF. Это значение может представлять любое отрицательное число. И если бы мы сохранили отрицательное число (например, возраст пользователя был бы отрицательным), то оно было бы некорректно интерпретировано при чтении как конец файла, и итоговый результа был бы неопределенным. Поэтому более правильно считывать именно числовой код символа в переменную int, а затем числовой код передавать в char.

    Запись и чтение массива структур

    Выше приведен пример по работе с одной структурой. Но, как правило, при работе с файлами мы оперируем не одной структурой, а каким-то набором структур. Поэтому усложним задачу и сохраним и считаем из файла массив структур:

    #include #include struct person < char name[20]; int age; >; int save(char * filename, struct person *st, int n); int load(char * filename); int main(void) < char * filename = "people.dat"; struct person people[] = < , , , >; int n = sizeof(people) / sizeof(people[0]); save(filename, people, n); load(filename); return 0; > // запись в файл массива структур int save(char * filename, struct person * st, int n) < char *c; // для записи отдельных символов // число записываемых байтов int size = n * sizeof(struct person); FILE * fp = fopen(filename, "wb"); if (!fp) < printf("Error occured while opening file\n"); return -1; >// записываем количество структур c = (char *)&n; for (int i = 0; i < sizeof(n); i++) < putc(*c++, fp); >// посимвольно записываем в файл все структуры c = (char *)st; for (int i = 0; i < size; i++) < putc(*c, fp); c++; >fclose(fp); return 0; > // загрузка из файла массива структур int load(char * filename) < char *c; // для считывания отдельных символов int m = sizeof(int); // сколько надо считать для получения размера массива int n; // количество структур в массиве FILE * fp = fopen(filename, "r"); if (!fp) < printf("Error occured while opening file\n"); return -1; >// выделяем память для хранения количества данных int *ptr_count = malloc(m); // считываем количество структур c = (char *)ptr_count; // пока не считаем m байт, сохраняем байт в выделенный блок для размера массива while (m > 0 && (*c = getc(fp)) != EOF) < c++; m--; >//получаем число элементов n = *ptr_count; free(ptr_count); // освобождаем память // выделяем память для считанного массива структур struct person * ptr = malloc(n * sizeof(struct person)); // устанавливаем указатель на блок памяти, выделенный для массива структур c = (char *)ptr; // считываем посимвольно из файла while ((*c= getc(fp))!=EOF) < c++; >// перебор загруженных элементов и вывод на консоль printf("\nFound %d people\n\n", n); for (int i = 0; i < n; i++) < printf("%-5d %-10s %5d \n", i + 1, (ptr + i)->name, (ptr + i)->age); // или так // printf("%-5d %-10s %5d \n", i + 1, ptr[i].name, ptr[i].age); > free(ptr); fclose(fp); return 0; >

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

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

    c = (char *)&n; for (int i = 0; i

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

    // посимвольно записываем в файл все структуры c = (char *)st; for (int i = 0; i

    При чтении нам придется файктически считывать из файла два значения: количество структур и их массив. Поэтому при чтении два раза выделяется память. Вначале для количества элементов:

    int *ptr_count = malloc(m);

    Затем мы считываем первые 4 байта из файла для получения числа:

    c = (char *)ptr_count; while (m > 0 && (*c = getc(fp)) != EOF) < c++; m--; >//получаем число элементов n = *ptr_count;

    Затем аналогичные действия проделываем для массива структур.

    struct person * ptr = malloc(n * sizeof(struct person)); // устанавливаем указатель на блок памяти, выделенный для массива структур c = (char *)ptr; // считываем посимвольно из файла while ((*c= getc(fp))!=EOF)

    И результатом программы должен быть вывод считанных данных:

    Found 4 people 1 Tom 23 2 Alice 27 3 Bob 31 4 Kate 29

    Как задать текстовый файл в c

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

    Запись текстового файла

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

    int fputs(const char *s, FILE *stream);

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

    При записи строки нулевой символ '\0' в файл не записывается.

    Например, запишем строку в файл:

    #include int main(void) < // строка для записи char * message = "Hello METANIT.COM!\nAn apple a day keeps the doctor away"; // файл для записи char * filename = "data.txt"; // запись в файл FILE *fp = fopen(filename, "w"); if(fp) < // записываем строку fputs(message, fp); fclose(fp); printf("File has been written\n"); >>

    Запись довольно проста: открываем файл на запись и с помощью вызова fputs(message, fp) записываем в файл искомую строку.

    Чтение текстового файла

    Функция fgets() считывает из файла одну строку и имеет следующий прототип:

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

    Первый параметр char *s представляет строку, в которую производится считывание. Второй параметр - число n указывает, сколько символов необходимо считывать. И третий параметр представляет файловый поток, из которого производится считывание.

    При вызове функция считывает из файла не более n-1 символов. Функция прекращает чтение, когда прочтет n-1 символов или встретит символ переноса строки \n. Все считанные символы записываются в строку s, в том числе символ \n. И также конец каждой строки дописывается нулевой символ '\0'.

    При успешном завершении функция возвращает указатель s , а при ошибке или достижении конца файла возвращается значение NULL .

    Считаем данные из выше записанного файла "data.txt":

    #include int main(void) < // файл чтения char * filename = "data.txt"; // буфер для считавания данных из файла char buffer[256]; // чтение из файла FILE *fp = fopen(filename, "r"); if(fp) < // пока не дойдем до конца, считываем по 256 байт while((fgets(buffer, 256, fp))!=NULL) < printf("%s", buffer); >fclose(fp); > >

    Здеcь открываем файл на чтение и в цикле считываем из файла по 256 символов и выводим их на консоль с помощью вызова fgets(cc, 256, fp) . Когда данные в файле закончатся, функция возвратит NULL, и произойдет выход из цикла.

    Копирование файлов

    Другой пример работы с текстовыми файлами - копирование содержимого из одного файла в другой:

    #include int main(void) < char * filename1 = "data1.txt"; char * filename2 = "data2.txt"; char buffer[256]; FILE *f1 = fopen(filename1, "r"); // файл на чтение FILE *f2 = fopen(filename2, "w"); // файл на запись if(!f1 || !f2) < printf("Error occured while opening file\n"); >else < // пока не дойдем до конца, считываем по 256 байт из файла f1 while((fgets(buffer, 256, f1))!=NULL) < // записываем строку в файл f2 fputs(buffer, f2); printf("%s", buffer); >> fclose(f1); fclose(f2); return 0; >

    Редактирование текстового файла произвольного размера в C/C++

    Например, файл 1.txt содержит информацию "123456789**" Как убрать звёздочки? В конце должно получиться "123456789". Как правильно редактировать файл 1.txt, не создавая другой файл?

    Отслеживать
    51.4k 87 87 золотых знаков 267 267 серебряных знаков 508 508 бронзовых знаков
    задан 9 мая 2011 в 14:54
    alexl1720p alexl1720p
    109 2 2 золотых знака 3 3 серебряных знака 12 12 бронзовых знаков

    4 ответа 4

    Сортировка: Сброс на вариант по умолчанию

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

    #include #include #include main (int ac, char *av[]) < if (ac < 2) < printf ("No filename\n"); exit(1); >int i = 0, c; FILE *in = fopen(av[1],"r"), *out = fopen(av[1],"r+"); if (in == NULL || out == NULL) < perror (av[1]); exit(2); >rewind(out); while ((c = fgetc(in)) != EOF) < if (c != '*') < i++; fputc(c,out); >> fclose(in); ftruncate(fileno(out),i); fclose(out); > 

    Отслеживать
    ответ дан 9 мая 2011 в 20:07
    46.1k 6 6 золотых знаков 48 48 серебряных знаков 116 116 бронзовых знаков

    Уважаемый avp, напишите пожалуйста для особо непонятливых программу сразу готовую для конпилеации. а то я запутался в FILE *in = fopen(av[1],"r"), *out = fopen(av[1],"r+"); и невьехал как работает ftruncate (((

    9 мая 2011 в 21:26

    Программа компилировалась gcc в MinGW и Interix. FILE *in = fopen("имя файла","r") открывает связывает переменную in с потоком для чтения. FILE *out = (. "r+") аналогично для записи в этот же файл. "r+" вообще-то открывает файл как для чтения, так и для записи НЕ УРЕЗАЯ ЕГО ПРИ ОТКРЫТИИ. В некоторых реализациях для перехода к операциям записи требуется seek() (rewind()). В переменной i подсчитывается количество байт, которые записали в файл (не *). ftruncate() (см. man 2 ftruncate) урезает файл до нужного размера. Она требует файловый дескриптор, получаем его по fileno(out). Все !

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *