c++文件操作
文件输入输出
头文件是fstream,里面三个可使用类型:
ifstream 从一个文件读取数据,i指inpuit
ofstream 从一个文件写输入,o指output
ftream 给一个文件既读又写
看一个小图
这就是依赖关系,所以ftream实现了读和写的功能
打开文件
再说打开文件之前先说一下,文件模式,也就是以什么方式打开文件
文件模式
in 以读的方式打开,文件指针在首,文件不存在打开失败
out 以写的方式打开,当文件不存在,新建一个空文件;当文件存在,清除原有内容
app 每次写操作前均定位到文件末尾,一般配合写文件使用,std::ios::out|std::ios::app,没有文件新建文件,这样文件存在的时候不会清空文件,文件指针到达末尾
ate 打开文件后立即定位到文件末尾,一般配合读文件使用,ios::ate|ios::in,没有文件打开失败,有文件文件指针定位到末尾
trunc 截断文件,删除文件内容打开
binary 以二进制的方式进行IO
模式之间是可以 | 或的,因为本身他们就是数值
ifstream 默认是 std::ios::in,不能使用std::ios::out
ofstream 默认是 std::ios::out | std::ios::trunc
fstream 默认是 std::ios::in | std::ios::out,不能使用std::ios::in
打开文件代码
打开文件的方式很多这里列举常用的:
ifstream a("E:\\aa1.txt", std::ios::in); //第二个参数如果不写,默认是std::ios::in
if(!a.is_open()) {
std::cout << "a.is_open()" << std::endl;
}
//使用is_open()判断函数是否打开
常见模式组合
说一下常见的模式组合:
对于fstream的std::ios::in | std::ios::out 打开文件,文件指针在首,不会清空文件,文件不存在打开失败
对于std::ios::out | std::ios::trunc 文件不存在新建一个空白文件,文件存在清空文件
对于std::ios::out | std::ios::app 文件不存在新建一个文件,文件存在不清空文件,让文件指针到尾部
打开失败处理办法
如果打开失败:
IO文件操作的错误状态
我们在操作文件的时候,可能发生各种各样的状态,流崩溃、Io操作失败、输出流达到了文件的末尾等,c++提供了函数和标志位,这里列出常用的
s.good() //如果流处于有效状态,返回true,可以用这个函数判断所有的可能错误
s.eof() //如果流处于文件的末尾,返回true,常常用在遍历文件的时候使用
s.fail() //如果IO操作失败或者流崩溃,这个函数返回true
std::ios_base::goodbit //文件流是好的可以操作的,值为0
std::ifstream::failbit //流崩溃
std::ifstream::eofbit //输出流达到了文件的末
std::ifstream:badbit //Io操作失败
可以使用rdstate函数,会返回当前流的状态位
if(a.rdstate() & std::ifstream::failbit) {
std::cout << "failbit" << std::endl;
}
//这样就可以判断当前是因为什么问题导致打开失败
读文件
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
ifstream a("E:\\aa.txt", std::ios_base::in);
if(!a.is_open()) {
a.clear(); //文件未打开成功,进行标志位清除
std::cout << "a.is_open()" << std::endl;
return -1;
}
/*****************************************/
//第一种方法,使用重载的>>操作符读取,优点方便快捷,缺点属于单个类型的读取,不能自己控制
//读取一行终止
char value[128] = {0};
if(!a.good()) {
std::cout << "a is not good" << std::endl;
}
a >> value; //可传入字符指针,会一直读取,还可使用int float等基本类型读取
printf("%s\n", value); //一个一个读取
/*****************************************/
//第二种方法,使用get()函数,读取一个字节,每调用这个函数字符指针下移
a.seekg(0, std::ios_base::beg); //文件指针定位到首位置
while(!a.eof() && a.good()) {
printf("%c\n", a.get()); //一个一个读取
}
/*****************************************/
//第三种方法使用getline实现一行一行的读取
char value_line[128] = {0};
a.clear(); //清清除eof标志位,稍后讲解
a.seekg(0, std::ios_base::beg); //文件指针定位到首位置
while(!a.eof() && a.good()) {
a.getline(value_line, 128, '\n');
//第二个参数的字符个数必须大于文件的一行的个数,第三个参数是终止符,就是读到终止符停止,如果不写,默认就是'\n'
//调用函数后,文件指针会自动到 \n的下一个
printf("%s\n", value_line); //一个一个读取
memset(value_line, 128, 0); //将数组重新赋值为0
}
a.close();
}
写文件
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
int main()
{
ofstream a("E:\\aa.txt", std::ios_base::out | std::ios_base::trunc);
if(!a.is_open()) {
a.clear(); //文件未打开成功,进行标志位清除
std::cout << "a.is_open()" << std::endl;
return -1;
}
//使用a.good()判断,流的状态是否正常
//第一种方法,使用重载的<<
if(!a.good()) {
std::cout << "a is not good()()" << std::endl;
}
a<<"sasaSA"; //优点可以写任意格式,库函数重载了很多版本
if(!a.good()) {
std::cout << "a is not good()()" << std::endl;
}
a<<1;
if(!a.good()) {
std::cout << "a is not good()()" << std::endl;
}
a<<1.3;
/***************************************/
//第二种方法,使用put函数,一个字节一个字节插入
//注意的是put插入的是char类型,如果你使用int类型插入会被转为int的ASCII插入
int i = 6;
char value[6] = "12345";
while((i--) && (a.good())) {
a.put(value[i]);
a.put('\n');
}
/***************************************/
//第三种方法,使用write函数,第一个参数是传入的字符串首地址,第二个参数是传入的大小
if(!a.good()) {
std::cout << "a is not good()()" << std::endl;
}
a.write(value, 6);
a.close();
}
关闭文件
当我们对一个文件操作完毕,需要调用a.close()关闭当前文件流,把文件恢复为可访问的状态,并且某些情况还会刷新缓冲区,让缓冲区文件写入文件中,关于缓冲区
缓冲区文章.文件成功打开一定要close()!!!!
更改文件指针
文件指针:下一次文件操作开始的位置,比如我们打开文件std::ios::in 文件指针指向文件的开始位置,使用get每当我们读取的时候文件指针都会下移
使用seekg(pos),一个参数的就是文件指针要达到的绝对位置,文件最开始就是0,依次往后
使用seekg(off_type off, std::ios_base::seekdir dir),第一个参数是文件指针要达到的相对位置,第二个参数实现基准,定义了三个值可以使用
std::ios_base::beg //文件流的开始
std::ios_base::end //文件流的结尾
std::ios_base::cur //文件流当前的位置
注意偏移的位置都是根据基准位置往后移动
显示当前文件指针的位置
a.tellg() //a代表定义的字符串流
关于clear()和setstate()的问题
clear() //清楚当前文件流的标志位,在当前文件流产生错误标志位使用
setstate() //函数参数设置为某个状态
对于clear(std::ios_base::end) //把原先的标志位清除,然后赋值新的标志位
默认clear() //是清楚所有标志位,变为std::ios_base::goodbit
setstate(std::ios_base::end) //不清楚当前标志位,将std::ios_base::end对应的位置位
网上有打开文件失败关于close和clear的先后顺序问题,我这边测试未发现问题,如果大家有问题,欢迎探讨
一个圆,圆内是你会的,圆外是你不知道的。而当圆越大,你知道的越多,不知道的也越多了