目录
首先要有这样一个概念
文件读取:
input:数据流动是 外部存储设备到内存
output:数据流动是 内存到外存
例如:
最常用的cin和cout
cin是关联了输入设备(也就是键盘)
cout是关联了输出设备,向他关联的对象(也就是屏幕)上输送。
>> 是std的命名空间,预先定义好了输入对象
<<插入到输入流中
而定义文件流对象后:
fstream infile,outfile;
infile定义后:infile>>x;关联的外设不再是键盘,而是文件
outfile定义后:outfile<<x;关联的外设不再是屏幕,而也是文件
文件操作步骤
- 定义一个文件流对象
- 打开文件
- 对文件读写操作
- 关闭文件
>>与getline的区别
>>:提取运算符,如果该文件中没有空格,能被读出来,遇到空格、回车、tab(制表)等非法字符会结束。
getline:结束条件只有读完所有或者遇到回车,可以读空格。
文件操作两种方式
字符数组方式
#include<iostream>
using namespace std;
#include<fstream>
int main() {
//创建输入流对象
ifstream input;
char name[80] ,str[80];
cout << "请输入文件名:" << endl;
cin >> name;
//打开文件
input.open(name);
if (!input) {
cout << "文件打开失败" << endl;
exit(1);
}
else {
//读
while (input.getline(str,80))
cout << str << endl;
input.close();
}
return 0;
}
这里值得注意的是:
char text[] :字符串数组末尾若没有 '\0',只能当做数组处理
若有 '\0',可以看做字符串,可以cou<<text,否则不可以。
所以字符数组数组在末尾要加上‘\0’;
补充:
- 用字符串初始化字符数组时,系统会在字符数组的末尾自动加上一个字符"\0",因此数组的大小比字符串中实际字符的个数大1。如:sizeof(str1)=strlen(str1) +1;sizeof会计入‘\0’,strlen不会。
- 在内存中,就是根据"\0"来确认字符串,如果找不到就会沿着字符一直找下去。它占用内存空间,但是不计入串长。
用途:
可以用它作为循环结束的条件:
for(int i =0;str[i]!='\0';i++)
string类方式
#include<iostream>
using namespace std;
#include<string>
#include<fstream>
//string类
int main() {
//创建输入流对象
fstream file;
string name ,str(" 90");
cout << "请输入文件名" << endl;
cin >> name;
file.open(name);
if (!file) {
cout << "输入文件错误" << endl;
}
while (getline(file, str))
{
cout << str << endl;
};
//关闭文件
file.close();
return 0;
}
string 对象没有 ‘\0’
getline()两种类型
成员函数 getline
getline()函数有两种重载形式:
istream& getline (char* s, streamsize n ); istream& getline (char* s, streamsize n, char delim );
作用是:
从istream中读取至多n个字符(包含结束标记符)保存在s对应的数组中。即使还没读够n个字符,如果遇到delim或字数达到限制,则读取终止,delim都不会被保存进s对应的数组中。
函数的变量:
s给一个地址 ,用来存储输入流中的流信息。
n:最大读取长度
char:结束字符,默认是回车。
结束只有两种情况:
- 读完所有
- 遇到回车
库函数getline
在string类型中的四种重载形式:
istream& getline (istream& is, string& str, char delim); istream& getline (istream&& is, string& str, char delim); istream& getline (istream& is, string& str); istream& getline (istream&& is, string& str);
函数的变量:
is :表示一个输入流,例如 cin,读取的istream是作为参数is传进函数的。
str :string类型引用,用来存储输入流中的流信息,读取的字符串保存在string类型的str中。
delim :char类型的变量,所设置的截断字符;在不自定义设置的情况下,遇到’\n’,则终止输入。结束条件:
读入了文件结束标志
读到一个新行(有重载函数可以指定行分隔符,默认是"\n".)
达到字符串的最大长度
如果getline没有读入字符,将返回false,可用于判断文件是否结束。
while()
接下来理解一下
while(cin>>a);
while(getline(cin,str));
while(file,str);//file是一个输入流对象
#include<iostream>
using namespace std;
#include<string>
#include<fstream>
int main() {
int a;
while (cin >> a) {
cout << a << endl;
}
/*
这里很容易误以为while判断语句的判断对象是line(也就是line是否为空)
然后想通过直接回车(即输入一个空的line)跳出循环,却发现怎么也跳不出循环
这是因为回车只会终止getline()函数的读入操作
而getline()函数终止后又进行while()判断
(即判断输入流是否有效,但是现在的输入流依然有效,因为返回的输入流对象是为真满足条件)
所以又运行getline()函数,导致程序永远跳不出循环
直到输入了EOF或者ctrl+z,while循环才会结束
*/
return 0;
}
#include<iostream>
using namespace std;
#include<string>
#include<fstream>
int main() {
ifstream file;
string str;
file.open("datas.txt");
while (getline(file, str))
{
cout << str << endl;
}
/*
类比于上面的cin,这里的getline是将file里的内容一行一行的读到str里
对于file里的文件对象(data.txt)里的本身存在的换行
就好比于上述提到的敲回车不会终止(只是暂停接着走while循环的内部)
这样结束的就只是getline()函数的读入操作,而不是循环。
getline()函数终止后,又进行while()判断,因为按行读,到没读完之前,输入流都是有效的
(循环结束的条件是读完或者遇到回车)
读完所有到最后一行geiline()返回得到的file对象为假,不满足条件,所以就退出循环
file对象为假的理解:就是到末尾了,再往后没东西就表示到了末尾了,得到的file对象变为假。
*/
return 0;
}
总结
判断while()是否结束循环的条件不是输入流是否输入了回车(或getline函数里你自己定义的结束符),而是getline这个函数是否输入无效, while判断语句的真实判断对象是cin的状态,也就是判断当前是否存在有效的输入流。
即读取到文件末尾的时候就不能再读取了,这个时候就会读取失败,这样循环就结束了。就是到了末尾了,再往后没东西就表示到了末尾了
例题
datas.txt文件内容:
##Safda 45sfas df45 DASSA
dsfsgdsgasdg
4564 842s dfssf
dsg
dsfg
#include<iostream>
#include<string>
using namespace std;
#include<fstream>
//采用string类型
int main()
{
ifstream word;
word.open("datas.txt", ios::in);
string qi, ti;
while (getline(word, qi))
{
for (int i = 0; i < qi.size(); i++)
{
if (isalpha(qi[i]) == 0)
{
continue;
}
else
{
cout << qi[i];
}
}
}
word.close();
}