Создание файла txt и запись в него C++?
прочитал ,что метод open создает файл ,если такого нету , но по факту ничего не создается . Видел ,что обьявляют классом ifstream , но мне нужен будет этот файл потом для записи ,а переопределить нельзя ,поэтому надо использовать fstream.
- Вопрос задан более двух лет назад
- 4202 просмотра
1 комментарий
Простой 1 комментарий
edward_freedom @edward_freedom
пробел ставится перед знаками препинания, а не после
Решения вопроса 1
Developer, ex-admin
Смотри сначала сюда: https://en.cppreference.com/w/cpp/io/basic_fstream
Потом сюда: https://en.cppreference.com/w/cpp/io/basic_filebuf/open
fstream открывает файл по умолчанию (как у тебя) в режиме in|out, а это значит, что если файла не существует, то возникает ошибка (смотри таблицу по второй ссылке). Логика такая, что если ты открываешь файл для чтения (тут не важно, что он открывается еще и для записи) без дополнительных флагов, то файл должен существовать.
В пару с ifstream, который открывает файл для чтения, существует и ofstream — он открывает файл для записи. При использовании ofstream не существующий файл будет создан (смотри таблицу по второй ссылке).
Как создать файл и папки по пути к нему
Как создать папки по пути к файлу, если из нет.
А также как создать файл, если его нет, а если есть — дописать в его конец.
Также, поскольку я использую C++11, я не могу использовать std::filesystem или std::experimental . У меня сейчас так:
#ifndef DEBUGGER_HPP #define DEBUGGER_HPP #include #include #include #include "../Main/Settings.hpp" namespace Debugger < // void PrintDebug(const std::string input)< if (Settings::settings_DebugMode >= 2) < // Add current datetime auto seconds = time(NULL); auto* timeinfo = localtime(&seconds); std::string result = "[DEBUG] [ "; result += asctime(timeinfo); result.erase(result.rfind('\n'), 1); result += " ] " + input + '\n'; if (Settings::settings_LogPath == "console")< std::cout else < // Create folder if it doesn't exist for(std::string::size_type pos = 0; (pos = Settings::settings_LogPath.find('/',pos+1)) != std::string::npos;) < mkdir(Settings::settings_LogPath.substr(0,pos).c_str()); >// Create logFile std::ofstream logFile; logFile.open("log.txt", std::ios::app); logFile > > > #endif // DEBUGGER_HPP
Отслеживать
Alrott SlimRG
задан 31 авг 2020 в 13:04
Alrott SlimRG Alrott SlimRG
1,567 9 9 серебряных знаков 38 38 бронзовых знаков
Вы можете разбить путь на составляющие и рекурсивно создать каталоги, начиная с корневого, проверяя есть ли он уже.
31 авг 2020 в 13:11
@timur я же поставил тег «кроссплатформенность»
31 авг 2020 в 13:12
31 авг 2020 в 13:15
Если используется Qt, то папки можно создать через QDir::mkpath а наличие проверить через QFile::exists
31 авг 2020 в 13:22
Используйте Boost.Filesystem или другую специальную библиотеку, если нет доступа к
31 авг 2020 в 13:24
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Отвечу по поводу создания нескольких директорий, вложенных друг в друга, à la mkdir -p . Это популярный запрос, как выяснилось. Есть программы, написанные для создания директорий рекурсивно, например здесь: http://mylinuxtechcorner.blogspot.com/2012/09/c-version-for-mkdir-p.html
Привожу код оттуда:
int createPath( mode_t mode, const std::string& rootPath, std::string& path ) < struct stat st; for( std::string::iterator iter = path.begin() ; iter != path.end(); ) < std::string::iterator newIter = std::find( iter, path.end(), '/' ); std::string newPath = rootPath + "/" + std::string( path.begin(), newIter); if( stat( newPath.c_str(), &st) != 0) < if( mkdir( newPath.c_str(), mode) != 0 && errno != EEXIST ) < std::cout > else if( !S_ISDIR(st.st_mode) ) < errno = ENOTDIR; std:: cout else std::cout return 0; > int main() < std::string path = "ionut/AAA/BBB"; createPath(0777, "/home", path); return 0; >
Отслеживать
ответ дан 31 авг 2020 в 13:13
1,510 9 9 серебряных знаков 18 18 бронзовых знаков
Не очень понятно, почему явно итеративный способ называют рекурсивным?
31 авг 2020 в 17:00
@avp алгоритм итеративный, но применительно к директориям говорят же recursive, например man ls(1): -R: Recursively list subdirectories encountered.
31 авг 2020 в 21:29
Также такое можно сказать про find, grep . Но это обход дерева рекурсивный. В данном случае же, очевидно, строго линейная итерация по заданным компонентам пути
31 авг 2020 в 21:31
@avp No problem, изменил формулировку.
31 авг 2020 в 21:37
Грустно, что нельзя использовать что-то кроме С++11.
Тогда посоветовал бы разбивать путь на составные куски по слешу, и использовать mkdir для покусочного 🙂 создания пути (насколько я помню, длинные вложенные каталоги он не создает — типа, log/test не создаст, если нет log ).
Ну, а когда путь есть и вы в этом убедились — обычные функции для работы с файлами. Например,
ofstream of("data",ios::app); of
Если файла нет - он будет создан, если есть - будет выполнена дозапись в его конец.
Разбивать на части? Да хоть так:
string logPath = "My/Long/Log/path/"; for(string::size_type pos = 0; (pos = logPath.find('/',pos+1)) != string::npos;)
Понятно, что вместо вывода строки надо использовать mkdir . Рекурсия особо не нужна, если каталог уже есть - попытка его создать к неприятностям не приведет.
С/С++ на Linux в Visual Studio Code для начинающих
Давайте начистоту, мало кто использует отладчик GDB на Linux в консольном варианте. Но что, если добавить в него красивый интерфейс? Под катом вы найдёте пошаговую инструкцию отладки кода С/С++ на Linux в Visual Studio Code.

Передаю слово автору.
Относительно недавно я переехал на Linux. Разрабатывать на Windows, конечно, удобнее и приятнее, но и здесь я нашел эффективный способ легко и быстро отлаживать код на С/С++, не прибегая к таким методам как «printf-стайл отладки» и так далее.
Итак приступим. Писать в sublime (или gedit/kate/emacs ), а запускать в терминале — так себе решение, ошибку при работе с динамическим распределением памяти вряд ли найдёшь с первого раза. А если проект трудоёмкий? У меня есть более удобное решение. Да и ещё поддержка Git в редакторе, одни плюсы.
Сегодня мы поговорим про Visual Studio Code.
Установка
Ubuntu/Debian
- Качаем версию пакета VS Code с расширением .deb
- Переходим в папку, куда скачался пакет (cd ~/Загрузки или cd ~/Downloads)
- Пишем, где (имя пакета).deb — название файла, который вы только что скачали:
sudo dpkg -i (имя пакета).deb sudo apt-get install -f
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc sudo sh -c 'echo -e "[code]\nname=Visual Studio Code\nbaseurl=https://packages.microsoft.com/yumrepos/vscode\nenabled=1\ntype=rpm-md\ngpgcheck=1\ngpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/zypp/repos.d/VScode.repo'
sudo zypper refresh sudo zypper install code
Расширения для С/С++
Чтобы VS Code полностью сопровождал нас при работе с файлами С/С++, нужно установить расширение «cpptools». Также полезным будет поставить один из наборов сниппетов.

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

Идём дальше. Открываем любую папку (новую или нет, неважно).

У меня в этой папке уже есть пара файлов для работы с C/C++. Вы можете скопировать одну из своих наработок сюда или создать новый файл.

Осталось всего ничего. Настроить компиляцию в одну клавишу и научиться отлаживать без printf .
Шаг 1. Открываем файл .c/.cpp, который (обязательно) лежит в вашей папке.
Шаг 2. Нажимаем Ctrl+Shift+B. VS Code вам мягко намекнет, что он не знает как собирать ваш проект.

Шаг 3. Поэтому дальше настраиваем задачу сборки: выбираем «Настроить задачу сборки» -> «Others».
Шаг 4. Прописываем конфигурацию в соответствии с образцом. По сути мы пишем скрипт для консоли, так что всем кто имел дело с ней будет понятно дальнейшее. Прошу заметить, что для сборки исходников в системе должен стоять сам компилятор (gcc или другой, отличаться будет только значение поля command ). Поэтому для компиляции .cpp, понадобится в поле command указать g++ или c++ , а для .c gcc .
Шаг 5. В args прописываем аргументы, которые будут переданы на вход вашему компилятору. Напоминаю, что порядок должен быть примерно таким: -g, .
Внимание: Если в вашей программе используется несколько файлов с исходным кодом, то укажите их в разных аргументах через запятую. Также обязательным является ключ -g (а лучше даже -g3 ). Иначе вы не сможете отладить программу.
Если в проекте для сборки вы используете makefile , то в поле command введите make , а в качестве аргумента передайте директиву для сборки.

Шаг 6. Далее возвращаемся обратно к нашему исходнику. И нажимаем F5 и выбираем C++.

Шаг 7. Осталось только написать путь к файлу программы. По умолчанию это $/a.out , но я в своем файле сборки указал флаг -o и переименовал файл скомпилированной программы, поэтому у меня путь до программы: $/main .

Шаг 8. Всё, больше нам не нужно ничего для начала использования всех благ VS Code. Переходим к основному проекту.
Отладка
Для начала скомпилируем программу (нет, нет, убери терминал, теперь это делается по нажатию Ctrl+Shift+B).

Как вы видите в проводнике появился main , значит все в порядке и сборка прошла без ошибок. У меня не слишком большая программа, но выполняется она моментально. Одним словом, провал чистой воды, потому что отладка идет в отдельном терминале, который закрывается после того, как программа дошла в main() до "return 0;" .

Пришло время для брейкпоинтов. Выберем строчку с "return 0;" и нажимаем F9.

Строчка, помеченная красной точкой слева — место, где остановится программа, при выполнении.
Далее нажимаем F5.

Как я и сказал, программа остановила выполнение. Обратите внимание на окно с локальными переменными.

Удобненько. Также при остановке можно наводить мышкой на переменные и структуры в коде и смотреть их значения.

Также, если на каком-то этапе выполнения вам нужно посмотреть пошаговое выполнение той или иной операции, например в цикле, то поставьте брейкпоинт перед ней и нажмите F10 для выполнения текущей строчки без захода в подпрограмму и F11 с заходом.
Также есть случаи, когда считать выражение очень муторно вручную, но для отладки вам нужно знать, например, значение суммы трех элементов массива, или значение большого логического выражения. Для этого существуют контрольные значения. Все это и многое другое могут показать вам Контрольные значения (или «watch»).

- Для каждой папки вам нужно отдельно настроить файлы сборки и путь к программе.
- VS Code не решит ваших проблем, но поможет быстрее с ними разобраться. Причем в разы.
- После каждого изменения программы, ее нужно компилировать заново, нажимая Ctrl+Shift+B.
Об авторе

Максимилиан Спиридонов — разработчик C#, студент МАИ, Microsoft Student Partner. В профессиональную разработку на .NET пришёл ещё в школе. Около года работал с реальными проектами на WPF(MVVM)+C#, MySQL, более 4-х лет разрабатывал на C#. Основная сфера интересов сейчас — это мобильная разработка на Xamarin. Также, по воле случая в сфере интересов оказались С/С++ и Linux.
- Блог компании Microsoft
- C++
- Visual Studio
- C
- Разработка под Linux
Как создать файл 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. Если же нам надо записать и затем считать строку, которая содержит пробелы, и какие-то другие данные, то такой способ, конечно, не сработает.
