Различные статьи по Qt и c++

Работа с текстовыми файлами и QTextStream: простое руководство

Введение

QTextStream — удобная обёртка для работы с текстовыми данными, упрощающая чтение и запись строк, чисел и форматированного текста по сравнению с прямым использованием низкоуровневых методов QFile. В статье разберём, как использовать QTextStream для типичных задач — построчного чтения, записи с форматированием, и работы с кодировками.

Концепция

QTextStream можно создать поверх любого QIODevice (включая QFile) или напрямую работать со строкой QString. Главное удобство — операторы << и >>, похожие на стандартные потоки C++, которые сами заботятся о преобразовании чисел и других типов в текст и обратно, и набор методов для построчной работы (readLine(), readAll()) и контроля форматирования чисел (количество знаков после запятой, выравнивание).

Пример кода: Работа с текстовыми файлами и QTextStream

#include <QFile>
#include <QTextStream>
#include <QDebug>

void writeFormattedReport()
{
    QFile file("report.txt");
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qDebug() << "Не удалось открыть файл";
        return;
    }

    QTextStream out(&file);

    out << "Отчёт по продажам" << "\n";
    out << "==================" << "\n\n";

    // Числа можно выводить напрямую через <<, как обычный текст
    const double total = 15400.567;
    out << "Итоговая сумма: " << total << " руб.\n";

    // Контроль количества знаков после запятой для более аккуратного вывода
    out.setRealNumberNotation(QTextStream::FixedNotation);
    out.setRealNumberPrecision(2);
    out << "Итоговая сумма (округлённая): " << total << " руб.\n";

    file.close();
    qDebug() << "Отчёт сохранён";
}

void readLineByLine()
{
    QFile file("report.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "Не удалось открыть файл";
        return;
    }

    QTextStream in(&file);
    int lineNumber = 1;

    while (!in.atEnd()) {
        const QString line = in.readLine();
        qDebug() << "Строка" << lineNumber << ":" << line;
        lineNumber++;
    }

    file.close();
}

void readEntireFileAtOnce()
{
    QFile file("report.txt");
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return;
    }

    QTextStream in(&file);
    const QString allContent = in.readAll(); // весь файл сразу как одна строка
    qDebug() << "Длина файла в символах:" << allContent.length();

    file.close();
}

void workWithStringStream()
{
    // QTextStream работает не только с файлами, но и напрямую со строками
    QString result;
    QTextStream stream(&result);

    stream << "Имя: " << "Алексей" << ", возраст: " << 30;

    qDebug() << "Собранная строка:" << result;
}

Пояснения к коду

writeFormattedReport() показывает, что числа можно записывать через << так же просто, как строки — QTextStream сам конвертирует double в текстовое представление. setRealNumberNotation()/setRealNumberPrecision() дают контроль над тем, как именно числа с плавающей точкой форматируются — без этой настройки число может вывестись с большим количеством знаков после запятой, что не всегда желательно для читаемого отчёта.

readLineByLine() демонстрирует стандартный паттерн обработки файла построчно с подсчётом номера строки, а readEntireFileAtOnce() — альтернативу, когда нужен весь текст файла сразу как одна строка (подходит для небольших файлов; для очень больших файлов построчное чтение экономнее по памяти). workWithStringStream() показывает менее очевидную, но полезную возможность — QTextStream можно «направить» не в файл, а в обычную QString, что удобно для сборки сложного текста через привычный синтаксис << вместо последовательных конкатенаций строк через +.

Подводные камни

  • Чтение огромного файла целиком через readAll(), когда достаточно построчной обработки — для действительно больших файлов (сотни мегабайт и больше) это может потребовать значительного объёма памяти; построчное чтение через readLine() в цикле обрабатывает файл по частям, не загружая его полностью в память одновременно.
  • Забытая настройка кодировки при работе с файлами, содержащими не-ASCII символы (например, русский текст) на разных платформах — в современных версиях Qt по умолчанию используется UTF-8, что покрывает большинство случаев, но при работе со старыми файлами в другой кодировке (Windows-1251 и аналогичные) может потребоваться явная настройка через setEncoding().
  • Смешивание QTextStream и прямых вызовов QFile::write()/read() на одном и том же файле без понимания внутренней буферизации. QTextStream может буферизовать данные перед фактической записью — чередование высокоуровневых вызовов потока с низкоуровневыми вызовами файла может привести к данным, записанным не в том порядке, в котором ожидалось.
  • Использование << для чисел без контроля формата там, где важен конкретный, предсказуемый вид вывода (например, для дальнейшего автоматического разбора этого же файла другой программой) — стоит явно настраивать точность и формат чисел, а не полагаться на формат по умолчанию, который может отличаться между разными версиями Qt.