Подтвердить что ты не робот

Как открыть файл для чтения и записи, создав его, если он не существует, без его усечения?

Каков правильный набор флагов ввода-вывода для std::fstream, где я хочу читать и записывать в файл, не обрезая файл, если он существует, но создавая его, если он не работает?

Я пробовал

std::ios::binary | std::ios::in | std::ios::out
std::ios::binary | std::ios::in | std::ios::out | std::ios::ate

но ни один из них не создает файл, если он еще не существует.

Я не хочу std::ios::app, потому что мне также нужно искать по файлу по желанию с помощью курсоров get и put.

Одним из способов решения этой проблемы было бы сначала создать экземпляр std::ofstream, а затем немедленно закрыть его и открыть поток, который я действительно хочу, но это кажется беспорядочным, если его можно избежать с помощью одного объекта потока.

4b9b3361

Ответ 1

В это время я заключу, что std::ios::in явно препятствует этому, и что я должен использовать обходной путь.

Итак:

if (!std::ostream(path.c_str()))
   throw std::runtime_error("Could not create/open file");

std::fstream fs(path.c_str(), std::ios::binary | std::ios::in | std::ios::out);
if (!fs)
   throw std::runtime_error("Could not open file");

// ... use `fs`

Ответ 2

Исследование с точки зрения Linux (хотя большая часть этого относится к другим Unices):

На уровне syscall вы хотите open(O_RDWR | O_CREAT, 0666) (но не O_TRUNC или O_APPEND) или кучу других флагов, хотя, возможно, все файлы должны быть открыты с помощью O_CLOEXEC | O_LARGEFILE, но рядом с точкой)

На уровне libc нет стандартной строки mode, которая подразумевает O_CREAT без O_TRUNC. Однако вы можете использовать open, а затем fdopen.

На уровне библиотеки С++ нет стандартного способа передать нужные флаги. Однако, используя классы/функции, специфичные для реализации, или сторонние библиотеки, это возможно; см. Как построить С++ fstream из дескриптора файла POSIX?


Лично я, как правило, делаю все операции ввода-вывода на уровне C или даже на уровне системы, поскольку API намного приятнее и более предсказуем. Для ввода/вывода экземпляров класса у меня есть свои собственные шаблоны.

Ответ 3

Взяв std::ios::binary как прочитанный, оставшийся openmode, возможно, вам нужен:

std::ios::in | std::ios::app

Эффект, как будто открыть файл с помощью:

std::fopen(filename,"a+")

и эффект от этого:

  • открыть или, если он не существует, создать файл для чтения и записи
  • записать данные в конце файла.

Если вы открываете файл как std::fstream с помощью этого openmode, он не усекается, если он существует. Вы можете читать из файла везде, где указатель fstream tellg()\tellp() указывает, при условии, что там что-то есть, и вы можете поместить этот указатель с потоком seekg()\seekp() для чтения. Однако все записи будут прилагается к концу файла.

Таким образом, этот openmode будет соответствовать вашему счету, если вам не нужно выполнять записи в существующие данные.