我的C++规范 - 请转移到文件

请转移到文件

操作文件

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
相关推荐
HalvmånEver2 小时前
Linux:信号初识上(信号一)
linux·运维·服务器·c++·系统架构·信号
从此不归路2 小时前
Qt5 进阶【1】信号与槽机制深度剖析——从语法到运行时调度
开发语言·qt
w***76552 小时前
PHP vs Go:动态与静态语言的巅峰对决
开发语言·golang·php
大闲在人2 小时前
25. 连续盘点系统(Q-R 策略):总成本优化与基于缺货成本的再订货点设定
开发语言·数据分析·供应链管理·智能制造·工业工程
skywalk81632 小时前
介绍一下QuantConnect Lean(python 15k star)
开发语言·python·量化
不凡而大米、2 小时前
报错:传入的请求具有过多的参数。该服务器支持最多2100个参数
java·开发语言·mybatis
打工的小王2 小时前
单例模式的实现
java·开发语言·单例模式
strive-debug2 小时前
cpp篇~~类和对象
开发语言·c++
是宇写的啊2 小时前
单例模式-阻塞队列
java·开发语言·单例模式