请转移到文件
操作文件
main.cpp
#include <iostream>
#include <fstream>
#include "mclog.h"
int main(int argc, char **argv)
{
// 定义文件名称,没有执行路径,文件会在执行目录下生成
std::string file_fstream = "file_fstream.txt";
// std::ios::out 重写文本文件,以前的内容直接被清空
// 代码被 { } 空作用域包围,用于限制变量名有效范围,变量名称一旦离开作用域就会被销毁
{
// 创建文件操作对象
std::fstream fs(file_fstream, std::ios::out);
// 判断是否成功打开
if (fs.is_open())
{
fs << "由 fstream 类型打开\n";
fs << "hello world!";
// 关闭文件
fs.close();
}
}
// std::ios::in 读取文本文件,不可以写入,但是可以读取
{
MCLOG("ifstream 第一次读取");
std::fstream fs(file_fstream, std::ios::in);
if (fs.is_open())
{
std::string buff;
while (std::getline(fs, buff))
{
MCLOG($(buff));
}
fs.close();
}
}
// 使用 std::ofstream 默认自带 std::ios::out 参数,可以直接写入
// std::ios::app 追加文本文件,从文件中读取原本内容后添加新内容
{
std::ofstream fs(file_fstream, std::ios::app);
if (fs.is_open())
{
fs << "\n追加了一段内容";
fs.close();
}
}
// 使用 ifstream 默认自带 std::ios::in 参数,可以读取内容
// 读取查看是否成功追加
{
MCLOG("\nifstream 第二次读取");
std::ifstream fs(file_fstream);
if (fs.is_open())
{
std::string buff;
while (std::getline(fs, buff))
{
MCLOG($(buff));
}
fs.close();
}
}
// 声明坐标结构
struct coord
{
int x = 0;
int y = 0;
int z = 0;
};
// 定义存储二进制数据的文件名称
std::string file_file_binary = "file_file_binary.txt";
// std::ios::out | std::ios::binary 重写内容与二进制模式,写入二进制内容到文件
{
std::fstream fs(file_file_binary, std::ios::out | std::ios::binary);
if (fs.is_open())
{
// 将这个坐标的数据的二进制数据转移到文件
coord obj;
obj.x = 210;
obj.y = 73;
obj.z = 16;
fs.write(reinterpret_cast<const char *>(&obj), sizeof(obj));
fs.close();
}
}
// std::ios::in | std::ios::binary 读取与二进制模式,从文件读取二进制内容
{
MCLOG("\n读取二进制文件数据");
std::fstream fs(file_file_binary, std::ios::in | std::ios::binary);
if (fs.is_open())
{
// 将二进制内容复制到 x 变量的地址,需要确认二进制的内容是否有效
std::string buff;
coord obj;
fs.read(reinterpret_cast<char *>(&obj), sizeof(obj));
fs.close();
MCLOG($(obj.x) $(obj.y) $(obj.z));
}
}
return 0;
}
打印结果
ifstream 第一次读取 [/home/red/open/github/mcpp/example/11/main.cpp:30]
[buff: 由 fstream 类型打开] [/home/red/open/github/mcpp/example/11/main.cpp:37]
[buff: hello world!] [/home/red/open/github/mcpp/example/11/main.cpp:37]
ifstream 第二次读取 [/home/red/open/github/mcpp/example/11/main.cpp:57]
[buff: 由 fstream 类型打开] [/home/red/open/github/mcpp/example/11/main.cpp:64]
[buff: hello world!] [/home/red/open/github/mcpp/example/11/main.cpp:64]
[buff: 追加了一段内容] [/home/red/open/github/mcpp/example/11/main.cpp:64]
读取二进制文件数据 [/home/red/open/github/mcpp/example/11/main.cpp:98]
[obj.x: 210] [obj.y: 73] [obj.z: 16] [/home/red/open/github/mcpp/example/11/main.cpp:108]
打开一个文件
处理文件内容是见常见的事情,我们通常需要将数据保存在各种文件中
在C++11中,可以使用 fstream ofstream ifstream 这三个类来读取和写入文件,在使用他们打开一个文件时,如果文件不存在则会自动创建一个新文件
当写入文件时,如果你想保持已有的文件内容,请记得使用追加模式
文件三部曲
std::fstream fs("test.txt");
if (fs.is_open())
{
fs.close();
}
在使用C++11提供的 fstream 文件操作类时,我们需要遵循操作文件的三个步骤,创建文件操作对象,判断文件是否成功打开,文件使用后关闭
这是使用文本的关键步骤,文件不一定可以成功打开,所以需要判断,如果打开失败,后续的操作就无法执行
要记得使用完成之后关闭文件,否则这个文件的使用权会一直在你的手上,直到你关闭文件,如果在 Windows 系统上,只要你不关闭,别人就无法打开,尽管获取文件之后什么都不干也是如此
及时关闭文件是 编程规范 的重要一步
读取和写入文件
在写入文本文件时可以使用 << 符号将内容推入到文件中,这个使用逻辑与 cout 是一致的
读取时使用 getline 函数循环读取,直到文件末尾,getline 需要一个 string 来存储数据,每一次读取之后,这个 string 的内容就会发生变化
如果你需要写入和读取二进制内容,需要打开二进制模式,而且你需要使用 write read 等函数来指定读取或者写入的字节(byte)内容
空作用域
你会发现在 main.cpp 文件中,有特别多的 { } 的作用域,这些作用域类似函数一样,他们能将变量隔绝在一个区域内,这样写可以限制变量的范围,你就可以在同一个函数下什么相同的变量名称,也可以让独自运行的代码划分出不同的区域
这种空作用域的使用是有好处的,他们能让变量起来作用域之后即刻释放,而且分区也可以让代码看上去更加聚拢,如果你有类似结构的代码,我推荐你使用空作用域,他们造成的性能差异是微乎其微的
二进制文件
二进制文件通常是很少用到的,在 main.cpp 例子中使用二进制文件存储结构体数据,这个在实际开发中是不可能的,因为结构体内只要存储的是指针而不是真实数据就会无法存入文件,所以二进制模式通常不是用来存储数据的
操作二进制文件的用途更多的是用于传输文件,通过二进制模式打开文件之后,读取文件的二进制数据字节,将字节到另一个电脑上再重新组装,他们可以完整的恢复出来
文件指针
在文件中存在一个文件指针,不管是写入还是读取都会让指针移动,通常写入时指针总是在文件的最末尾的位置,如果你想覆盖前面的内容可以让文件指针向前移动,然后写入内容
读取时文件指针在首位,当第一次读取整个文件时,文件指针会随着读取的进度到到达尾部,一旦到达 EOF 文件结束标记,文件都无法在读取内容了,如果你想再次读取,你需要向前移动文件指针
文件指针是操作系统层面的内容,与编程语言关联不大,你可以自行学习文件指针相关内容
常用存储文件格式
通常读取和写入文件都不会是操作 txt 格式的文件,这种文件不方便存储数据结构,将结构体存储到 txt 格式的文件上是愚蠢的行为
如果你需要存储结构体,你需要了解 json xml ini 等更方便存储数据结构的文件格式,然后将你的结构体数据存储到这些文件格式上
相关的文件格式读取与写入需要你自行学习
运行结果
项目结构
.
├── 11
│ ├── build
│ │ ├── file_file_binary.txt
│ │ ├── file_fstream.txt
│ │ └── mcpp
│ └── main.cpp
├── CMakeLists.txt
├── common
└── run.sh
file_fstream.txt
由 fstream 类型打开
hello world!
追加了一段内容
file_fstream.txt 是文本文件可以打开
file_file_binary.txt 文件为二进制内容无法打开
项目路径
https://github.com/HellowAmy/mcpp.git