参考:《Big C++ 》
输入/输出库是基于流的概念。
输入流是数据的源头
输出流是数据的汇集/数据的目标
最常见的数据源头和数据目标是————硬盘上的文件·
三种类型的文件流
- ifstream(input file stream)
- ofstream
- fstream
要包含**< fstream >**head文件
对于文件流的操作
5. 从文件流中读取内容
1.1. open
string filename;
cin>> filename;
ifstream in_file; //declare a ifsream named in_file
in_file.open(filename.c_str());//将c++ 的string变量转换为C语言的字符串(char[])
可以从close这一(流里面的)成员函数(method)关闭流
in_file.close();
1.2. 读入
string name;
double value;
in_file >>name>>value;
if(!in_file.fail()){ //读入成功
//handle the input
}
小提示:在调用open之后,最好立即测试是否fail掉,不要在读取之后的时候才测试
- 写入文件
需要ofstream或者fstream 变量
如
ofstream out_file;
out_file.open(“output.txt”);
outfile << name << " " << value << endl;
从文件中读取数据和读取见键盘输入一样容易。
//以下是例程
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
/**
读取名字信息,如果tota>=0, 则打印该名字,并根据实际情况修改total
@ param in_file 输入流
@ param total 还需处理的部分占总数的百分比(理解,还能被处理的名字的数量占总数的百分比)
*/
//传入实参
void process_name(ifstream &in_file, double &total){
string name;
int count;
double percent;
in_file >> name>> count>>percent;
//if 读取失败
if(in_file.fail())
return;
// 还能继续处理,收集的名字应的人数占总数的比尚未超过total(%)
if(total > 0)
cout << name << " ";
total = total -percent;
}
int main(){
ifstream in_file;
in_file.open("babynames.txt");
if(in_file.fail()){
cout<<"Failure Reading!"<<endl;
return 0;
}
double boy_total = 50;
double girl_total = 50;
while(boy_total>0 || girl_total > 0){
int level;
in_file>>level;
if(in_file.fail())
return 0;
cout<< level<< " ";
process_name(in_file, boy_total);
process_name(in_file,girl_total);
cout<<endl;
}
return 0;
}
刚才所看到的“逐个读取“的流的形式
这种形式最simple,但可以想见还可以直接读取文本的输入
这样更符合人的阅读方式,不是逐词逐词读
而是一大段一大段地读
- 读入单词
读入单词就是
string word;
in_file >> word;
这两句代码的底层mechanism就是,先从输入流,也就是被打开的文件中删除任何空白字符
也就是跳过所有空白字符
所谓“空白字符”,就是
-
空格
-
制表符
-
换行符
从而第一个不是空白的character 将成为字符串word的第一个字符
然后继续添加字符,知道再次出现空白字符而停止,或者达到EOF
但单词后面的空白字符尚不会被跳过(不从流中删除)————用心感受原理,理解 -
读取字符
call get!
char ch;
in_file.get(ch);
返回一个“not failed” 状态
while(in_file.get(ch)){
//handle ch;
}
get 函数会读取空白字符,若对空白字符不感兴趣,就用>>这个operator
in_file >> ch;//读取一个(下一个)non-blank character
- 读取一行
“getline函数读取一整行输入,包括行末的换行符。它将(除了换行符以外的)所有字符放入字符串line中”
string line;
getline(in_file, line);
写入文本并输出
<<
- 往流中写入单个字符 put方法
out_file.put(ch);
控制输出格式 ———— 流operator
设置字长为10, 在写入下一个数据项时,会产生足够的空格填充该项,使得该输出能够达到10个字符的长度
当然,如果该项的长度超过10个字符,则setw(10)自动失效
out_file << setw(10)
//前导0填充
out_file <<setfill(‘0’) << setw(2)<<hours
<<’:’ << setw(2) << minutes<< setfill(’ ');
左对齐右对齐
out_file << left << setw(10) << word << right << setw(10) << number;
4. 解析和格式化字符串
istringstream类 从字符串中读取字符
ostringstream 将字符写入字符串中
字符串流(stringstream)和其他类具有相同的公共接口
包含sstream头文件
istringstream strm;
//str 函数,将流设置成为“要读取的字符串”
strm.str(“January 24, 1973”);
string month;
int day;
string comma;
int year;
strm >> month >> day >> comma >> year;
以下的凯撒密码程序需要用命令行模式才能运行
// caesar凯撒密码
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;
/**
使用凯撒密码对流数据进行
加密
@参数 in 读取的流
@参数 out 写入的流
@参数 k 加密密钥
*/
void encrypt_file(ifstream &in, ofstream &out, int k){
char ch;
while(in.get(ch)){
//encryption
out.put(ch+k);
}
}
int main(int argc, char *argv[]){
int key = 3;
int file_count = 0;
ifstream in_file;
ofstream out_file;
for(int i = 1;i<argc;i++){
string arg = argv[i];
if(arg == "-d")
key = -3;
else{
file_count ++ ;
if(file_count == 1){
in_file.open(arg);
if(in_file.fail()){
cout<< "Error opening input file" << arg <<endl;
return 1;
}
}
else if(file_count == 2){
out_file.open(arg);
if(out_file.fail()){
cout<< "Error opening output file" << arg <<endl;
return 1;
}
}
}
}
if (file_count !=2){
cout<< "Usage: " <<argv[0] << " [-d] infile outfile"<<endl;
return 1;
}
encrypt_file(in_file,out_file, key);
return 0;
}