之前写过两篇跟文件操作相关的博客,有兴趣也可以看一下:
C语言读写文件
Qt关于文件路径的处理
先讲一些关于基础文本文件和二进制文件的读写操作,后续将会整理C++/Qt关于ini、xml、json、xlsx相关文件的读写操作。
C++
相比于C语言使用FILE文件指针来实现文件操作,C++ 采用的是标准库中的fstream类来实现文件的打开、关闭、读取和写入。
引入头文件:
#include <fstream>
打开文件:
explicit ifstream(const char* fileName, ios_base::openmode mode = ios_base::in);
explicit ifstream(const string& fileName, ios_base::openmode mode = ios_base::in);
第一个参数表示文件名,第二个表示打开方式,关于打开方式有以下几种,以下是官方给出的定义说明:
// 27.4.2.1.4 Type ios_base::openmode
/**
* @brief This is a bitmask type.
*
* @c @a _Ios_Openmode is implementation-defined, but it is valid to
* perform bitwise operations on these values and expect the Right
* Thing to happen. Defined objects of type openmode are:
* - app
* - ate
* - binary
* - in
* - out
* - trunc
*/
typedef _Ios_Openmode openmode;
/// Seek to end before each write.
static const openmode app = _S_app;
/// Open and seek to end immediately after opening.
static const openmode ate = _S_ate;
/// Perform input and output in binary mode (as opposed to text mode).
/// This is probably not what you think it is; see
/// https://gcc.gnu.org/onlinedocs/libstdc++/manual/fstreams.html#std.io.filestreams.binary
static const openmode binary = _S_bin;
/// Open for input. Default for @c ifstream and fstream.
static const openmode in = _S_in;
/// Open for output. Default for @c ofstream and fstream.
static const openmode out = _S_out;
/// Open for input. Default for @c ofstream.
static const openmode trunc = _S_trunc;
ios::in | 以读取的方式打开文件 |
ios::out | 以写入的方式打开文件,如果文件不存在则会创建文件 |
ios::ate | 打开文件时定位到文件尾部 |
ios::app | 以追加的形式打开文件,写入的内容将会添加到文件末尾 |
ios::trunc | 打开文件时将清空文件原有的内容 |
ios::binary | 以二进制的方式打开文件 |
这些方式可以采用“|”组合使用,例如:
fstream file;
file.open("1.txt", ios::out | ios::app);
以写入的方式打开文件1.txt,写入的内容将会追加到文件末尾。
关闭文件:
close()
读取文件示例:
fstream file;
file.open("1.txt", ios::in);
if (file.is_open()) {
string line;
while (getline(file, line)) {
cout << line << endl;
}
file.close();
}
只读方式打开文件1.txt,如果该文件存在则会逐行打印文件内容
1.txt文件内容:
运行结果:
写文件示例:
fstream file;
file.open("1.dat", ios::out | ios::trunc);
if (file.is_open()) {
file << "123";
file << endl;
file << "456";
file << endl;
file.close();
}
以写文件的方式打开文件1.dat并且会先清空文件原有内容,执行后文件内容为:
Qt
Qt关于文件的打开、关闭、读取、写入操作将会用QFile、QTextStream、QDataStream,其中QFile负责文件的打开与关闭操作,QTextStream和QDataStream将以文本数据流和二进制数据流的方式读写文件。
打开文件:
bool open(OpenMode flags) override;
bool open(FILE *f, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
bool open(int fd, OpenMode ioFlags, FileHandleFlags handleFlags=DontCloseHandle);
也是需要指定文件的打开OpenMode,OpenMode有以下定义:
QIODevice::NotOpen | 设备未打开 |
QIODevice::ReadOnly | 只读形式打开 |
QIODevice::WriteOnly | 写文件形式打开,文件不存在则会创建文件 |
QIODevice::ReadWrite | 读写形式打开 |
QIODevice::Append | 追加形式打开,写入内容将添加到文件尾 |
QIODevice::Truncate | 截断形式打开,会清除文件原版内容 |
QIODevice::Text | 文本形式打开,读取时,行结束符被翻译为'\n'。在写入时,行结束符被转换为本地编码,例如Win32中的'\r\n' |
QIODevice::Unbuffered | 无缓冲形式打开,设备中的任何缓冲区都被绕过 |
QIODevice::NewOnly | 如果要打开的文件已经存在,则失败。仅在文件不存在时创建并打开该文件。操作系统保证您是唯一创建和打开文件的人。注意,此模式意味着WriteOnly,并且允许将其与ReadWrite结合使用。这个标志目前只影响QFile。其他类将来可能会使用此标志,但在此之前,对QFile以外的任何类使用此标志可能会导致未定义的行为(自Qt 5.11起) |
QIODevice::ExistingOnly | 如果要打开的文件不存在,则失败。此标志必须与ReadOnly, WriteOnly或ReadWrite一起指定。注意,单独对ReadOnly使用此标志是多余的,因为当文件不存在时,ReadOnly已经失败了。这个标志目前只影响QFile。其他类将来可能会使用此标志,但在此之前,对QFile以外的任何类使用此标志可能会导致未定义的行为(自Qt 5.11起) |
这些也是可以使用“|”一起使用的。
关闭文件:
close()
QTextStream:
QTextStream以文本数据流的形式读写文件。
头文件:
#include <QTextStream>
读文件示例:
QFile file("1.txt");
if (file.open(QIODevice::ReadOnly)) {
QTextStream in(&file);
while (!in.atEnd())
{
qDebug()<<in.readLine();
}
file.close();
}
以只读的形式打开1.txt文件,然后逐行打印文件内容。
写文件示例:
QFile file("1.txt");
if (file.open(QIODevice::WriteOnly|QIODevice::Append)) {
QTextStream out(&file);
out<<"123aa";
out<<endl;
out<<"456aa";
out<<endl;
file.close();
}
以写文件的形式打开,并且写入的内容会在文件末尾追加内容。
QDataStream:
QDataStream是以二进制数据流的形式进行文件的读写操作,用于将二进制数据到 QIODevice 的序列化。
头文件:
#include <QDataStream>
示例:
QFile file("1.dat");
if (file.open(QIODevice::WriteOnly|QIODevice::Truncate)) {
QDataStream out(&file);
out << QString("abc");
out << (int)123;
file.close();
}
以写文件以及截断方式打开文件1.dat,依次写入字符串“abc”和int整形123,程序执行后用notepad++打开对应文件预览:
可以看到因为是二进制形式写入文件中所以是不支持预览的,但是用对应的QDataStream可以直接读取:
QFile file("1.dat");
if (file.open(QIODevice::ReadOnly)) {
QDataStream in(&file);
int i;
QString s;
in>>s;
in>>i;
qDebug()<<i<<s;
file.close();
}
运行结果:
将图片数据写入文件:
QFile file("1.dat");
QFile pic("1.png");
if (file.open(QIODevice::WriteOnly|QIODevice::Truncate) && pic.open(QIODevice::ReadOnly)) {
QDataStream out(&file);
out << pic.fileName();
out << pic.readAll();
file.close();
}
将图片文件1.png的文件名和文件数据写入到文件1.dat中 ,反正也可以读取对应图片数据生成对应图片文件:
QFile file("1.dat");
if (file.open(QIODevice::ReadOnly)) {
QDataStream in(&file);
QByteArray data;
QString name;
in>>name;
in>>data;
QPixmap pix;
pix.loadFromData(data);
pix.save(name);
file.close();
}
QDataStream读写自定义数据:
比如用DataStream实现自定义结构体数据的读写。
struct MyStruct {
int i;
QString s;
double d;
friend QDataStream& operator <<(QDataStream &stream, const MyStruct &ms)
{
stream<<ms.i<<ms.s<<ms.d;
return stream;
}
friend QDataStream& operator >>(QDataStream &stream, MyStruct &ms)
{
stream>>ms.i>>ms.s>>ms.d;
return stream;
}
};
需要重载对应<<和>>操作符
QFile file("1.dat");
if (file.open(QIODevice::WriteOnly|QIODevice::Truncate)) {
QDataStream out(&file);
MyStruct my;
my.i = 1;
my.s = "a";
my.d = 1.1;
out<<my;
file.close();
}
读取:
if (file.open(QIODevice::ReadOnly)) {
QDataStream in(&file);
MyStruct ms;
in>>ms;
qDebug()<<ms.i<<ms.s<<ms.d;
file.close();
}
运行效果:
成功读取对应文件中的结构体数据。