C++ 标准输入输出与文件操作
标准输入输出
基本输入输出
头文件 <iostream>,命名空间 std,定义了 cin,cout,cerr,clog
#include <iostream>
using namespace std;
int main(){
char str[] = "Hello";
char data[100]
int a;
cout << "value of str is: " << str << endl;
cin >> a;
cin.getline(data, 100);
cerr << "Error" << endl; // 非缓冲标准错误流
clog << "Log" << endl; // 缓冲标准错误流
}
cin 常用成员方法:
| 成员方法名 | 功能 |
|---|---|
| getline(str,n,ch) | 从输入流中接收 n-1 个字符给 str 变量,当遇到指定 ch 字符时会停止读取,默认情况下 ch 为 '\0'。 |
| get() | 从输入流中读取一个字符,同时该字符会从输入流中消失。 |
| gcount() | 返回上次从输入流提取出的字符个数,该函数常和 get()、getline()、ignore()、peek()、read()、readsome()、putback() 和 unget() 联用。 |
| peek() | 返回输入流中的第一个字符,但并不是提取该字符。 |
| putback(c) | 将字符 c 置入输入流(缓冲区)。 |
| ignore(n,ch) | 从输入流中逐个提取字符,但提取出的字符被忽略,不被使用,直至提取出 n 个字符,或者当前读取的字符为 ch。 |
| operator>> | 重载 >> 运算符,用于读取指定类型的数据,并返回输入流对象本身。 |
cout,cerr,clog常用成员方法:
| 成员方法名 | 功能 |
|---|---|
| put(ch) | 输出单个字符 |
| write(str, n) | 输出指定的字符串。 |
| tellp() | 用于获取当前输出流指针的位置。 |
| seekp(pos) seek(off, way) |
设置输出流指针的位置。 |
| flush() | 刷新输出流缓冲区。 |
| operator<< | 重载 << 运算符,使其用于输出其后指定类型的数据。 |
cin 读取
cin 逐字节读取
int ch; // 注意 ch 是 int 类型的,因为 EOF 为 -1,如果读取到的字符 ASCII 码为 0xFF,如果类型为 char,其值就等于 -1,会被误判为文件结尾
while ((ch = cin.get()) != EOF){
// 处理ch
}
cin 读入一行字符串
getline(buf, n, ch)如果输入流中\n或者ch之前的字符个数达到或者超过n,程序出错,虽然会向buf中读入n-1个字符,但之后的读入操作都会失败,可用cin.clear()清除错误标记,使之恢复正常。
const int MAX_LINE_LEN = 1000;
char szBuf[MAX_LINE_LEN + 10];
while(cin.getline(szBuf, MAX_LINE_LEN+5))
// 处理
cin 读入结束判断
Windows 中,键盘 Ctrl + Z + Enter 表示输入结束
UNIX / Linux / Mac OS 中,Ctrl +D 表示输入结束
cin 读取到文件末尾,就会返回 false(这是因为 istream 类对 operator bool() 进行了重载,cin 没有读到输入结尾时为 true,否则为 false),如果 cin 在读取中发生了错误,同样返回 false。
输入输出错误
c++ 将输入输出错误的所有可能情况归结为四类流状态(定义于 ios_base,但 ios 派生于 ios_base,故 ios_base::badbit 可写作 ios::badbit):
badbit:发生了(或许是物理上的)致命性错误,流将不能继续使用eofbit:输入结束failbit:I/O 操作失败,主要原因是非法数据goodbit:一切止常,没有错误发生,也没有输入结束
可分别用 bad(),eof(),fail(),bad() 成员函数来检测如上的流状态,而clear() 可用于清除流状态,clear(流状态) 可用于设置流状态。
cout 格式化输出
ostream 类中可实现格式化输出的常用成员方法:
| 成员函数 | 说明 |
|---|---|
| flags(fmtfl) | 当前格式状态全部替换为 fmtfl。注意,fmtfl 可以表示一种格式,也可以表示多种格式。 |
| precision(n) | 设置输出浮点数的精度为 n。 |
| width(w) | 指定输出宽度为 w 个字符。 |
| fill(c) | 在指定输出宽度的情况下,输出的宽度不足时用字符 c 填充(默认情况是用空格填充)。 |
| setf(fmtfl, mask) | 在当前格式的基础上,追加 fmtfl 格式,并删除 mask 格式。其中,mask 参数可以省略。 |
| unsetf(mask) | 在当前格式的基础上,删除 mask 格式。 |
fmtfl 和 mask 参数的可选值:
| 标 志 | 作 用 |
|---|---|
ios::boolalpha |
把 true 和 false 输出为字符串 |
ios::left |
输出数据在本域宽范围内向左对齐 |
ios::right |
输出数据在本域宽范围内向右对齐 |
ios::internal |
数值的符号位在域宽内左对齐,数值右对齐,中间由填充字符填充 |
ios::dec |
设置整数的基数为 10 |
ios::oct |
设置整数的基数为 8 |
ios::hex |
设置整数的基数为 16 |
ios::showbase |
强制输出整数的基数(八进制数以 0 开头,十六进制数以 0x 打头) |
ios::showpoint |
强制输出浮点数的小点和尾数 0 |
ios::uppercase |
在以科学记数法格式 E 和以十六进制输出字母时以大写表示 |
ios::showpos |
对正数显示“+”号 |
ios::scientific |
浮点数以科学记数法格式输出 |
ios::fixed |
浮点数以定点格式(小数形式)输出 |
ios::unitbuf |
每次输出之后刷新所有的流 |
<iomanip> 中定义格式控制符:
*dec,hex,oct,fixed,scientific,left,*right,setbase(b),setw(w),setfill(c),setprecision(n),setiosflags(mask),resetiosflags(mask),boolapha,*noboolalpha,showpoint,*noshowpoint,showpos,*noshowpos,uppercase,*nouppercase,internal(*表示默认)
如
cout << hex << 16 << endl; // 输出 10
cout << resetiosflags(ios::basefield)<< scientific << 123 << endl; // 输出 1.230000e+02
输入输出重定向
cin 和 cout 都可以被重定向。
方法一:用 freopen()
-
该函数定义在
<stdio.h>头文件
方法二:用 rdbuf()
-
该函数定义在
<ios>头文件,由于ios是istream和ostream的基类,所以,该函数也被继承,因此,cout与cin可直接调用该函
方法三:控制台重定向
- 命令行执行时
<in.txt将cin输入重定向到in.txt,>out.txt将cout重定向到out.txt
管理输出缓存区
缓冲区刷新原因:
- 程序正常结束
- 缓存区满
- 用
endl、flush、ends显式刷新flush刷新缓冲区,但不输出任何额外的字符ends向缓冲区插入一个空字符,然后刷新缓冲区
-
用
unitbuf清空缓冲区(默认情况下,cerr是设置unitbuf的)- 设置
cout << unitbuf;,每次输出后都立即刷新缓冲区
- 设置
-
被关联的流读写时,关联到的流缓冲区会刷新(默认情况下,
cin和cerr都关联到cout,因此,读cin或写cerr都会导致cout的缓冲区被刷新)
文件操作
文件流
头文件:<fstream>
ofstream:该数据类型表示输出文件流,用于创建文件并向文件写入信息。ifstream:该数据类型表示输入文件流,用于从文件读取信息。fstream:该数据类型通常表示文件流,且同时具有ofstream和ifstream两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。
fstream,ifstream 是从 istream 派生出来的,因此 cin 的成员方法,同样适用于 fstream,ifstream 类的文件流对象,同样地,cout 的成员方法,同样适用于 fstream,ofstream 类的文件流对象。
-
fstream,ifstream,ofstream的常用成员方法open()、is_open()、close()、swap()、good()、eof()
-
fstream,ifstream的常用成员方法operator>>、gcount()、get()、getline(str,n,ch)、ignore(n,ch)、peek()、putback(c)
-
fstream,ofstream的常用成员方法operator<<、put()、write()、tellp()、seekp()、flush()
打开文件
用成员函数 open(fileName, mode),mode 为文件的打开模式标记
| 模式标记 | 适用对象 | 作用 |
|---|---|---|
ios::in |
ifstream fstream | 打开文件用于读取数据。如果文件不存在,则打开出错。 |
ios::out |
ofstream fstream | 打开文件用于写入数据。如果文件不存在,则新建该文件;如果文件原来就存在,则打开时清除原来的内容。 |
ios::app |
ofstream fstream | 打开文件,用于在其尾部添加数据。如果文件不存在,则新建该文件。 |
ios::ate |
ifstream | 打开一个已有的文件,并将文件读指针指向文件末尾(读写指 的概念后面解释)。如果文件不存在,则打开出错。 |
ios:: trunc |
ofstream | 打开文件时会清空内部存储的所有数据,单独使用时与 ios::out 相同。 |
ios::binary |
ifstream ofstream fstream | 以二进制方式打开文件。若不指定此模式,则以文本模式打开。 |
ios::in | ios::out |
fstream | 打开已存在的文件,既可读取其内容,也可向其写入数据。文件刚打开时,原有内容保持不变。如果文件不存在,则打开出错。 |
ios::in | ios::out |
ofstream | 打开已存在的文件,可以向其写入数据。文件刚打开时,原有内容保持不变。如果文件不存在,则打开出错。 |
ios::in | ios::out | ios::trunc |
fstream | 打开文件,既可读取其内容,也可向其写入数据。如果文件本来就存在,则打开时清除原来的内容;如果文件不存在,则新建该文件。 |
判断文件是否打开成功,可以直接看“对象名”这个表达式的值是否为 true。
打开文件也可用 ifstream、ofstream、fstream 的构造函数。
文本方式和二进制方式打开文件并没有本质上的区别,除了换行符:UNIX/Linux 平台上,文本文件换行符为 \n,Windows 平台上,文本文件换行符为 \r\n。故在 Windows 平台上,若以文本方式打开文件,则读入 \r\n 会转换为一个字符 \n,若写入 \n 则会自动写为 \r\n。
文件关闭
close() 方法用于关闭已打开的文件。
即便不调用 close() 方法,当文件流对象生命周期结束时,会调用其析构函数,析构函数会先调用 close() 方法切断与任何文件的关联。
如果程序崩溃,很可能文件流对象的析构函数未能执行,所以一定要手动调用 close() 方法关闭文件,否则文件可能不完整。
文件读写
-
operator>>,operator<< -
逐个读取(写入)字符,用
get()和put()方法。(虽然是逐个字符读取(写入),但其实,操作系统会在文件输出缓冲区中缓冲字符(文件输入缓冲区中一次性读取很多数据)。 -
get一次读取一个字符有两种形式int get()和istream& get(char& c) -
put(c)输出字符 c。 -
getline()用于一次读取一行字符串 -
getline(buf, bufSize):读取bufSize-1个字符到buf,或遇到\n为止(\n不读入),并在buf读入数据的结尾添加\0 -
getline(buf, bufSize, delim):读取bufSize-1个字符到buf,或遇到delim为止,并在buf读入数据的结尾添加\0 -
若要以二进制形式读取文件(如直接将某一 class 的对象以二进制形式存入文件,然后再读取出来),需要用到
read()和write()成员方法 -
write(buffer, count):将 buffer 指向的 count 个字节写入文件,传入 buffer 的地址需要强制类型转换为char * -
read(buffer, count):与write方法类似
注:以二进制方式读写用
read()和write(),在 Linux 平台上用文本方式打开和用二进制方式打开文件都没有问题,但在 Windows 平台上,应该用二进制方式打开文件,否则可能出错。
文件读写指针
seekg(offset, mode) (seekp(offset, mode))成员函数设置读(写)指针位置,mode 为文件读写指针的设置模式:
ios::beg:使文件指针指向文件开始向后offset字节处ios::cur:使文件指针从当前位置移动,offset 正数向尾部移动,负数向起始方向移动ios::end:使文件指针指向文件结尾向前|offset|字节处
tellg()(tellp())获取文件读(写)指针的位置。