C++文件操作,2024年最新这份火爆全网的452页Golang Framework内核解析

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注go)
img

正文

int main() {
const char *url =“http://c.biancheng.net/cplus/”;
//创建一个 fstream 类对象
fstream fs;
//将 test.txt 文件和 fs 文件流关联
fs.open(“test.txt”, ios::out);
//向test.txt文件中写入 url 字符串
fs.write(url, 30);
fs.close();
return 0;
}

执行程序,该程序同目录下会生成一个 test.txt 文件,该文件的内容为:

http://c.biancheng.net/cplus/

注意,初学者只需借助注释看懂程序执行流程即可,具体的代码实现不必深究,后续章节会做详细讲解。

值得一提的是,无论是读取文件中的数据,还是向文件中写入数据,最先要做的就是调用 open() 成员方法打开文件。同时在操作文件结束后,还必须要调用 close() 成员方法关闭文件。关于如何使用 open() 函数打开一个文件,下一节会做详细介绍。

关注公众号「站长严长生」,在手机上阅读所有教程,随时随地都能学习。本公众号由站长亲自运营,长期更新,坚持原创,专注于分享创业故事+学习历程+工作记录+生活日常+编程资料。

C++ open 打开文件(含打开模式一览表)

在对文件进行读写操作之前,先要打开文件。打开文件有以下两个目的:

  • 通过指定文件名,建立起文件和文件流对象的关联,以后要对文件进行操作时,就可以通过与之关联的流对象来进行。
  • 指明文件的使用方式。使用方式有只读、只写、既读又写、在文件末尾添加数据、以文本方式使用、以二进制方式使用等多种。

打开文件可以通过以下两种方式进行:

  • 调用流对象的 open 成员函数打开文件。
  • 定义文件流对象时,通过构造函数打开文件。

使用 open 函数打开文件

先看第一种文件打开方式。以 ifstream 类为例,该类有一个 open 成员函数,其他两个文件流类也有同样的 open 成员函数:

void open(const char* szFileName, int mode)

第一个参数是指向文件名的指针,第二个参数是文件的打开模式标记。

文件的打开模式标记代表了文件的使用方式,这些标记可以单独使用,也可以组合使用。表 1 列出了各种模式标记单独使用时的作用,以及常见的两种模式标记组合的作用。

模式标记适用对象作用
ios::inifstream fstream打开文件用于读取数据。如果文件不存在,则打开出错。
ios::outofstream fstream打开文件用于写入数据。如果文件不存在,则新建该文件;如果文件原来就存在,则打开时清除原来的内容。
ios::appofstream fstream打开文件,用于在其尾部添加数据。如果文件不存在,则新建该文件。
ios::ateifstream打开一个已有的文件,并将文件读指针指向文件末尾(读写指 的概念后面解释)。如果文件不存在,则打开出错。
ios:: truncofstream打开文件时会清空内部存储的所有数据,单独使用时与 ios::out 相同。
ios::binaryifstream ofstream fstream以二进制方式打开文件。若不指定此模式,则以文本模式打开。
ios::inios::outfstream
ios::inios::outofstream
ios::inios::outios::trunc

ios::binary 可以和其他模式标记组合使用,例如:

  • ios::in | ios::binary表示用二进制模式,以读取的方式打开文件。
  • ios::out | ios::binary表示用二进制模式,以写入的方式打开文件。

文本方式与二进制方式打开文件的区别其实非常微小,我会在《文件的文本打开方式和二进制打开方式的区别》一节中专门解释。一般来说,如果处理的是文本文件,那么用文本方式打开会方便一些。但其实任何文件都可以以二进制方式打开来读写。

在流对象上执行 open 成员函数,给出文件名和打开模式,就可以打开文件。判断文件打开是否成功,可以看“对象名”这个表达式的值是否为 true,如果为 true,则表示文件打开成功。

下面的程序演示了如何打开文件:

#include
#include
using namespace std;
int main()
{
ifstream inFile;
inFile.open(“c:\tmp\test.txt”, ios::in);
if (inFile) //条件成立,则说明文件打开成功
inFile.close();
else
cout << “test.txt doesn’t exist” << endl;
ofstream oFile;
oFile.open(“test1.txt”, ios::out);
if (!oFile) //条件成立,则说明文件打开出错
cout << “error 1” << endl;
else
oFile.close();
oFile.open(“tmp\test2.txt”, ios::out | ios::in);
if (oFile) //条件成立,则说明文件打开成功
oFile.close();
else
cout << “error 2” << endl;
fstream ioFile;
ioFile.open(“…\test3.txt”, ios::out | ios::in | ios::trunc);
if (!ioFile)
cout << “error 3” << endl;
else
ioFile.close();
return 0;
}

调用 open 成员函数时,给出的文件名可以是全路径的,如第 7 行的c:\\tmp\\test.txt, 指明文件在 c 盘的 tmp 文件夹中;也可以只给出文件名,如第 13 行的test1.txt,这种情况下程序会在当前文件夹(也就是可执行程序所在的文件夹)中寻找要打开的文件。

第 18 行的tmp\\test2.txt给出的是相对路径,说明 test2.txt 位于当前文件夹的 tmp 子文件夹中。第 24 行的..\\test3.txt也是相对路径,代表上一层文件夹,此时要到当前文件夹的上一层文件夹中查找 test3.txt。此外,..\\..\\test4.txt..\\tmp\\test4.txt等都是合法的带相对路径的文件名。

使用流类的构造函数打开文件

定义流对象时,在构造函数中给出文件名和打开模式也可以打开文件。以 ifstream 类为例,它有如下构造函数:

ifstream::ifstream (const char* szFileName, int mode = ios::in, int);

第一个参数是指向文件名的指针;第二个参数是打开文件的模式标记,默认值为ios::in; 第三个参数是整型的,也有默认值,一般极少使用。

在定义流对象时打开文件的示例程序如下(用流类的构造函数打开文件):

#include
#include
using namespace std;
int main()
{
ifstream inFile(“c:\tmp\test.txt”, ios::in);
if (inFile)
inFile.close();
else
cout << “test.txt doesn’t exist” << endl;
ofstream oFile(“test1.txt”, ios::out);
if (!oFile)
cout << “error 1”;
else
oFile.close();
fstream oFile2(“tmp\test2.txt”, ios::out | ios::in);
if (!oFile2)
cout << “error 2”;
else
oFile.close();
return 0;
}

注意,当不再对打开的文件进行任何操作时,应及时调用 close() 成员方法关闭文件。有关该方法的用法,后续会做详细讲解。

文本打开方式和二进制打开方式的区别是什么?

在学习了 C++ 文件流对象使用 open() 打开文件后,我们知道它的第二个参数是一个字符串,用来表示文件打开方式,即如果使用 ios::binary,则表示以二进制方式打开文件;反之,则以文本文件的方式打开文件。

文本文件和二进制文件的区别

根据我们以往的经验,文本文件通常用来保存肉眼可见的字符,比如 .txt文件、.c文件、.dat文件等,用文本编辑器打开这些文件,我们能够顺利看懂文件的内容。

二进制文件通常用来保存视频、图片、程序等不可阅读的内容,用文本编辑器打开这些文件,会看到一堆乱码,根本看不懂。

但是从物理上讲,二进制文件和字符文件并没有什么区别,它们都是以二进制的形式保存在磁盘上的数据。

我们之所以能看懂文本文件的内容,是因为文本文件中采用的是 ASCII、UTF-8、GBK 等字符编码,文本编辑器可以识别出这些编码格式,并将编码值转换成字符展示出来。

而二进制文件使用的是 mp4、gif、exe 等特殊编码格式,文本编辑器并不认识这些编码格式,只能按照字符编码格式胡乱解析,所以就成了一堆乱七八糟的字符,有的甚至都没见过。

如果我们新建一个 mp4 文件,给它写入一串字符,然后再用文本编辑器打开,你一样可以读得懂,有兴趣的读者可以自己试试。

总的来说,不同类型的文件有不同的编码格式,必须使用对应的程序(软件)才能正确解析,否则就是一堆乱码,或者无法使用。

两种打开方式的区别

文本方式和二进制方式并没有本质上的区别,只是对于换行符的处理不同。

在 UNIX/Linux 平台中,用文本方式或二进制方式打开文件没有任何区别,因为文本文件以 \n(ASCII 码为 0x0a)作为换行符号。

但在 Windows 平台上,文本文件以连在一起的 \r\n 作为换行符号。如果以文本方式打开文件,当读取文件时,程序会将文件中所有的 \r\n 转换成一个字符 \n。也就是说,如果文本文件中有连续的两个字符是 \r\n,则程序会丢弃前面的 \r,只读入 \n。

同样当写入文件时,程序会将 \n 转换成 \r\n 写入。也就是说,如果要写入的内容中有字符 \n,则在写入该字符前,程序会自动先写入一个 \r。

因此在 Windows 平台上,如果用文本方式打开二进制文件进行读写,读写的内容就可能和文件的内容有出入。

总的来说,Linux 平台使用哪种打开方式都行;Windows 平台上最好用 “ios::in | ios::out” 等打开文本文件,用 “ios::binary” 打开二进制文件。但无论哪种平台,用二进制方式打开文件总是最保险的。

C++ close()关闭文件方法详解

C++ open打开文件》一节中,详细介绍了文件流对象如何调用 open() 成员方法打开指定文件。相对应地,文件流对象还可以主动关闭先前打开的文件,即调用 close() 成员方法。

我们知道,调用 open() 方法打开文件,是文件流对象和文件之间建立关联的过程。那么,调用 close() 方法关闭已打开的文件,就可以理解为是切断文件流对象和文件之间的关联。注意,close() 方法的功能仅是切断文件流与文件之间的关联,该文件流并会被销毁,其后续还可用于关联其它的文件。

close() 方法的用法很简单,其语法格式如下:

void close( )

可以看到,该方法既不需要传递任何参数,也没有返回值。

举个例子:

#include
using namespace std;
int main()
{
const char *url=“http://c.biancheng.net/cplus/”;
ofstream outFile(“url.txt”, ios::out);
//向 url.txt 文件中写入字符串
outFile.write(url, 30);
//关闭已打开的文件
outFile.close();
return 0;
}

运行程序,在该程序同目录下会生成一个 url.txt 文件,其内部存储的数据为:

http://c.biancheng.net/cplus/

有些读者可能发现,即便上面程序中不调用 close() 方法,也能成功向 url.txt 文件中写入 url 字符串。这是因为,当文件流对象的生命周期结束时,会自行调用其析构函数,该函数内部在销毁对象之前,会先调用 close() 方法切断它与任何文件的关联,最后才销毁它。

强烈建议读者,使用 open() 方法打开的文件,一定要手动调用 close() 方法关闭,这样可以避免程序发生一些奇葩的错误!

值得一提的是,《C++处理输入输出错误》一节中介绍了 4 种流状态,它们也同样适用于文件流。当文件流对象未关联任何文件时,调用 close() 方法会失败,其会为文件流设置 failbit 状态标志,该标志可以被 fail() 成员方法捕获。例如:

#include
#include
using namespace std;
int main()
{
const char *url=“http://c.biancheng.net/cplus/”;
ofstream outFile;
outFile.close();
if (outFile.fail()) {
cout << “文件操作过程发生了错误!”;
}
return 0;
}

程序执行结果为:

文件操作过程发生了错误!

C++打开的文件一定要用close()方法关闭!

通过前面的学习我们知道,C++ 使用 open() 方法打开文件,使用 close() 方法关闭文件。例如(程序一):

#include //std::cout
#include //std::ofstream
using namespace std;
int main()
{
const char * url = “http://c.biancheng.net/cplus/”;
//以文本模式打开out.txt
ofstream destFile(“out.txt”, ios::out);
if (!destFile) {
cout << “文件打开失败” << endl;
return 0;
}
//向out.txt文件中写入 url 字符串
destFile << url;
//关闭打开的 out.txt 文件
destFile.close();
return 0;
}

执行该程序,会生成一个 out.txt 文件,内部存有如下内容:

http://c.biancheng.net/cplus/

前面提到,在某些情况下(例如上面程序中),即便不显式调用 close() 方法,文件的读写操作也能成功执行。因为当文件流对象的生命周期结束时,会自行调用析构函数,此函数内部会先调用 close() 方法切断文件流对象与任何文件的关联,最后才销毁它。

那么,既然文件流对象自行销毁时会隐式调用 close() 方法,是不是就不用显式调用 close() 方法了呢?

当然不是。在实际进行文件操作的过程中,对于打开的文件,要及时调用 close() 方法将其关闭,否则很可能会导致读写文件失败。

举个例子(程序二):

#include //std::cout
#include //std::ofstream
using namespace std;
int main()
{
const char * url = “http://c.biancheng.net/cplus/”;
//以文本模式打开out.txt
ofstream destFile(“out.txt”, ios::out);
if (!destFile) {
cout << “文件打开失败” << endl;
return 0;
}
//向out.txt文件中写入 url 字符串
destFile << url;
//程序抛出一个异常
throw “Exception”;
//关闭打开的 out.txt 文件
destFile.close();
return 0;
}

通过对比不难发现,此程序和程序一唯一的区别在于,第 17 行添加了抛出异常的语句。由于程序中没有对抛出的异常进行处理,因此当程序执行到此行时会崩溃。

更重要的是,第 17 行会导致文件写入操作失败。执行此程序,同样会生成 out.txt 文件,但 “http:c.biancheng.net/cplus/” 字符串并没有成功被写入。

也就是说,对于已经打开的文件,如果不及时关闭,一旦程序出现异常,则很可能会导致之前读写文件的所有操作失效。在程序二的基础上,如果将第 17 行代码和第 19 行代码互换,再次执行程序会发现,虽然程序执行仍会崩溃,但 “http:c.biancheng.net/cplus/” 字符串可以被成功写入到 out.txt 文件中。

C++ flush()刷新缓冲区

在很多实际场景中,即便已经对文件执行了写操作,但后续还可能会执行其他的写操作。对于这种情况,我们可能并不想频繁地打开/关闭文件,可以使用 flush() 方法及时刷新输出流缓冲区,也能起到防止写入文件失败的作用。

程序二之所以写入文件失败,是因为 << 写入运算符会先将 url 字符串写入到输出流缓冲区中,待缓冲区满或者关闭文件时,数据才会由缓冲区写入到文件中。但直到程序崩溃,close() 方法也没有得到执行,且 destFile 对象也没有正常销毁,所以 url 字符串一直存储在缓冲区中,没有写入到文件中。

比如,修改程序二的代码:

#include //std::cout
#include //std::ofstream
using namespace std;
int main()
{
const char * url = “http://c.biancheng.net/cplus/”;
//以文本模式打开out.txt
ofstream destFile(“out.txt”, ios::out);
if (!destFile) {
cout << “文件打开失败” << endl;
return 0;
}
//向out.txt文件中写入 url 字符串
destFile << url;
//刷新输出流缓冲区
destFile.flush();
//程序抛出一个异常
throw “Exception”;
//关闭打开的 out.txt 文件
destFile.close();
return 0;
}

可以看到,在程序二的基础上,在第 17 行调用了 flush() 方法。再次执行程序,虽然仍执行崩溃,但 “http://c.baincheng.net/cplus/” 字符串成功写入到了 out.txt 文件中。

总之,C++ 中使用 open() 打开的文件,在读写操作执行完毕后,应及时调用 close() 方法关闭文件,或者对文件执行写操作后及时调用 flush() 方法刷新输出流缓冲区。

C++文本文件读写操作详解

前面章节中,已经给大家介绍了文件流对象如何调用 open() 方法打开文件,并且在读写(又称 I/O )文件操作结束后,应调用 close() 方法关闭先前打开的文件。那么,如何实现对文件内容的读写呢?接下来就对此问题做详细的讲解。

在讲解具体读写文件的方法之前,读者首先要搞清楚的是,对文件的读/写操作又可以细分为 2 类,分别是以文本形式读写文件和以二进制形式读写文件。

  1. 我们知道,文件中存储的数据并没有类型上的分别,统统都是字符。所谓以文本形式读/写文件,就是直白地将文件中存储的字符(或字符串)读取出来,以及将目标字符(或字符串)存储在文件中。
  2. 而以二进制形式读/写文件,操作的对象不再是打开文件就能看到的字符,而是文件底层存储的二进制数据。更详细地讲,当以该形式读取文件时,读取的是该文件底层存储的二进制数据;同样,当将某数据以二进制形式写入到文件中时,写入的也是其对应的二进制数据。

举个例子,假设我们以文本形式将浮点数 19.625 写入文件,则该文件会直接将 “19.625” 这个字符串存储起来。当我们双击打开此文件,也可以看到 19.625。值得一提的是,由非字符串数据(比如这里的浮点数 19.625)转换为对应字符串(转化为 “19.625”)的过程,C++ 标准库已经实现好了,不需要我们操心。

但如果以二进制形式将浮点数 19.625 写入文件,则该文件存储的不再是 “19.625” 这个字符串,而是 19.625 浮点数对应的二进制数据。以 float 类型的 19.625 来说,文件最终存储的数据如下所示:

0100 0001 1001 1101 0000 0000 0000 0000

至于如何得出 float 类型的 19.625 对应的二进制,感兴趣的读者可阅读《小数在内存中是如何存储的》一节。

显然,如果直接将以上二进制数据转换为 float 类型,仍可以得到浮点数 19.625。但对于文件来说,它只会将存储的二进制数据根据既定的编码格式(如 utf-8、gbk 等)转换为一个个字符。这也就意味着,如果我们直接打开此文件,看到的并不会是 19.625,往往是一堆乱码。

C++ 标准库中,提供了 2 套读写文件的方法组合,分别是:

  1. 使用 >> 和 << 读写文件:适用于以文本形式读写文件;
  2. 使用 read() 和 write() 成员方法读写文件:适用于以二进制形式读写文件。

本节先讲解如何用 >> 和 << 实现以文本形式读写文件,至于如何实现以二进制形式读写文件,下一节会做详细介绍。

C++ >>和<<读写文本文件

通过《C++文件流类》一节的学习我们知道,fstream 或者 ifstream 类负责实现对文件的读取,它们内部都对 >> 输出流运算符做了重载;同样,fstream 和 ofstream 类负责实现对文件的写入,它们的内部也都对 << 输出流运算符做了重载。

所以,当 fstream 或者 ifstream 类对象打开文件(通常以 ios::in 作为打开模式)之后,就可以直接借助 >> 输入流运算符,读取文件中存储的字符(或字符串);当 fstream 或者 ofstream 类对象打开文件(通常以 ios::out 作为打开模式)后,可以直接借助 << 输出流运算符向文件中写入字符(或字符串)。

举个例子:

#include
#include
using namespace std;
int main()
{
int x,sum=0;
ifstream srcFile(“in.txt”, ios::in); //以文本模式打开in.txt备读
if (!srcFile) { //打开失败
cout << “error opening source file.” << endl;
return 0;
}
ofstream destFile(“out.txt”, ios::out); //以文本模式打开out.txt备写
if (!destFile) {
srcFile.close(); //程序结束前不能忘记关闭以前打开过的文件
cout << “error opening destination file.” << endl;
return 0;
}
//可以像用cin那样用ifstream对象
while (srcFile >> x) {
sum += x;
//可以像 cout 那样使用 ofstream 对象
destFile << x << " ";
}
cout << “sum:” << sum << endl;
destFile.close();
srcFile.close();
return 0;
}

注意,此程序中分别采用 ios::in 和 ios::out 打开文件,即以文本模式而非二进制模式打开文件。感兴趣的读者可在其基础上添加 ios::binary,即以二进制模式打开文件,程序依旧会正常执行。这是因为,以文本模式打开文件和以二进制模式打开文件,并没有很大的区别(后续章节会做详细讲解)。

执行此程序之前,必须在和该程序源文件同目录中手动创建一个 in.txt 文件,假设其内部存储的字符串为:

10 20 30 40 50

建立之后,执行程序,其执行结果为:

sum:150

同时在 in.txt 文件同目录下,会生成一个 out.txt 文件,其内部存储的字符和 in.txt 文件完全一样,读者可自行打开文件查看。

通过分析程序的执行结果不难理解,对于 in.txt 文件中的 “10 20 30 40 50” 字符串,srcFile 对象会依次将 “10”、“20”、“30”、“40”、“50” 读取出来,将它们解析成 int 类型的整数 10、20、30、40、50 并赋值给 x,同时完成和 sum 的加和操作。

同样,对于每次从 in.txt 文件读取并解析出的整形 x,destFile 对象都会原封不动地将其再解析成对应的字符串(如整数 10 解析成字符串 “10”),然后和 " " 空格符一起写入 out.txt 文件。

C++ read()和write()读写二进制文件(超级详细)

通过《C++文本文件读写操作》一节的学习,读者了解了以文本形式读写文件和以二进制形式读写文件的区别,并掌握了用重载的 >> 和 << 运算符实现以文本形式读写文件。在此基础上,本节继续讲解如何以二进制形式读写文件。

不过介绍具体的实现方法前,先给读者介绍一下相比以文本形式读写文件,以二进制形式读写文件有哪些好处?

举个例子,现在要做一个学籍管理程序,其中一个重要的工作就是记录学生的学号、姓名、年龄等信息。这意味着,我们需要用一个类来表示学生,如下所示:

class CStudent
{
char szName[20]; //假设学生姓名不超过19个字符,以 ‘\0’ 结尾
char szId[l0]; //假设学号为9位,以 ‘\0’ 结尾
int age; //年龄
};

前面章节中,我们学会了如何以文本形式读写文件,如果使用此方式存储学生的信息,则最终的文件中存储的学生信息可能是这个样子:

Micheal Jackson 110923412 17
Tom Hanks 110923413 18

要知道,这种存储学生信息的方式不但浪费空间,而且后期不利于查找指定学生的信息(查找效率低下),因为每个学生的信息所占用的字节数不同。

这种情况下,以二进制形式将学生信息存储到文件中,是非常不错的选择,因为以此形式存储学生信息,可以直接把 CStudent 对象写入文件中,这意味着每个学生的信息都只占用 sizeof(CStudent) 个字节。

值得一提的是,要实现以二进制形式读写文件,<< 和 >> 将不再适用,需要使用 C++ 标准库专门提供的 read() 和 write() 成员方法。其中,read() 方法用于以二进制形式从文件中读取数据;write() 方法用于以二进制形式将数据写入文件。

C++ ostream::write()方法写文件

ofstream 和 fstream 的 write() 成员方法实际上继承自 ostream 类,其功能是将内存中 buffer 指向的 count 个字节的内容写入文件,基本格式如下:

ostream & write(char* buffer, int count);

其中,buffer 用于指定要写入文件的二进制数据的起始位置;count 用于指定写入字节的个数。

也就是说,该方法可以被 ostream 类的 cout 对象调用,常用于向屏幕上输出字符串。同时,它还可以被 ofstream 或者 fstream 对象调用,用于将指定个数的二进制数据写入文件。

同时,该方法会返回一个作用于该函数的引用形式的对象。举个例子,obj.write() 方法的返回值就是对 obj 对象的引用。

需要注意的一点是,write() 成员方法向文件中写入若干字节,可是调用 write() 函数时并没有指定这些字节写入文件中的具体位置。事实上,write() 方法会从文件写指针指向的位置将二进制数据写入。所谓文件写指针,是是 ofstream 或 fstream 对象内部维护的一个变量,文件刚打开时,文件写指针指向的是文件的开头(如果以 ios::app 方式打开,则指向文件末尾),用 write() 方法写入 n 个字节,写指针指向的位置就向后移动 n 个字节。

下面的程序演示了如何将学生信息以二进制形式写入文件:

#include
#include
using namespace std;
class CStudent
{
public:
char szName[20];
int age;
};
int main()
{
CStudent s;
ofstream outFile(“students.dat”, ios::out | ios::binary);
while (cin >> s.szName >> s.age)
outFile.write((char*)&s, sizeof(s));
outFile.close();
return 0;
}

输入:

Tom 60↙
Jack 80↙
Jane 40↙
^Z↙

其中,表示输出换行符,^Z 表示输入Ctrl+Z组合键结束输入。

执行程序后,会自动生成一个 students.dat 文件,其内部存有 72 字节的数据,如果用“记事本”打开此文件,可能看到如下乱码:

Tom 烫烫烫烫烫烫烫烫< Jack 烫烫烫烫烫烫烫蘌 Jane 烫烫烫烫烫烫烫?

值得一提的是,程序中第 13 行指定文件的打开模式为 ios::out | ios::binary,即以二进制写模式打开。在 Windows平台中,以二进制模式打开文件是非常有必要的,否则可能出错,原因会在《文件的文本打开方式和二进制打开方式的区别》一节中介绍。

另外,第 15 行将 s 对象写入文件。s 的地址就是要写入文件的内存缓冲区的地址,但是 &s 不是 char * 类型,因此要进行强制类型转换;第 16 行,文件使用完毕一定要关闭,否则程序结束后文件的内容可能不完整。

C++ istream::read()方法读文件

ifstream 和 fstream 的 read() 方法实际上继承自 istream 类,其功能正好和 write() 方法相反,即从文件中读取 count 个字节的数据。该方法的语法格式如下:

istream & read(char* buffer, int count);

其中,buffer 用于指定读取字节的起始位置,count 指定读取字节的个数。同样,该方法也会返回一个调用该方法的对象的引用。

和 write() 方法类似,read() 方法从文件读指针指向的位置开始读取若干字节。所谓文件读指针,可以理解为是 ifstream 或 fstream 对象内部维护的一个变量。文件刚打开时,文件读指针指向文件的开头(如果以 ios::app 方式打开,则指向文件末尾),用 read() 方法读取 n 个字节,读指针指向的位置就向后移动 n 个字节。因此,打开一个文件后连续调用 read() 方法,就能将整个文件的内容读取出来。

通过执行 write() 方法的示例程序,我们将 3 个学生的信息存储到了 students.dat 文件中,下面程序演示了如何使用 read() 方法将它们读取出来:

#include
#include
using namespace std;
class CStudent
{
public:
char szName[20];
int age;
};
int main()
{
CStudent s;
ifstream inFile(“students.dat”,ios::in|ios::binary); //二进制读方式打开
if(!inFile) {
cout << “error” <<endl;
return 0;
}
while(inFile.read((char *)&s, sizeof(s))) { //一直读到文件结束
cout << s.szName << " " << s.age << endl;
}
inFile.close();
return 0;
}

程序的输出结果是:

Tom 60
Jack 80
Jane 40

注意,程序中第 18 行直接将 read() 方法作为 while 循环的判断条件,这意味着,read() 方法会一直读取到文件的末尾,将所有字节全部读取完毕,while 循环才会终止。

另外,在使用 read() 方法的同时,如果想知道一共成功读取了多少个字节(读到文件尾时,未必能读取 count 个字节),可以在 read() 方法执行后立即调用文件流对象的 gcount() 成员方法,其返回值就是最近一次 read() 方法成功读取的字节数。感兴趣的读者可自行尝试,这里不再做具体演示。

C++ get()和put()读写文件详解

在某些特殊的场景中,我们可能需要逐个读取文件中存储的字符,或者逐个将字符存储到文件中。这种情况下,就可以调用 get() 和 put() 成员方法实现。

C++ ostream::put()成员方法

通过《C++ cout.put()》一节的学习,读者掌握了如何通过执行 cout.put() 方法向屏幕输出单个字符。我们知道,fstream 和 ofstream 类继承自 ostream 类,因此 fstream 和 ofstream 类对象都可以调用 put() 方法。

当 fstream 和 ofstream 文件流对象调用 put() 方法时,该方法的功能就变成了向指定文件中写入单个字符。put() 方法的语法格式如下:

ostream& put (char c);

其中,c 用于指定要写入文件的字符。该方法会返回一个调用该方法的对象的引用形式。例如,obj.put() 方法会返回 obj 这个对象的引用。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
ead() 方法成功读取的字节数。感兴趣的读者可自行尝试,这里不再做具体演示。

C++ get()和put()读写文件详解

在某些特殊的场景中,我们可能需要逐个读取文件中存储的字符,或者逐个将字符存储到文件中。这种情况下,就可以调用 get() 和 put() 成员方法实现。

C++ ostream::put()成员方法

通过《C++ cout.put()》一节的学习,读者掌握了如何通过执行 cout.put() 方法向屏幕输出单个字符。我们知道,fstream 和 ofstream 类继承自 ostream 类,因此 fstream 和 ofstream 类对象都可以调用 put() 方法。

当 fstream 和 ofstream 文件流对象调用 put() 方法时,该方法的功能就变成了向指定文件中写入单个字符。put() 方法的语法格式如下:

ostream& put (char c);

其中,c 用于指定要写入文件的字符。该方法会返回一个调用该方法的对象的引用形式。例如,obj.put() 方法会返回 obj 这个对象的引用。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-Ah6lvkJo-1713288891945)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值