Поиск по сайту:

Как читать и записывать файлы на C++


Если вы знаете, как использовать потоки ввода-вывода в C++, вы можете (в принципе) работать с любым типом устройства ввода-вывода.

В C++ чтение и запись файлов можно выполнять с помощью потоков ввода-вывода в сочетании с операторами потока >> и <<. При чтении или записи файлов эти операторы применяются к экземпляру класса, представляющего файл на жестком диске. Этот потоковый подход имеет огромное преимущество: с точки зрения C++ не имеет значения, что вы читаете или записываете, будь то файл, база данных, консоль или другой компьютер, к которому вы подключены через сеть. Следовательно, знание того, как записывать файлы с помощью потоковых операторов, можно перенести и в другие области.

Классы потоков ввода-вывода

Стандартная библиотека C++ предоставляет класс ios_base. Этот класс действует как базовый класс для всех классов, совместимых с потоками ввода-вывода, таких как Basic_ofstream и Basic_ifstream. В этом примере будут использоваться специализированные типы для чтения/записи символов: ifstream и ofstream.

  • ofstream означает поток выходного файла, и доступ к нему можно получить с помощью оператора вставки <<.
  • ifstream означает поток входного файла, и доступ к нему можно получить с помощью оператора извлечения >>.

Оба типа определены внутри заголовка <fstream>.

Класс, который наследуется от ios_base, можно рассматривать как приемник данных при записи в него или как источник данных при чтении из него, полностью отделенный от самих данных. Этот объектно-ориентированный подход упрощает реализацию таких концепций, как разделение задач и внедрение зависимостей.

Простой пример

Этот пример программы довольно прост: он создает ofstream, записывает в него, создает ifstream и читает из него:

#include <iostream> // cout, cin, cerr etc...
#include <fstream> // ifstream, ofstream
#include <string>


int main()
{
    std::string sFilename = "MyFile.txt";    

    /******************************************
     *                                        *
     *                WRITING                 *
     *                                        *
     ******************************************/

    std::ofstream fileSink(sFilename); // Creates an output file stream

    if (!fileSink) {
        std::cerr << "Canot open " << sFilename << std::endl;
        exit(-1);
    }

    /* std::endl will automatically append the correct EOL */
    fileSink << "Hello Open Source World!" << std::endl;


    /******************************************
     *                                        *
     *                READING                 *
     *                                        *
     ******************************************/
    
    std::ifstream fileSource(sFilename); // Creates an input file stream

    if (!fileSource) {
        std::cerr << "Canot open " << sFilename << std::endl;
        exit(-1);
    }
    else {
        // Intermediate buffer
        std::string buffer;

        // By default, the >> operator reads word by workd (till whitespace)
        while (fileSource >> buffer) 
        {
            std::cout << buffer << std::endl;
        }
    }

    exit(0);
}

Этот код доступен на GitHub. Когда вы скомпилируете и запустите его, вы должны получить следующий вывод:

(Стефан Авенведде, CC BY-SA 4.0)

Это упрощенный пример, удобный для начинающих. Если вы хотите использовать этот код в своем приложении, обратите внимание на следующее:

  • Потоки файлов автоматически закрываются в конце программы. Если вы хотите продолжить выполнение, вам следует закрыть их вручную, вызвав метод close().
  • Эти классы файловых потоков наследуют (на нескольких уровнях) от Basic_ios, который перегружает оператор !. Это позволяет вам реализовать простую проверку, можете ли вы получить доступ к потоку. На сайте cppreference.com вы можете найти обзор того, когда эта проверка будет успешной (и не будет) успешной, а также вы можете реализовать дальнейшую обработку ошибок.
  • По умолчанию ifstream останавливается на пробеле и пропускает его. Чтобы читать построчно, пока не достигнете EOF, используйте метод getline(...).
  • Для чтения и записи двоичных файлов передайте конструктору флаг std::ios::binary: это предотвращает добавление символов EOL в каждую строку.

Написание с точки зрения системы

При записи файлов данные записываются в буфер записи в памяти системы. Когда система получает системный вызов sync, содержимое этого буфера записывается на жесткий диск. Этот механизм также является причиной того, что вам не следует извлекать USB-накопитель, не сообщив об этом системе. Обычно sync регулярно вызывается демоном. Если вы действительно хотите перестраховаться, вы также можете вызвать sync вручную:

#include <unistd.h> // needs to be included

sync();

Краткое содержание

Чтение и запись файлов на C++ не так уж сложны. Более того, если вы знаете, как обращаться с потоками ввода-вывода, вы также знаете (в принципе), как обращаться с любым типом устройств ввода-вывода. Библиотеки для различных типов устройств ввода-вывода позволяют использовать операторы потока для облегчения доступа. Вот почему полезно знать, как работают пары ввода-вывода.

Статьи по данной тематике: