Введение
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.