文件读写从专家到小白

C标准库文件读写

文本文件写入

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

const char* filename = "ctest.txt";

FILE* fp = fopen(filename, "w");
if (fp == nullptr) {
    perror("打开文件失败");
    return;
}

// 写入字符串
fprintf(fp, "姓名: %s\n", "张三");
fprintf(fp, "年龄: %d\n", 25);
fprintf(fp, "分数: %.2f\n", 89.5);

// 写入单个字符
fputc('\n', fp);

fclose(fp);

写模式参考

模式文件不存在文件存在时行为
"w"创建覆盖从头写入
"a"创建保留追加到末尾
"w+"创建覆盖从头写入(可读)
"a+"创建保留追加到末尾(读可任意位置)
"r+"失败保留从当前位置覆盖写入

b 得二进制版本(如 "wb", "ab", "w+b"/"wb+" 等),详见二进制章节。Windows 上 b 抑制 \n\r\n 转换,POSIX 无影响。

C11 独占模式(x): "wx", "w+x"——文件已存在则打开失败,防止意外覆盖,打开后行为同对应的 w/w+。二进制版本为 "wbx", "w+bx"/"wb+x"

文本文件读取

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

const char* filename = "ctest.txt";

FILE* fp = fopen(filename, "r");
if (fp == nullptr) {
    perror("打开文件失败");
    return;
}

// 方式1:逐行读取
char line[256];
while (fgets(line, sizeof(line), fp) != nullptr) {
    printf("读取: %s", line);
}

// 方式2:格式化读取
rewind(fp);  // 重置到文件开头
char name[50];
int age;
float score;
fscanf(fp, "姓名: %s", name);
fscanf(fp, "年龄: %d", &age);
fscanf(fp, "分数: %f", &score);

fclose(fp);

读模式参考

模式文件不存在说明
"r"失败只读,从开头读
"r+"失败读写,写入行为见写模式参考

b 得二进制版本("rb", "rb+"/"r+b"),详见二进制章节。"a+""w+" 也支持读取,详见写模式参考。

二进制文件写入

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

const char* filename = "cbinary.dat";

// 定义结构体
struct Student {
    int id;
    char name[50];
    float score;
};

FILE* fp = fopen(filename, "wb");
if (fp == nullptr) {
    perror("打开文件失败");
    return;
}

Student s1 = {1, "张三", 85.5};
Student s2 = {2, "李四", 90.0};

// 写入结构体
fwrite(&s1, sizeof(Student), 1, fp);
fwrite(&s2, sizeof(Student), 1, fp);

fclose(fp);

二进制写模式

模式等效文本模式行为说明
"wb""w"覆盖创建或清空后写入
"ab""a"追加写入始终追加到末尾
"wb+" / "w+b""w+"覆盖从头写入(可读)
"ab+" / "a+b""a+"追加追加到末尾(读可任意位置)
"rb+" / "r+b""r+"定位写入文件必须存在,从当前位置写入

b 抑制 Windows 上的 \n\r\n 转换,POSIX 无影响。二进制写入行为与文本版本相同,仅换行处理不同。
C11 独占:"wbx", "w+bx"/"wb+x"——文件已存在则失败。

二进制文件读取

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

const char* filename = "cbinary.dat";

// 定义结构体
struct Student {
    int id;
    char name[50];
    float score;
};

FILE* fp = fopen(filename, "rb");
if (fp == nullptr) {
    perror("打开文件失败");
    return;
}

// 获取文件大小
fseek(fp, 0, SEEK_END);
long fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);

printf("文件大小: %ld 字节\n", fileSize);

// 读取结构体
Student s;
while (fread(&s, sizeof(Student), 1, fp) == 1) {
    printf("ID: %d, 姓名: %s, 分数: %.2f\n", s.id, s.name, s.score);
}

fclose(fp);

二进制读模式

模式等效文本模式说明
"rb""r"只读,从开头读
"rb+" / "r+b""r+"读写,写入行为见二进制写模式

"ab+""wb+" 等也支持读取,详见二进制写模式。

文件位置操作

#include <cstdio>
#include <cstdlib>

FILE* fp = fopen("test.txt", "w+");

// 写入数据
fputs("Hello World\n", fp);
fputs("Second Line\n", fp);

// 获取当前位置
long pos = ftell(fp);
printf("当前位置: %ld\n", pos);

// 移动到文件开头
fseek(fp, 0, SEEK_SET);

// 移动到文件末尾
fseek(fp, 0, SEEK_END);

// 从当前位置偏移
fseek(fp, -5, SEEK_CUR);

// 重置到开头
rewind(fp);

fclose(fp);

C++标准库文件读写

文本文件写入

基本写入

#include <iostream>
#include <fstream>
#include <string>

std::ofstream outFile(filename);
if (!outFile.is_open()) {
    std::cerr << "无法打开文件: " << filename << std::endl;
    return;
}

// 写入多行文本
outFile << "第一行内容" << std::endl;
outFile << "第二行内容" << std::endl;
outFile << "数字: " << 42 << std::endl;
outFile << "浮点数: " << 3.14159 << std::endl;

outFile.close();
std::cout << "文件写入成功" << std::endl;

追加模式写入

#include <iostream>
#include <fstream>
#include <string>

// std::ios::app 表示追加模式
std::ofstream outFile(filename, std::ios::app);
if (!outFile.is_open()) {
    std::cerr << "无法打开文件: " << filename << std::endl;
    return;
}

outFile << "这是追加的内容" << std::endl;
outFile.close();

写模式参考

std::ofstream 默认 out | trunc(等效 C "w"):

标志组合等效 C 模式行为说明
out"w"覆盖创建或清空后写入
out | app"a"追加写入始终追加到末尾
in | out"r+"定位写入文件必须存在,从当前位置覆盖写入
in | out | trunc"w+"覆盖创建或清空后读写
in | out | app"a+"追加读可任意位置,写追加到末尾

\| binary 得二进制版本,详见二进制章节。appate 的区别:app每次写入前自动定位到末尾;ate 只在打开时定位一次,之后可 seekp 到任意位置。trunc 只有指定了 out 才生效。

文本文件读取

#include <iostream>
#include <fstream>
#include <string>

std::ifstream inFile(filename);
if (!inFile.is_open()) {
    std::cerr << "无法打开文件: " << filename << std::endl;
    return;
}

// 方式1:逐行读取
std::string line;
std::cout << "=== 逐行读取 ===" << std::endl;
while (std::getline(inFile, line)) {
    std::cout << line << std::endl;
}

// 重置文件指针到开头
inFile.clear();
inFile.seekg(0, std::ios::beg);

// 方式2:逐词读取
std::string word;
std::cout << "\n=== 逐词读取 ===" << std::endl;
while (inFile >> word) {
    std::cout << word << " ";
}
std::cout << std::endl;

inFile.close();

读模式参考

std::ifstream 默认 in(等效 C "r"):

标志组合等效 C 模式说明
in"r"只读,文件必须存在
in | out"r+"读写,写入行为见写模式参考

\| binary 得二进制版本,详见二进制章节。in | out | app"a+")、in | out | trunc"w+")等也支持读取,详见写模式参考。

使用 fstream(读写一体)

#include <fstream>
#include <iostream>

// 以读写模式打开文件
std::fstream file(filename, std::ios::in | std::ios::out | std::ios::app);
if (!file.is_open()) {
    std::cerr << "无法打开文件" << std::endl;
    return;
}

// 读取内容
std::string line;
while (std::getline(file, line)) {
    std::cout << line << std::endl;
}

// 写入新内容
file << "新添加的内容" << std::endl;

file.close();

打开模式标志速查

标志含义
std::ios::in以读取方式打开文件
std::ios::out以写入方式打开文件
std::ios::app追加模式,每次写入前定位到文件末尾
std::ios::ate打开后立即定位到文件末尾(At The End)
std::ios::trunc若文件存在则截断(清空内容)
std::ios::binary二进制模式(Windows 上抑制换行符转换)

各流类型的默认模式:

流类型默认模式等效 C 模式
std::ifstreamstd::ios::in"r"
std::ofstreamstd::ios::out | std::ios::trunc"w"
std::fstreamstd::ios::in | std::ios::out"r+"

写模式组合和写入行为汇总已归入上方「写模式参考」,读模式已归入「读模式参考」。

二进制文件写入

基本写入

#include <iostream>
#include <fstream>
#include <vector>

// 定义一个结构体用于二进制读写
struct Student {
    int id;
    char name[50];
    double score;
};

std::ofstream outFile(filename, std::ios::binary);
if (!outFile.is_open()) {
    std::cerr << "无法打开文件" << std::endl;
    return;
}

// 写入单个结构体
Student s1 = {1, "张三", 85.5};
outFile.write(reinterpret_cast<const char*>(&s1), sizeof(Student));

// 写入多个结构体
Student students[] = {
    {2, "李四", 90.0},
    {3, "王五", 78.5}
};
outFile.write(reinterpret_cast<const char*>(students), sizeof(students));

// 写入原始字节数组
std::vector<char> buffer = {'H', 'e', 'l', 'l', 'o'};
outFile.write(buffer.data(), buffer.size());

outFile.close();

二进制写模式

标志组合等效 C 模式行为说明
out | binary"wb"覆盖创建或清空后写入
out | app | binary"ab"追加写入始终追加到末尾
in | out | binary"r+b"定位写入文件必须存在,从当前位置写入
in | out | trunc | binary"w+b"覆盖创建或清空后读写
in | out | app | binary"a+b"追加读可任意位置,写追加到末尾

binary 抑制 Windows 上的 \n\r\n 转换,POSIX 无影响。行为与对应文本模式相同,仅换行处理不同。

二进制文件读取

#include <iostream>
#include <fstream>
#include <vector>

// 定义一个结构体用于二进制读写
struct Student {
    int id;
    char name[50];
    double score;
};

std::ifstream inFile(filename, std::ios::binary);
if (!inFile.is_open()) {
    std::cerr << "无法打开文件" << std::endl;
    return;
}

// 获取文件大小
inFile.seekg(0, std::ios::end);
std::streamsize fileSize = inFile.tellg();
inFile.seekg(0, std::ios::beg);

std::cout << "文件大小: " << fileSize << " 字节" << std::endl;

// 读取单个结构体
Student s;
inFile.read(reinterpret_cast<char*>(&s), sizeof(Student));
std::cout << "ID: " << s.id
          << ", 姓名: " << s.name
          << ", 分数: " << s.score << std::endl;

// 读取到缓冲区
std::vector<char> buffer(fileSize);
inFile.seekg(0, std::ios::beg);
inFile.read(buffer.data(), fileSize);

inFile.close();

二进制读模式

标志组合等效 C 模式说明
in | binary"rb"只读,从开头读
in | out | binary"r+b"读写,写入行为见二进制写模式

in | out | app | binary"a+b")等也支持读取,详见二进制写模式。

流缓冲区写入优化

#include <iostream>
#include <fstream>
#include <vector>

std::ofstream outFile(filename, std::ios::binary);

// 使用缓冲区提高性能
std::vector<char> buffer(1024 * 1024);  // 1MB 缓冲区
outFile.rdbuf()->pubsetbuf(buffer.data(), buffer.size());

// 大量数据写入
for (int i = 0; i < 10000; ++i) {
    outFile.write(reinterpret_cast<const char*>(&i), sizeof(int));
}

流缓冲区读取优化

#include <iostream>
#include <fstream>
#include <vector>

std::ifstream inFile(filename, std::ios::binary);

std::vector<char> buffer(1024 * 1024);
inFile.rdbuf()->pubsetbuf(buffer.data(), buffer.size());

int value;
while (inFile.read(reinterpret_cast<char*>(&value), sizeof(int))) {
    // 处理数据
}

文件位置操作

#include <iostream>
#include <fstream>

std::fstream file(filename, std::ios::in | std::ios::out | std::ios::trunc);

// 写入一些数据
for (int i = 0; i < 10; ++i) {
    file << "Line " << i << std::endl;
}

// 获取当前写入位置
std::streampos writePos = file.tellp();
std::cout << "当前写入位置: " << writePos << std::endl;

// 移动到文件开头
file.seekp(0, std::ios::beg);

// 移动到文件末尾
file.seekp(0, std::ios::end);

// 从当前位置向前移动
file.seekp(-10, std::ios::cur);

// 切换到读取模式,获取读取位置
file.seekg(0, std::ios::beg);
std::streampos readPos = file.tellg();

file.close();

Qt 文件读写

使用 QFile

基础文件操作

#include <QFile>
#include <QDebug>
#include <QFileInfo>

QString filename = "test.txt";

// 检查文件是否存在
QFile file(filename);
if (file.exists()) {
    qDebug() << "文件存在";
}

// 获取文件信息
QFileInfo fileInfo(filename);
qDebug() << "文件名:" << fileInfo.fileName();
qDebug() << "文件大小:" << fileInfo.size() << "字节";
qDebug() << "创建时间:" << fileInfo.birthTime();
qDebug() << "修改时间:" << fileInfo.lastModified();

文本文件写入(QFile + QTextStream)

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

QFile file(filename);

// 打开文件,只写模式,文本模式
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
    qDebug() << "无法打开文件:" << file.errorString();
    return;
}

// 使用 QTextStream 写入
QTextStream out(&file);
out.setCodec("UTF-8");  // 设置编码

out << "第一行内容" << Qt::endl;
out << "第二行内容" << Qt::endl;
out << "整数: " << 42 << Qt::endl;
out << "浮点数: " << 3.14159 << Qt::endl;
out << "字符串: " << QString("Hello Qt") << Qt::endl;

file.close();
qDebug() << "文件写入成功";

追加模式写入

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

QFile file(filename);

// Append 模式
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
    qDebug() << "无法打开文件:" << file.errorString();
    return;
}

QTextStream out(&file);
out << "这是追加的内容" << Qt::endl;

file.close();

写模式参考

Qt 默认二进制模式,加 | Text 切换文本模式(Windows 换行转换)。以下为文本模式组合:

Qt 组合等效 C 模式行为说明
WriteOnly | Text定位写入从开头写入,不覆盖尾部旧数据(Qt 特有
WriteOnly | Truncate | Text"w"覆盖清空后写入,等同 C "w"
WriteOnly | Append | Text"a"追加写入始终追加到末尾
ReadWrite | Text"r+"定位写入文件必须存在,从当前位置写入
ReadWrite | Truncate | Text"w+"覆盖清空后读写
ReadWrite | Append | Text"a+"追加读可任意位置,写追加到末尾
WriteOnly | NewOnly | Text"wx"覆盖仅新建,文件已存在则失败
ReadWrite | NewOnly | Text覆盖仅新建后读写,文件已存在则失败

⚠ 关键差异: Qt 的 WriteOnly 默认不清空文件(与 C "w" 和 C++ out 不同)。需要等同 C "w" 的行为时,必须显式加 Truncate。去掉 \| Text 即得对应二进制模式,详见二进制章节。

文本文件读取(QFile + QTextStream)

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

QFile file(filename);

if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    qDebug() << "无法打开文件:" << file.errorString();
    return;
}

QTextStream in(&file);
in.setCodec("UTF-8");

// 方式1:逐行读取
qDebug() << "=== 逐行读取 ===";
while (!in.atEnd()) {
    QString line = in.readLine();
    qDebug() << line;
}

// 重置到文件开头
file.seek(0);
in.reset();

// 方式2:读取所有内容
qDebug() << "\n=== 读取全部 ===";
QString allContent = in.readAll();
qDebug() << allContent;

file.close();

读模式参考

文本模式读取(加 | Text):

Qt 组合等效 C 模式说明
ReadOnly | Text"r"只读,文件必须存在
ReadWrite | Text"r+"读写,写入行为见写模式参考

去掉 \| Text 即得二进制版本,详见二进制章节。ReadWrite \| Append \| Text"a+")等也支持读取,详见写模式参考。

打开模式标志速查

标志含义
QIODevice::ReadOnly只读
QIODevice::WriteOnly只写
QIODevice::ReadWrite读写(ReadOnly | WriteOnly
QIODevice::Append追加模式,每次写入前定位到文件末尾
QIODevice::Truncate打开时截断文件(清空内容)
QIODevice::Text文本模式(Windows 下转换换行符)
QIODevice::Unbuffered绕过缓冲区,直接读写
QIODevice::NewOnly仅当文件不存在时才创建(类似 C11 x
QIODevice::ExistingOnly仅当文件已存在时才打开

写模式组合和写入行为汇总已归入上方「写模式参考」。

二进制文件写入(QDataStream)

基本写入

#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QDateTime>

// 定义数据结构
struct Product {
    int id;
    QString name;
    double price;
    QDateTime createTime;
};

QFile file(filename);
if (!file.open(QIODevice::WriteOnly)) {
    qDebug() << "无法打开文件:" << file.errorString();
    return;
}

QDataStream out(&file);

// 设置版本(保证兼容性)
out.setVersion(QDataStream::Qt_5_15);

// 写入魔数和版本标识
out << quint32(0xA0B0C0D0);  // 魔数
out << qint32(1);             // 文件版本

// 写入基本数据类型
out << qint32(42);
out << QString("Hello Qt");
out << double(3.14159);
out << true;

// 写入列表
QStringList list;
list << "Item1" << "Item2" << "Item3";
out << list;

// 写入自定义结构
out << qint32(1);  // ID
out << QString("Product A");
out << double(99.99);
out << QDateTime::currentDateTime();

file.close();
qDebug() << "二进制文件写入成功";

二进制写模式

Qt 默认即二进制模式(无需 | Text):

Qt 组合等效 C 模式行为说明
WriteOnly定位写入从开头写入,不覆盖尾部旧数据(Qt 特有
WriteOnly | Truncate"wb"覆盖清空后写入
WriteOnly | Append"ab"追加写入始终追加到末尾
ReadWrite"r+b"定位写入文件必须存在,从当前位置写入
ReadWrite | Truncate"w+b"覆盖清空后读写
ReadWrite | Append"a+b"追加读可任意位置,写追加到末尾
WriteOnly | NewOnly"wbx"覆盖仅新建,文件已存在则失败
ReadWrite | NewOnly覆盖仅新建后读写

\| Text 切换文本模式(见文本章节)。

二进制文件读取(QDataStream)

#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QDateTime>

QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
    qDebug() << "无法打开文件:" << file.errorString();
    return;
}

QDataStream in(&file);
in.setVersion(QDataStream::Qt_5_15);

// 读取魔数和版本
quint32 magic;
qint32 version;
in >> magic >> version;

if (magic != 0xA0B0C0D0) {
    qDebug() << "文件格式错误";
    file.close();
    return;
}

// 读取基本数据类型
qint32 intValue;
QString stringValue;
double doubleValue;
bool boolValue;

in >> intValue >> stringValue >> doubleValue >> boolValue;

qDebug() << "整数:" << intValue;
qDebug() << "字符串:" << stringValue;
qDebug() << "浮点数:" << doubleValue;
qDebug() << "布尔值:" << boolValue;

// 读取列表
QStringList list;
in >> list;
qDebug() << "列表:" << list;

// 读取自定义结构
qint32 id;
QString name;
double price;
QDateTime createTime;

in >> id >> name >> price >> createTime;
qDebug() << "产品ID:" << id;
qDebug() << "产品名:" << name;
qDebug() << "价格:" << price;
qDebug() << "创建时间:" << createTime;

file.close();

二进制读模式

Qt 默认即二进制(无需 | Text):

Qt 组合等效 C 模式说明
ReadOnly"rb"只读,文件必须存在
ReadWrite"r+b"读写,写入行为见二进制写模式

\| Text 切换文本模式(见文本章节)。ReadWrite \| Append"a+b")等也支持读取。

原始字节写入

#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QDateTime>

QFile file(filename);
file.open(QIODevice::WriteOnly);

QByteArray data;
data.append("Hello World");
data.append(0x00);
data.append(0xFF);

file.write(data);
file.close();

原始字节读取

#include <QFile>
#include <QDataStream>
#include <QDebug>
#include <QDateTime>

QFile file(filename);
file.open(QIODevice::ReadOnly);

// 方式1:读取全部
QByteArray allData = file.readAll();

// 方式2:分块读取
file.seek(0);
const int bufferSize = 1024;
while (!file.atEnd()) {
    QByteArray chunk = file.read(bufferSize);
    // 处理 chunk
}

file.close();

内存映射文件(QFile + mmap)

#include <QFile>
#include <QDebug>

QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
    qDebug() << "无法打开文件";
    return;
}

// 内存映射(只读)
uchar* memory = file.map(0, file.size());
if (memory) {
    // 直接访问内存中的文件内容
    QByteArray data(reinterpret_cast<const char*>(memory), file.size());
    qDebug() << "映射内容:" << data;

    // 解除映射
    file.unmap(memory);
}

file.close();

临时文件和缓冲区

临时文件

#include <QTemporaryFile>
#include <QDebug>

QTemporaryFile tempFile;
tempFile.setAutoRemove(true);  // 自动删除

if (tempFile.open()) {
    // 写入数据
    tempFile.write("临时数据");
    tempFile.flush();

    qDebug() << "临时文件路径:" << tempFile.fileName();

    // 读取数据
    tempFile.seek(0);
    QByteArray data = tempFile.readAll();
    qDebug() << "临时文件内容:" << data;
}
// 离开作用域自动删除

内存缓冲区

#include <QBuffer>
#include <QDebug>

QBuffer buffer;
if (buffer.open(QIODevice::ReadWrite)) {
    // 写入数据
    buffer.write("缓冲区数据");

    // 读取数据
    buffer.seek(0);
    QByteArray data = buffer.readAll();
    qDebug() << "缓冲区内容:" << data;

    // 获取缓冲区数据
    QByteArray rawData = buffer.data();
}

文件监视

#include <QFileSystemWatcher>
#include <QDebug>

class FileWatcher : public QObject {
    Q_OBJECT
public:
    FileWatcher(QObject* parent = nullptr)
        : QObject(parent)
    {
        connect(&watcher, &QFileSystemWatcher::fileChanged,
                this, &FileWatcher::onFileChanged);
        connect(&watcher, &QFileSystemWatcher::directoryChanged,
                this, &FileWatcher::onDirectoryChanged);
    }

    void watchFile(const QString& path) {
        watcher.addPath(path);
    }

    void watchDirectory(const QString& path) {
        watcher.addPath(path);
    }

private slots:
    void onFileChanged(const QString& path) {
        qDebug() << "文件发生变化:" << path;
    }

    void onDirectoryChanged(const QString& path) {
        qDebug() << "目录发生变化:" << path;
    }

private:
    QFileSystemWatcher watcher;
};

MFC 文件读写

使用 CFile

文本文件写入(CFile)

#include <afx.h>

CFile file;
if (!file.Open(filename, CFile::modeCreate | CFile::modeWrite | CFile::typeText)) {
    AfxMessageBox(_T("无法打开文件"));
    return;
}

CString content = _T("MFC文件写入测试\n");
file.Write(content, content.GetLength() * sizeof(TCHAR));

file.Close();

写模式参考

CFile 默认二进制模式,加 typeText 切换文本。文本模式组合:

MFC 组合等效 C 模式行为说明
modeCreate | modeWrite | typeText"w"覆盖创建或清空后写入
modeCreate | modeWrite | modeNoTruncate | typeText"a"追加写入始终追加到末尾
modeReadWrite | typeText"r+"定位写入文件必须存在,从当前位置写入
modeCreate | modeReadWrite | typeText"w+"覆盖创建或清空后读写
modeCreate | modeReadWrite | modeNoTruncate | typeText"a+"追加读可任意位置,写追加到末尾

modeCreate 会清空已存在文件,加 modeNoTruncate 转为追加。换 typeBinary(或省略,因为二进制是默认)即得对应二进制模式,详见二进制章节。

文本文件读取(CFile)

#include <afx.h>

CFile file;
if (!file.Open(filename, CFile::modeRead | CFile::typeText)) {
    AfxMessageBox(_T("无法打开文件"));
    return;
}

char buffer[1024];
UINT bytesRead;
while ((bytesRead = file.Read(buffer, sizeof(buffer) - 1)) > 0) {
    buffer[bytesRead] = '\0';
    // 处理数据
}

file.Close();

读模式参考

文本模式读取(加 typeText):

MFC 组合等效 C 模式说明
modeRead | typeText"r"只读,文件必须存在
modeReadWrite | typeText"r+"读写,写入行为见写模式参考

typeBinary(或省略,默认即二进制)得二进制版本,详见二进制章节。modeCreate \| modeReadWrite \| typeText"w+")等也支持读取,详见写模式参考。

二进制文件写入(CFile)

#include <afx.h>

CFile file;
if (file.Open(filename, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary)) {
    struct Record { int id; char name[50]; double score; };
    Record rec = {1, "张三", 85.5};
    file.Write(&rec, sizeof(Record));
    file.Close();
}

二进制写模式

CFile 默认即二进制(无需 typeBinary,或可显式写出):

MFC 组合等效 C 模式行为说明
modeCreate | modeWrite"wb"覆盖创建或清空后写入
modeCreate | modeWrite | modeNoTruncate"ab"追加写入始终追加到末尾
modeReadWrite"r+b"定位写入文件必须存在,从当前位置写入
modeCreate | modeReadWrite"w+b"覆盖创建或清空后读写
modeCreate | modeReadWrite | modeNoTruncate"a+b"追加读可任意位置,写追加到末尾

modeCreate 会清空已存在文件,加 modeNoTruncate 转为追加。加 typeText 切换文本模式(见文本章节)。

二进制文件读取(CFile)

#include <afx.h>

CFile file;
if (file.Open(filename, CFile::modeRead | CFile::typeBinary)) {
    Record rec;
    file.Read(&rec, sizeof(Record));
    file.Close();
}

二进制读模式

CFile 默认即二进制:

MFC 组合等效 C 模式说明
modeRead"rb"只读,文件必须存在
modeReadWrite"r+b"读写,写入行为见二进制写模式

typeText 切换文本模式(见文本章节)。modeCreate \| modeReadWrite"w+b")等也支持读取。

打开模式标志速查

标志含义
CFile::modeRead只读
CFile::modeWrite只写
CFile::modeReadWrite读写
CFile::modeCreate创建新文件(已存在且无 modeNoTruncate 则截断)
CFile::modeNoTruncatemodeCreate 配合使用,不截断已存在的文件
CFile::typeText文本模式
CFile::typeBinary二进制模式(默认,与 C/C++ 不同)
CFile::shareDenyNone不拒绝其他进程的读写访问
CFile::shareDenyRead拒绝其他进程的读取访问
CFile::shareDenyWrite拒绝其他进程的写入访问
CFile::shareExclusive独占访问
CFile::osNoBuffer无系统缓冲
CFile::osWriteThrough写入直接落盘
CFile::osRandomAccess随机访问优化
CFile::osSequentialScan顺序访问优化

注意: CFile 默认使用二进制模式,与 C/C++ 标准库默认文本模式不同。写模式组合和写入行为汇总已归入上方「写模式参考」。

使用 CStdioFile

CStdioFile file;

// 写入
if (file.Open(filename, CFile::modeCreate | CFile::modeWrite | CFile::typeText)) {
    file.WriteString(_T("第一行内容\n"));
    file.WriteString(_T("第二行内容\n"));
    file.Close();
}

// 读取
if (file.Open(filename, CFile::modeRead | CFile::typeText)) {
    CString line;
    while (file.ReadString(line)) {
        // 处理每一行
    }
    file.Close();
}

使用 CArchive(序列化)

// 写入(存储)
{
    CFile file(filename, CFile::modeCreate | CFile::modeWrite);
    CArchive ar(&file, CArchive::store);

    int nValue = 42;
    CString str = _T("Hello MFC");
    double dValue = 3.14;

    ar << nValue << str << dValue;
    ar.Close();
    file.Close();
}

// 读取(加载)
{
    CFile file(filename, CFile::modeRead);
    CArchive ar(&file, CArchive::load);

    int nValue;
    CString str;
    double dValue;

    ar >> nValue >> str >> dValue;
    ar.Close();
    file.Close();
}

方案对比与选择建议

方式优点缺点适用场景
C FILE*性能高、兼容性好不安全、需手动管理资源遗留代码、性能敏感场景
C++ ifstream/ofstream类型安全、支持RAII、面向对象相对C风格稍慢现代C++项目首选
Qt QFile跨平台、支持信号槽、功能丰富依赖Qt库Qt项目首选
QDataStream支持Qt类型、版本兼容Qt专属格式Qt对象序列化
MFC CFileWindows原生、与MFC框架深度集成仅限Windows、较老旧MFC/Windows项目
MFC CArchive支持MFC对象序列化仅限Windows、MFC专属格式MFC序列化
内存映射大文件处理快占用虚拟内存大文件读写

选择建议

  • C项目/性能敏感:使用 C 风格文件操作(FILE*
  • 纯C++项目:使用 std::ifstream / std::ofstream
  • Qt项目:使用 QFile + QTextStream / QDataStream
  • MFC项目:使用 CFile / CStdioFile / CArchive
  • 需要跨平台:优先选择 C++ 标准库或 Qt 的文件操作封装
  • 序列化对象:Qt 使用 QDataStream,MFC 使用 CArchive
  • 大文件读写:考虑内存映射

完整示例程序

// main.cpp - 完整示例
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDataStream>
#include <QDebug>
#include <iostream>
#include <fstream>

int main(int argc, char* argv[]) {
    QCoreApplication app(argc, argv);

    // ========== C++ 标准库示例 ==========
    std::cout << "=== C++ 标准库文件操作 ===" << std::endl;

    // 写入文本
    std::ofstream cppOut("cpp_test.txt");
    cppOut << "C++标准库写入测试" << std::endl;
    cppOut.close();

    // 读取文本
    std::ifstream cppIn("cpp_test.txt");
    std::string line;
    std::getline(cppIn, line);
    std::cout << "读取内容: " << line << std::endl;
    cppIn.close();

    // ========== Qt 文件操作示例 ==========
    qDebug() << "\n=== Qt 文件操作 ===";

    // 文本文件
    QFile qtFile("qt_test.txt");
    if (qtFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QTextStream out(&qtFile);
        out << "Qt文件写入测试" << Qt::endl;
        qtFile.close();
    }

    if (qtFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream in(&qtFile);
        QString content = in.readAll();
        qDebug() << "读取内容:" << content;
        qtFile.close();
    }

    // 二进制文件
    QFile binFile("qt_binary.dat");
    if (binFile.open(QIODevice::WriteOnly)) {
        QDataStream out(&binFile);
        out << QString("二进制数据") << 42 << 3.14;
        binFile.close();
    }

    qDebug() << "\n所有测试完成!";

    return 0;
}

注意事项

编码问题

  • Windows下文本文件默认使用本地编码(GBK)
  • 建议统一使用 UTF-8 编码
  • Qt中使用 QTextStream::setCodec() 设置编码

文件路径

  • 使用 QDirQFileInfo 处理跨平台路径
  • Windows路径分隔符可用 /\\
  • 使用 QDir::separator() 获取系统分隔符

错误处理

  • 始终检查文件是否成功打开
  • 使用 QFile::errorString() 获取错误信息
  • 大文件操作考虑使用异常处理

何时使用二进制文件读写

应使用二进制模式("rb" / "wb" / std::ios::binary)的场景:

  • 存储结构体或对象原始内存数据(fwrite / write
  • 读写图片、音频、视频等非文本格式文件
  • 需要精确控制文件字节内容(如网络协议封包、文件格式解析)
  • 跨平台交换数据时避免换行符转换(Windows \r\n\n
  • 需要随机访问文件指定偏移位置(定长记录)

应使用文本模式("r" / "w" / std::ios::in / std::ios::out)的场景:

  • 读写人类可读的配置文件、日志、CSV、JSON 等
  • 内容需要在文本编辑器中直接查看或编辑
  • 需要平台原生换行符自动转换

注意: Qt 和 MFC 默认二进制模式,与 C/C++ 标准库默认文本模式不同,跨库混用时务必确认模式一致。

性能优化

  • 大量小文件写入时,使用缓冲区
  • 大文件考虑内存映射
  • 频繁读写考虑使用 QBuffer
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值