0
点赞
收藏
分享

微信扫一扫

【C++grammar】文件I/O流的基本用法


目录

  • ​​1、输入输出类介绍​​
  • ​​1.C/C++文件操作对比​​
  • ​​2.什么是流?​​
  • ​​3.C++ I/O流类层次​​
  • ​​4.带缓冲的输入输出​​
  • ​​5.gcc编译器cin.in_avail()​​
  • ​​2、向文件写入数据​​
  • ​​1.写文件小练习​​
  • ​​2.如何将信息同时输出到文件和屏幕?​​
  • ​​3、从文件读数据​​
  • ​​1.检测文件是否成功打开​​
  • ​​2.检测是否已到文件末尾​​
  • ​​3.读取文件小练习​​
  • ​​4.bad()函数能否用来判断文件流是否成功打开?​​


1、输入输出类介绍

1.C/C++文件操作对比

【C++grammar】文件I/O流的基本用法_编程语言

2.什么是流?

流是一个数据序列。
一个流是有两个端点的,一边是data source(数据源),一边是程序。
一个I / O流表示输入源或输出目的地。流可以表示许多不同种类的源和目标,包括磁盘文件,设备,其他程序和内存阵列。
流支持许多不同类型的数据,包括简单字节,原始数据类型,本地化字符和对象。一些流只是传递数据;其他则以有用的方式操纵和转换数据。
无论它们在内部如何工作,所有流都向使用它们的程序提供相同的简单模型:流是数据序列。
程序使用输入流从源中一次读取一项数据:
【C++grammar】文件I/O流的基本用法_流_02

程序使用输出流将数据写入目的地,一次写入一项:
【C++grammar】文件I/O流的基本用法_#include_03
摘自:​​​I / O流​​

3.C++ I/O流类层次

【C++grammar】文件I/O流的基本用法_流_04

C++的流类主要有五类:



流基类(ios_base和ios)
标准输入输出流类(istream/ostream/iostream)
字符串流类(istringstream/ostringstream)
文件流类(ifstream/ofstream/fstream)
缓冲区类(streambuf/stringbuf/filebuf)



标准输入输出流对象 cin 和 cout 分别是类 istream 和 ostream 的实例

字符串流:将各种不同的数据格式化输出到一个字符串中,可以使用I/O操纵器控制格式;反之也可以从字符串中读入各种不同的数据。

4.带缓冲的输入输出

C++的I/O流是有内部缓冲区的。
c = cin.get(void)每次读取一个字符并把由Enter键生成的换行符留在输入队列中

#include<iostream>

using namespace std;

int main() {
char c;
int i = 0;
do {
c = cin.get();
cout << ++i << " : " <<
static_cast<int>(c) << endl;
} while (c != 'q');
return 0;

}

【C++grammar】文件I/O流的基本用法_#include_05

本部分要展示的内容如下:
1、键盘输入一个字母后回车,实际进入缓冲区的是两个字符
2、使用cin输入信息后,有换行字符残留在缓冲区,从而导致return语句前的cin.get()不起作用

#include <iostream>

int main()
{
//拿到cin对象的缓冲区指针

auto p = std::cin.rdbuf();
//从键盘读入字符到缓冲区,保留所有字符在缓冲区

auto x = std::cin.peek();
std::cout << "x= " << x << std::endl;
//显示缓冲区中的字符数量
//由于每次读取返回值都不一样,所以先将初始值保存
auto count = p->in_avail();
std::cout << "There are " << count << "characters in the buffer." << std::endl;
//把缓冲区的字符都取出来并显示
for (int i = 0; i < count; i++)
{
std::cout << i + 1 << ":" << std::cin.get() << std::endl;
}

std::cin.get();
return 0;
}

5.gcc编译器cin.in_avail()

在使用gcc编译器的时候,存在这样一种意外的情况:

无论输入多少个字符, cin.in_avail()函数返回值永远是0。

这是由于GCC编译器中配套的libstdc++实现中的问题(可以看作是标准库gcc实现的一个bug,或者一个特性)。

解决办法是,在使用cin之前,插入下面一行代码

​cin.sync_with_stdio(false);​

简单解释原因:GCC的libstdc++默认是保证C++的cin与C的stdin同步的。

2、向文件写入数据

ofstrem可向文本文件中写数据.
输出数据的流程:
【C++grammar】文件I/O流的基本用法_#include_06
文件已存在,则直接清除内容。
Writing Data to a File – Auto type recognition (自动类型识别)

1.写文件小练习

本部分要展示的内容如下:
1、创建文件输出流
2、向文件写数据
output << “Lilei” << " " << 90.5 << endl;
output << “HanMeimei” << " " << 85 << endl;
3、关闭文件
4、用文本编辑器打开文件,对比代码语句检查结果

//std::c++latest
#include <fstream>
#include <iostream>
#include <filesystem>

using std::ifstream;
using std::ofstream;
using std::cout;
using std::endl;
namespace fs = std::filesystem;

int main()
{
//第一步,关联文件

fs::path p{ "scores.txt" };

//第二步,创建一个流输出对象
ofstream output{ p };

double lileiScore{ 90.5 };
int hanmeimeiScore{ 84 };

output << "Lilei " << lileiScore << endl;
output << "HanMeimei " << hanmeimeiScore << endl;

output.close();

cout << "size of " << p << " is " << fs::file_size(p) << endl;
std::cin.get();
return 0;
}

打开一个输出文件流的方法包括:
【C++grammar】文件I/O流的基本用法_数据_07

2.如何将信息同时输出到文件和屏幕?

在软件的调试技术中,很重要的一个技术是将软件运行过程中的一些信息写入到“日志文件”中。但是同时还要将信息显示到屏幕上,以方便程序员实时查看这些信息。
最简单的一种办法是这样的:

std::ofstream output("debug.log", ios::out);
output << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;
cout << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;

下面使用streambuf构造一个自己的类,来实现这个功能

#include <streambuf>
#include <iostream>
#include <fstream>

//Linux tee命令用于读取标准输入的数据,并将其内容输出成文件。
//tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。
class teebuf : public std::streambuf
{
public:
// Construct a streambuf which tees output to both input
// streambufs.
teebuf(std::streambuf* sb1, std::streambuf* sb2)
: sb1(sb1)
, sb2(sb2)
{
}
private:
// This tee buffer has no buffer. So every character "overflows"
// and can be put directly into the teed buffers.
virtual int overflow(int c)
{
if (c == EOF)
{
return !EOF;
}
else
{
int const r1 = sb1->sputc(c);
int const r2 = sb2->sputc(c);
return r1 == EOF || r2 == EOF ? EOF : c;
}
}

// Sync both teed buffers.
virtual int sync()
{
int const r1 = sb1->pubsync();
int const r2 = sb2->pubsync();
return r1 == 0 && r2 == 0 ? 0 : -1;
}
private:
std::streambuf* sb1;
std::streambuf* sb2;
};

class teestream : public std::ostream
{
public:
// Construct an ostream which tees output to the supplied
// ostreams.
teestream(std::ostream& o1, std::ostream& o2);
private:
teebuf tbuf;
};

teestream::teestream(std::ostream& o1, std::ostream& o2)
: std::ostream(&tbuf)
, tbuf(o1.rdbuf(), o2.rdbuf())
{
}

int main()
{
std::ofstream output("debug.log");
//1、创建文件/屏幕输出流对象tee
teestream tee(std::cout, output);

auto x = 1.1;
tee << __FILE__ << ":" << __LINE__ << "\t" << "Variable x = " << x;

return 0;
}

效果:
【C++grammar】文件I/O流的基本用法_c++_08

3、从文件读数据

ifstrem可从文本文件中读数据,并检测文件是否成功打开。
【C++grammar】文件I/O流的基本用法_数据_09
了解数据格式
若想正确读出数据,必须确切了解数据的存储格式。
用流提取运算符从文件流中读数据,所读入的信息的长度与流提取运算符右侧的变量的类型有关。

1.检测文件是否成功打开

可能出现错误:

1、读文件时文件不存在
2、写文件时介质只读

检测文件是否正确打开的方法:

1、open()之后马上调用fail()函数
2、fail()返回true, 文件未打开

ofstream output("scores.txt");
if (output.fail()) {
cout << R"(Can't open file "scores.txt"!)";
}

2.检测是否已到文件末尾

若你不知道文件有多少行,还想把他们全读出来,用eof()函数检查是否是文件末尾
由于get函数返回值是int,所以需要强制类型转换再进行屏幕输出。

ifstream in("scores.txt");
while (in.eof() == false) {
cout << static_cast<char>(in.get());
}

3.读取文件小练习

本部分要展示的内容如下:
1、创建文件输入流,打开文件score.txt
2、用>>从文件读取数据
3、使用fail()函数检测文件是否打开
4、将读文件语句放入循环中,使用eof()作为循环条件
5、关闭文件

//std::c++latest
#include <fstream>
#include <iostream>
#include <filesystem>
#include <string>
using std::ifstream;
using std::ofstream;
using std::cout;
using std::endl;
using std::string;
namespace fs = std::filesystem;

int main()
{
//第一步,关联文件

fs::path p{ "scores.txt" };

//第二步,创建一个流输入对象
ifstream input{ p };

//第三步使用fail判断流是否正常打开
if (input.fail())
{
cout << "Can't open file " << p << endl;
std::cin.get();
return 0;
}
//第四步,定义一些变量去存这些数据
string name{ "" };
double score{ 0.0 };

//读取文件中的姓名和分数
//input >> name >> score;
//cout << name << " " << score << endl;
//input >> name >> score;
//cout << name << " " << score << endl;

while (input.eof() == false)
{
cout << static_cast<char>(input.get());
}

std::cin.get();
return 0;
}

【C++grammar】文件I/O流的基本用法_流_10

4.bad()函数能否用来判断文件流是否成功打开?

在ifstream和ofstream类中,除了fail()函数之外,还有bad()函数。

那么我们能否用bad()函数取代fail()函数判断流是否成功打开?

不能,bad() 如果出现意外的问题,如文件受损或硬件故障,最后一次读取数据的时候发生了这样的问题,方法bad()将返回true.


举报

相关推荐

0 条评论