在C++中,数据流动的方法一共有四种:
- 标准输入输出
stdio.h
- 在输入输出流类文件
iostream.h
中定义流对象 - 插入运算符:<<
- 提取运算符:>>
<<和>>就是我们最常见的cout << endl;或者cin >> str;
,我们把cout比作输出设备,如屏幕,cin比作输入设备,如键盘。这些操作符也就在我们一直用的头文件#include <iostream>
中。
有一点要说的是,我们在输入一句话中带有空格时,是不能使用cin >> str;
的,因为cin在等待读取的过程中,一是遇到回车键返回,二则是遇到空格就返回。所以可以使用另一种方法:cin.get(str,size);
下面只介绍我们常用的文件输入/输出流。
一、文件打开/关闭
1.建立流
流一共有三种:
- 输入流
ifstream
- 输出流
ofstream
- 输入/输出流
fstream
打开一个文件,我们使用open
函数
open函数原型:
void open(char *filename, int mod, int access);
-
filename不用提,大家都懂。
-
mod是文件打开的工作模式。
对于输入流ifstream,默认是ios::in;对于输出流ofstream,默认是ios::out。
mod | explain |
---|---|
ios::app | 输出时,追加到文件尾部 |
ios::ate | 寻找文件尾部 |
ios::in | 文件可输入 |
ios::nocreate | 不创建,就是说文件不存在时返回失败 |
ios::noreplace | 不替换,就是说文件存在时返回失败 |
ios::out | 文件可输出 |
ios::trunc | 使同名文件被删除 |
ios::binary | 二进制形式打开 |
- access是打开文件的类型
整型 | 文件类型 |
---|---|
0 | 普通文件 |
1 | 只读文件 |
2 | 隐藏文件 |
3 | 系统文件 |
4 | 备份文件 |
如:
out.open("test",ios::out,0);
fstream
的两种方式打开,如:
io.open("test",ios::out | ios::in,0);
当然,前文也说到过,对于ifstream,默认是输入流,ofstream是输出流,所以我们只想打开普通文件时,没有必要这么做。因为我们在执行默认操作时,使用构造函数也是同样的。
ifstream in("test");
三种文件的方式可以互相借鉴,但是之间并不绝对。如果在目录下没有指定文件,fstream和istream都会执行失败,因为它们没有主动创建文件的步骤。
而ofstream则有判断出该文件不存在,就建立的特性。
二、文件读写
首先,我们建立一个txt文件,写入以下内容:
I am a PC!
Hello world!
你好!
1.读
先看读的代码
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, const char * argv[]) {
ifstream in("/Users/yucheng/test.txt");
if(!in)
{
cout << "not found" << endl;
return 0;
}
char str[100];
in >> str;
cout << str << endl;
return 0;
}
运行后,猜猜看会显示什么?
·
·
·
·
·
·
答案是
I
我们想象一下,把in看成cin,那么是不是相当于我们在键盘输入的过程呢,在遇到空格或回车停止读取!
所以,我们可以使用
in.get(str,100);
//或者
in.getline(str, 100);
来读取一行
·
·
·
如果要读取全部字符,包括回车符、换行符等。
char s;
in.get(s);
while(!in.eof())
{
cout << s;
in.get(s);
}
2.写
写主要分为两种,
一是格式化写
二是加在尾端写
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, const char * argv[]) {
ofstream out("/Users/yucheng/test.txt");
if(!out)
{
cout << "bcz" << endl;
return 0;
}
char str[100] = "I like this place!\n你好";
out << str;
return 0;
}
执行完毕后可发现它默认是格式化书写的
书写的函数接口还有
- put、get函数,它们是更细节化的char字符类型的获取及写入;
char ch;
while(!f.eof())
{
f.get(ch);
cout << ch;
}
char str[] = "hello world!";
char * p;
for(p = str ; *p!='\0'; p++)
f.put(*p);
注意的是,如果你的put字符数量不如文件中原字符数量,容易造成字符混插。
因为在使用get和put函数时,并没有将文件格式化。所以,C++又为我们提供下面两种方法,更为简洁。
- getline(),get();函数
其原型是basic_istream& getline(char_type* __s, streamsize __n)
根据其本身意思也能猜到这是读取整行的字符。包括get函数
f.getline(str,1000);
cout << str << endl;
所以需要每行每行依次处理字符时,这就很方便。不用判断每行有多少字符。
- read(char &, length),write(char &, length);
char str[100];
f.read(str, 100);
cout << str << endl;
char str[100]="hello world!";
f.write(str, 100);
那么,我们只希望在文档末端加上字符,就需要在构造函数或者open函数里申明
ios::app
就可以了!
ofstream out("/Users/yucheng/test.txt",ios::app);
//或者
out.open("/Users/yucheng/test.txt",ios::app);
并且,可以根据需要读取的字符串或者整形数字的大小来决定读取位数。
如:
int num;
char str[100]="";
f.read((char *)&num,sizeof(int));
f.read(str,100);
cout << num << endl << str << endl;
3、文件指针
文件指针函数有两个:
- seekg(pos); ——输入文件
- seekp(pos); ——输出文件
还有两种进阶函数
- seekg(pos,origin); ——输入文件
- seekp(pos,origin); ——输出文件
pos就是指针的位置偏移量,origin是起始位置
pos可为正、也可为负。正时往右偏移,负时往左偏移。
origin有以下三种
origin | 意思 |
---|---|
ios::beg | 文件开头 |
ios::cur | 文件当前位置 |
ios::end | 文件末端 |
f.seekp(3);
f >> str;
cout << str;
源文件是:1234567890
输出:4567890