17. io、file

17.1 C++输入和输出概述

17.1.1 流和缓冲区

  • C++程序把输入和输出看作字节流
  • streambuf类为缓冲区提供了内存,并提供了用于填充缓冲区、访问缓冲区内容、刷新缓冲区和管理缓冲区内存的类方法
  • ios base类表示流的一般特征,如是否可读取、是二进制流还是文本流等:
  • ios类基于ios base,其中包括了一个指向streambuf对象的指针成员;
  • ostream类是从ios类派生而来的,提供了输出方法:
  • istream类也是从ios类派生而来的,提供了输入方法:
  • iostream类是基于istream和ostream类的,因此继承了输入方法和输出方法。

C+的iostream类库管理了很多细节。例如,在程序中包含iostream文件将自动创建8个流对象(4个用于窄字符流,4个用于宽字符流)。

  • cin对象对应于标准输入流。在默认情况下,这个流被关联到标准输入设备(通常为键盘)。wcin对象与此类似,但处理的是wchar_t类型。
  • cout对象与标准输出流相对应。在默认情况下,这个流被关联到标准输出设备(通常为显示器)。wcout对象与此类似,但处理的是wchar_t类型。
  • cerr对象与标准错误流相对应,可用于显示错误消息。在默认情况下,这个流被关联到标准输出设备(通常为显示器)。这个流没有被缓冲,这意味着信息将被直接发送给屏幕,而不会等到缓冲区填满或新的换行符。wcerr对象与此类似,但处理的是wchar t类型。
  • clog对象也对应着标准错误流。在默认情况下,这个流被关联到标准输出设备(通常为显示器)。这个流被缓冲。wclog对象与此类似,但处理的是wchar t类型。
  • 对象代表流——这意味着什么呢?当iostream文件为程序声明一个cout对象时,该对象将包含存储了与输出有关的信息的数据成员,如显示数据时使用的字段宽度、小数位数、显示整数时采用的计数方法以及描述用来处理输出流的缓冲区的streambuf对象的地址。下面的语句通过指向的streambuf对象将字符串“Bjarna free”中的字符放到cout管理的缓冲区中:img

17.2 使用cout进行输出

  1. 不要忘了,C++用指向字符串存储位置的指针来表示字符串。指针的形式可以是char数组名、显式的char指针或用引号括起的字符串。因此,下面所有的cout语句都显示字符串:
img
  1. 对于其他类型的指针,C++将其对应于Vod*,并打印地址的数值表示。如果要获得字符串的地址,则必须将其强制转换为其他类型,如下面的代码片段所示:
img
  1. 缓冲区
  • 缓冲区为512的整数倍,输出到屏幕时,换行符发送到缓冲区将会刷新缓冲区
  • 输入即将发生时刷新缓冲区
  • cout<<flush 刷新
  1. 用cout格式化
  • 计数系统

    • 来看如何设置显示整数时使用的计数系统。要控制整数以十进制、十六进制还是八进制显示,可以使用dec、hex和oct控制符。例如,下面的函数调用将cout对象的计数系统格式状态设置为十六进制:hex(cout)以十六进制打印整数值,也可以cout << hex;
  • 调整字段宽度

    • widh()方法只影响将显示的下一个项目,然后字段宽度将恢复为默认值。右对齐
  • 填充字符

    • cout用空格填充字段中未被使用的部分,可以用fill()成员函数来改变填充字符
    • cout.fill('*')
  • 设置浮点数的显示精度

    • precision(2)精度设置为2
  • 打印末尾的0和小数点

    • ios_base提供了setf()函数
    • cout.setf(ios_base::showpoint); cout显示末尾小数点
  • 再谈setf

    • img
    • img
    • img
    • 调用setf()的效果可以通过unsetf()消除,后者的原型如下:
    • void unsetf(fmtflags mask);
    • 其中,mask是位模式。mask中所有的位都设置为1,将使得对应的位被复位。也就是说,setf()将位设置为1,unsetf()将位恢复为0。例如:
    • 默认模式:cout.setf(0,ios_base:floatfield);
    • img
  • 标准控制符

    • img
    • img
    • img
  • 头文件iomanip

    • 常用setprecision()设置精度 setfill()填充字符 setw()字段宽度

17.3 使用cin进行输入

  • 可以将hex、oct和dec控制符与cin一起使用,来指定将整数输入解释为十六进制、八进制和十进制格式

    • cin >> hex;
  • cin>>如何检查输入

    • img
  • 流状态

    • cin或cout对象包含一个描述流状态(stream state)的数据成员(从ios base类那里继承的)。
    • 流状态(被定义为iostate类型,而iostate是一种bitmask类型)由3个ios base元素组成:eofbit、badbit或failbit,其中每个元素都是一位,可以是1(设置)或0(清除)。
    • 当cin操作到达文件末尾时,它将设置eofbit:
    • 当cin操作未能读取到预期的字符时,它将设置failbit。I/O失败(如试图读取不可访问的文件或试图写入写保护的磁盘),也可能将failbit设置为1。
    • 在一些无法诊断的失败破坏流时,badbit元素将被设置(实现没有必要就哪些情况下设置failbit,哪些情况下设置badbit达成一致)。当全部3个状态位都设置为0时,说明一切顺利。
    • img
    • 设置状态
      • clear()方法将状态设置为它的参数。clear()将使用默认参数0,清除三个状态位
      • clear(eofbit)状态设置为eofbit,其他两个状态位被清除
      • setstate()方法只影响参数中已设置的位,下面的调用将设置eofbit,而不会影响其他位setstate(eofbit);
  • getline()函数将对其输入中的定界字符#,而get()函数不会

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
const int Limit = 255;
int main()
{
using std::cout;
using std::cin;
using std::endl;
char input[Limit];

cout << "Enter a string for getline() processing:\n";
cin.getline(input, Limit, '#');
cout << "Here is your input:\n";
cout << input << "\nDone with pase 1\n";

char ch;
cin.get(ch);
cout << "The next input character is " << ch << endl;

if (ch != '\n')
{
cin.ignore(Limit, '\n');
}
cout << "Enter a string for get() processing : \n";
cin.get(input, Limit, '#');
cout << "Here is your input:\n";
cout << input << "\nDone with phase 2\n";

cin.get(ch);
cout << "The next input chatacter is " << ch << endl;

return 0;
}
img
img
  • 其他方法
  • read()不会在输入后加上空值字符,因此不能将输入转换为字符串。
  • peek()函数返回输入中的下一个字符,但不愁去输入流中的字符。也就是说,他能查看下一个字符
  • gcount()方法返回最后一个非格式化抽取方法读取的字符数。这意味着字符是由get()、getline()、ignore()或者read()方法读取的,不是由抽取运算符>>读取的,抽取运算符对输入进行格式化,使之与特定的数据类型匹配,速度比strlen()慢
  • putback()函数将一个字符插入到输入字符串中,被插入的字符将是下一条输入语句读取的第一个字符。

17.4 文件输入和输出

1. 文件输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <fstream>
#include <string>

int main()
{
using namespace std;
string filename;

cout << "Enter name for new file: ";
cin >> filename;

ofstream fout(filename.c_str());

fout << "For your eyes only!\n";
cout << "Enter your secret number: ";
float secret;
cin >> secret;
fout << "Your secret number is " << secret << endl;
fout.close();

ifstream fin(filename.c_str());
cout << "Here are the contents of " << filename << ":\n";
char ch;
while (fin.get(ch))
{
cout << ch;
}
cout << "Done\n";
fin.close();
return 0;
}
img

2. 检查文件是否打开成功

1
2
3
4
5
6
7
fin.open(filename);
if(fin.fail())
{}
if(!fin)
{}
if(!fin.is_open())
{}

3. 打开多个文件

1
2
3
4
5
6
ifstream fin;
fin.open("fat.txt");
fin.close();
fin.clear();
fin.open("rat.txt");
fin.close();

4. 命令行处理技术

在UNIX和linux中计算文件包含的字数,命令行输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
wc report1 report2 report3 //程序名 后面三个是作为命令行参数传递给程序的文件名
#include <iostream>
#include <fstream>
#include <cstdlib>

int main(int argc, char* argv[])
{
using namespace std;
if (argc == 1)
{
cerr << "Usage: " << argv[0] << " filename[s]\n";
exit(EXIT_FAILURE);
}

ifstream fin;
long count;
long total = 0;
char ch;
for (int file = 1; file < argc; file++)
{
fin.open(argv[file]);
if (!fin.is_open())
{
cerr << "Could not open " << argv[file] << endl;
fin.clear();
continue;
}
count = 0;
while (fin.get(ch))
{
count++;
}
cout << count << " characters in " << argv[file] << endl;
total += count;
fin.clear();
fin.close();
}
cout << total << "characters in all files\n";
return 0;
}

5. 文件模式

img
img

6. 文件随机存取

seekg()

seekp()

tellg()

tellp()


17. io、file
http://binbo-zappy.github.io/2024/11/27/cpp-primer-plus/17-io、file/
作者
Binbo
发布于
2024年11月27日
许可协议