Qt 数据流 #

数据流概述 #

text
┌─────────────────────────────────────────────────────────────┐
│                    Qt 数据流类型                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  QDataStream                                                │
│  ├── 二进制数据流                                           │
│  ├── 跨平台二进制格式                                       │
│  ├── 支持多种数据类型                                       │
│  └── 适合文件存储和网络传输                                 │
│                                                             │
│  QTextStream                                                │
│  ├── 文本数据流                                             │
│  ├── 支持编码转换                                           │
│  ├── 方便的文本格式化                                       │
│  └── 适合文本文件处理                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

QDataStream 二进制数据流 #

基本使用 #

cpp
// 写入数据
void writeData(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly)) {
        return;
    }
    
    QDataStream out(&file);
    
    // 设置版本(确保跨版本兼容)
    out.setVersion(QDataStream::Qt_6_0);
    
    // 写入基本类型
    out << 42;                    // int
    out << 3.14;                  // double
    out << true;                  // bool
    out << QString("Hello");      // QString
    out << QByteArray("data");    // QByteArray
    
    // 写入容器
    out << QList<int>{1, 2, 3};
    out << QMap<QString, int>{{"one", 1}, {"two", 2}};
}

// 读取数据
void readData(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly)) {
        return;
    }
    
    QDataStream in(&file);
    in.setVersion(QDataStream::Qt_6_0);
    
    // 按写入顺序读取
    int num;
    double d;
    bool b;
    QString str;
    QByteArray data;
    
    in >> num >> d >> b >> str >> data;
    
    qDebug() << num << d << b << str << data;
}

支持的数据类型 #

cpp
QDataStream out(&file);

// 基本类型
out << qint8(1);           // 8位有符号整数
out << quint8(1);          // 8位无符号整数
out << qint16(1);          // 16位有符号整数
out << quint16(1);         // 16位无符号整数
out << qint32(1);          // 32位有符号整数
out << quint32(1);         // 32位无符号整数
out << qint64(1);          // 64位有符号整数
out << quint64(1);         // 64位无符号整数
out << float(1.0);         // 单精度浮点
out << double(1.0);        // 双精度浮点
out << true;               // 布尔值

// Qt 类型
out << QString("text");    // 字符串
out << QByteArray("data"); // 字节数组
out << QDate::currentDate();
out << QTime::currentTime();
out << QDateTime::currentDateTime();
out << QPoint(10, 20);
out << QPointF(10.5, 20.5);
out << QSize(100, 200);
out << QRect(0, 0, 100, 200);
out << QVariant(42);

// 容器类型
out << QList<int>{1, 2, 3};
out << QStringList{"a", "b", "c"};
out << QSet<int>{1, 2, 3};
out << QMap<QString, int>{{"a", 1}};
out << QHash<QString, int>{{"a", 1}};

序列化自定义类型 #

cpp
// 自定义类型
struct Person
{
    QString name;
    int age;
    QString email;
};

// 声明为 QDataStream 可序列化类型
QDataStream &operator<<(QDataStream &out, const Person &person)
{
    out << person.name << person.age << person.email;
    return out;
}

QDataStream &operator>>(QDataStream &in, Person &person)
{
    in >> person.name >> person.age >> person.email;
    return in;
}

// 使用
void savePerson(const QString &fileName, const Person &person)
{
    QFile file(fileName);
    if (file.open(QIODevice::WriteOnly)) {
        QDataStream out(&file);
        out << person;
    }
}

Person loadPerson(const QString &fileName)
{
    Person person;
    QFile file(fileName);
    if (file.open(QIODevice::ReadOnly)) {
        QDataStream in(&file);
        in >> person;
    }
    return person;
}

版本兼容性 #

cpp
// 设置数据流版本
QDataStream out(&file);
out.setVersion(QDataStream::Qt_6_0);  // 使用 Qt 6.0 格式

// 可用版本
QDataStream::Qt_4_0
QDataStream::Qt_4_1
QDataStream::Qt_4_2
// ...
QDataStream::Qt_6_0
QDataStream::Qt_6_1
// ...

// 读取时必须使用相同版本
QDataStream in(&file);
in.setVersion(QDataStream::Qt_6_0);

字节序和浮点精度 #

cpp
QDataStream out(&file);

// 设置字节序
out.setByteOrder(QDataStream::BigEndian);     // 大端
out.setByteOrder(QDataStream::LittleEndian);  // 小端

// 设置浮点精度
out.setFloatingPointPrecision(QDataStream::SinglePrecision);  // 32位
out.setFloatingPointPrecision(QDataStream::DoublePrecision);  // 64位

状态检查 #

cpp
QDataStream in(&file);

while (!in.atEnd()) {
    int value;
    in >> value;
    
    if (in.status() != QDataStream::Ok) {
        qDebug() << "Error reading data";
        break;
    }
    
    qDebug() << value;
}

// 重置状态
in.resetStatus();

QTextStream 文本数据流 #

基本使用 #

cpp
// 写入文本
void writeText(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        return;
    }
    
    QTextStream out(&file);
    
    // 设置编码
    out.setEncoding(QStringConverter::Utf8);
    
    // 写入文本
    out << "Hello, Qt!" << Qt::endl;
    out << "Line 2" << Qt::endl;
    out << 42 << " " << 3.14 << Qt::endl;
    
    // 格式化输出
    out << QString("Name: %1, Age: %2").arg("Alice").arg(25) << Qt::endl;
}

// 读取文本
void readText(const QString &fileName)
{
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return;
    }
    
    QTextStream in(&file);
    in.setEncoding(QStringConverter::Utf8);
    
    // 读取全部
    QString all = in.readAll();
    qDebug() << all;
    
    // 或逐行读取
    in.seek(0);  // 回到开头
    while (!in.atEnd()) {
        QString line = in.readLine();
        qDebug() << line;
    }
}

编码设置 #

cpp
QTextStream stream(&file);

// 设置编码
stream.setEncoding(QStringConverter::Utf8);
stream.setEncoding(QStringConverter::Latin1);
stream.setEncoding(QStringConverter::Local8Bit);  // 系统本地编码

// 自动检测编码
stream.setAutoDetectUnicode(true);

字段格式化 #

cpp
QTextStream out(&file);

// 设置字段宽度
out.setFieldWidth(10);
out << "Name" << "Age" << "City" << Qt::endl;
out << "Alice" << 25 << "Beijing" << Qt::endl;

// 设置对齐方式
out.setFieldAlignment(QTextStream::AlignLeft);
out << "Left" << Qt::endl;

out.setFieldAlignment(QTextStream::AlignRight);
out << "Right" << Qt::endl;

out.setFieldAlignment(QTextStream::AlignCenter);
out << "Center" << Qt::endl;

// 设置填充字符
out.setPadChar('-');
out << "Padded" << Qt::endl;

数字格式化 #

cpp
QTextStream out(&file);

// 整数进制
out.setIntegerBase(10);  // 十进制
out << 42 << Qt::endl;

out.setIntegerBase(16);  // 十六进制
out << 42 << Qt::endl;   // 输出 "2a"

out.setIntegerBase(2);   // 二进制
out << 42 << Qt::endl;   // 输出 "101010"

// 实数格式
out.setRealNumberNotation(QTextStream::ScientificNotation);
out << 3.14159 << Qt::endl;  // 科学计数法

out.setRealNumberNotation(QTextStream::FixedNotation);
out << 3.14159 << Qt::endl;  // 固定小数点

out.setRealNumberPrecision(2);  // 小数位数
out << 3.14159 << Qt::endl;     // 输出 "3.14"

读取操作 #

cpp
QTextStream in(&file);

// 读取所有
QString all = in.readAll();

// 读取一行
QString line = in.readLine();

// 读取指定字符数
QString chunk = in.read(100);

// 读取到分隔符
QString word;
while (!in.atEnd()) {
    in >> word;  // 按空白分隔读取
    qDebug() << word;
}

// 读取单个字符
QChar ch;
in >> ch;

实用示例 #

配置文件读写 #

cpp
class Config : public QObject
{
    Q_OBJECT
public:
    void save(const QString &fileName)
    {
        QFile file(fileName);
        if (!file.open(QIODevice::WriteOnly)) {
            return;
        }
        
        QDataStream out(&file);
        out.setVersion(QDataStream::Qt_6_0);
        
        // 写入魔数和版本
        out << quint32(0x12345678);
        out << quint32(1);  // 版本号
        
        // 写入配置数据
        out << m_settings;
    }
    
    bool load(const QString &fileName)
    {
        QFile file(fileName);
        if (!file.open(QIODevice::ReadOnly)) {
            return false;
        }
        
        QDataStream in(&file);
        in.setVersion(QDataStream::Qt_6_0);
        
        // 验证魔数和版本
        quint32 magic, version;
        in >> magic >> version;
        
        if (magic != 0x12345678) {
            return false;
        }
        
        // 读取配置数据
        in >> m_settings;
        return true;
    }

private:
    QMap<QString, QVariant> m_settings;
};

CSV 文件处理 #

cpp
void writeCsv(const QString &fileName, const QList<QStringList> &data)
{
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        return;
    }
    
    QTextStream out(&file);
    out.setEncoding(QStringConverter::Utf8);
    
    for (const QStringList &row : data) {
        QStringList escapedRow;
        for (const QString &cell : row) {
            // 处理包含逗号或引号的字段
            QString escaped = cell;
            if (escaped.contains(',') || escaped.contains('"')) {
                escaped.replace('"', "\"\"");
                escaped = '"' + escaped + '"';
            }
            escapedRow << escaped;
        }
        out << escapedRow.join(',') << Qt::endl;
    }
}

QList<QStringList> readCsv(const QString &fileName)
{
    QList<QStringList> data;
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        return data;
    }
    
    QTextStream in(&file);
    in.setEncoding(QStringConverter::Utf8);
    
    while (!in.atEnd()) {
        QString line = in.readLine();
        // 简单解析(实际应使用更完善的 CSV 解析器)
        data << line.split(',');
    }
    
    return data;
}

下一步 #

现在你已经掌握了数据流的使用,接下来学习 多线程,了解 Qt 的多线程编程!

最后更新:2026-03-29