С++ файловый поток открытые режимы неоднозначность
Для выполнения IO файла в С++ мы используем классыstream, ifstream и fstream.
- ofstream: класс Stream для записи в файлах
- ifstream: класс Stream для чтения из файлов
- fstream: класс Stream для чтения и записи из/в файлы
Процесс связывания файла с объектом потока называется "открытием файла".
При открытии файла мы можем указать режим, в котором файл должен быть открыт.
Мой запрос связан с режимами ios::out
и ios:in
.
Когда я создаю объект ofstream
и открываю файл в режиме ios::in
, я могу
пишите в файл, но только если его уже создано (с файлом режима ios::out
также создается, если он еще не существует).
Но когда я создаю объект ifstream
и открываю файл в режиме ios::out
, я могу читать из файла.
Мой вопрос в том, почему эти режимы (ios::in
/ios::out
) предоставляются языком, когда сам тип потока (ifstream
/ofstream
) указывает, какой тип операции (ввод/вывод) ) выполняется?
Также почему это неоднозначное использование (ofstream
с ios::in
и ifstream
с ios::out
) работает в одном случае и не удается (хотя только если файл еще не присутствует) в другом?
Ответы
Ответ 1
Классы ofstream
, ifstream
и fstream
- это интерфейсы высокого уровня для подстроки filebuf
, которые можно получить через функцию члена rdbuf()
для потока.
В соответствии со стандартом, когда вы открываете ofstream
с некоторым режимом mode
, он открывает буфер подчеркивания потока, как и в mode | ios_base::out
. Аналогично ifstream
использует mode | ios_base::in
. fstream
передает параметр mode
дословно в буфер потока подчеркивания.
Из сказанного следует, что следующий код открывает файл с точно такими же открытыми флагами:
fstream f("a.txt", ios_base::in | ios_base::out);
ifstream g("a.txt", ios_base::out);
ofstream h("a.txt", ios_base::in);
После этих строк вы можете делать то же самое с f.rdbuf()
, g.rdbuf()
и h.rdbuf()
, и все три действуют так, как будто вы открыли файл с помощью вызова C fopen("a.txt", "r+")
, который дает вам чтение/доступ на запись, не обрезает файл и не удается, если файл не существует.
Итак, почему у нас есть три разных класса? Как я уже сказал, это классы высокого уровня, обеспечивающие высокоуровневый интерфейс над потоковым буфером более низкого уровня. Идея состоит в том, что ifstream
имеет функции-члены для ввода (например, read()
), ofstream
имеет функции-члены для вывода (например, write()
), а fstream
- оба. Например, вы не можете этого сделать:
g.write("abc", 3); // error: g does not have a write function
Но это работает, потому что, хотя g
является ifstream
, мы открыли его с помощью ios_base::out
:
g.rdbuf()->sputn("abc", 3); // we still have write access
Ответ 2
Поскольку режим не ограничивается вводом/выводом. Например, конструктор ifstream
выглядит следующим образом:
explicit ifstream ( const char * filename, ios_base::openmode mode = ios_base::in );
Обратите внимание, что значение по умолчанию ios_base::in
, поэтому вам не нужно указывать его самостоятельно. Однако mode
устанавливает флаги потоков не, ограниченные in
/out
, но включают:
-
app
(добавить) Установите индикатор позиции потока в конец потока перед каждой операцией вывода.
-
ate
(в конце) Установите индикатор положения потока в конец потока при открытии.
-
binary
(двоичный) Рассмотрим поток как двоичный, а не текстовый.
-
in
(ввод) Разрешить операции ввода в потоке.
-
out
(вывод) Разрешить выходные операции в потоке.
-
trunc
(truncate) Любое текущее содержимое отбрасывается, предполагая длину нуля при открытии.