文章目录
文件输入/输出流类
C++ 提供以下类来执行文件的字符输出和输入:
ofstream
:写入文件的流类ifstream
:从文件中读取的流类fstream
:流类以读取和写入文件。
表5: 文件读写模式
读写模式 | 意义 |
---|---|
ios::in | 打开输入操作(ifstream的默认模式)。 |
ios::out | 打开以进行输出操作(ofstream的默认模式)。 |
ios::binary | 以二进制模式打开。 |
ios::ate | 在文件末尾设置初始位置。 如果未设置此标志,则初始位置是文件的开头。 |
ios::app | 所有输出操作都在文件末尾执行,将内容附加到文件的当前内容。 |
ios::trunc | 如果打开文件以进行输出操作并且它已经存在,则删除其先前的内容并用新的内容替换。 |
表6:ios_base 标识的组合意义
ios_base 标识 | 意义 | C模式 |
---|---|---|
in | 读取 (文件必须存在) | “r” |
out | 清空之后改写 (有必要才产生) | “w” |
out | trunc | 清空之后改写 (有必要才产生) | “w” |
out | app | 添加 (有必要才产生) | “a” |
in | out | 读和写: 最初位置在起始点 (文件必须存在) | “r + ” |
in | out | trunc | 先清空, 再读写 (有必要才产生) | “w+” |
ofstream:写入文件的流类
例8:输出文本文件
#include <iostream>
#include <iomanip>
#include <vector>
#include <string>
#include <fstream>
int main()
{
std::vector<std::string> fruit{ "火龙果","梨" };
std::vector<double> price{ 3.02,4.51 };
//使用输出至显示器
std::cout << "水果名 单价\n" << std::setiosflags(std::ios::left);
for (int i = 0; i < 2; ++i)
{
std::cout << std::setw(8) << fruit[i];
std::cout << std::setw(6) << price[i];
std::cout << std::endl;
}
// 使用文件输出流类ofstream的文件对象fout将数据输出到文本文件price.txt
std::ofstream fout; //文件输出流类ofstream对象fout需要程序员自己定义
fout.open("price.txt",std::ios::out);//打开文件price.txt,如文件不存在则创建新文件
fout << "水果名 单价\n" << std::setiosflags(std::ios::left);
for (int i = 0; i < 2; ++i)
{
fout << std::setw(8) << fruit[i];
fout << " ";
fout << std::setw(6) << price[i];
fout << std::endl;
}
fout.close(); //关闭所打开的文件price.txt
return 0;
}
结果:
水果名 单价
火龙果 3.02
梨 4.51
例9:输出二进制文件
#include <iostream>
#include <iomanip>
#include <string.h>
#include <fstream>
int main()
{
char *fruit[] = { "火龙果","梨" };
double price[] = { 3.02,4.51 };
char str[7];
//使用文件对象fout将数据输出到二进制文件price.dat
std::ofstream fout; //文件输出流类ofstream对象fout需要程序员自己定义
fout.open("price.dat",std::ios::out|std::ios::binary);//以二进制模式打开文件price.dat,如文件不存在则创建新文件
for (int i = 0; i < 2; ++i)
{
strcpy(str,fruit[i]);
fout.write(str,sizeof(str));//输出水果名
fout.write((char*)(&price[i]),sizeof(double));//输出价格
}
fout.close(); //关闭所打开的文件price.dat
return 0;
}
ifstream:从文件中读取的流类
例10:输入文本文件
#include <iostream>
#include <fstream>
int main()
{
char fruit[20];
double price;
std::ifstream fin; //使用文件输入流类ifstream的文件对象fin从文本文件price.txt中输入数据
fin.open("price.txt"); //打开文本文件
if(fin.is_open()==false) //检查打开文件是否成功
std::cout<<"打开文件price.txt失败"<<std::endl;
else
{
fin.getline(fruit,19); //读出标题行
std::cout<<fruit<<std::endl; //显示所读出的标题行,显示结果:水果名称单价
for(int i=0;i<2;++i)
{
fin>>fruit>>price; //从文件price.txt中读取水果名称和单价
std::cout<<fruit<<","<<price<<std::endl; //显示水果名称和单价,验证输入结果
}
fin.close(); //关闭所打开的文件price.txt
}
return 0;
}
结果:
水果名 单价
火龙果,3.02
梨,4.51
例11:输入二进制文件
#include <iostream>
#include <iomanip>
#include <fstream>
int main()
{
char name[20];
double num;
std::ifstream fin;
fin.open("price.dat",std::ios::in |std::ios::binary);
for (int i = 0; i < 2; ++i)
{
fin.read(name,7);
fin.read((char*)(&num),8);
std::cout<<name<<" "<<num<<std::endl;
}
fin.close(); //关闭所打开的文件price.dat
return 0;
}
结果:
火龙果 3.02
梨 4.51
表7:检查流的特定状态
成员函数 | 意义 |
---|---|
good | 检查是否没有发生错误, |
eof | 检查是否到达了文件末尾 |
fail | 检查是否发生了可恢复的错误 |
bad | 检查是否已发生不可恢复的错误 |
例12:检查输入文件状态
#include <iostream>
#include <fstream>
int main()
{
char ch;
std::ifstream fin; //使用文件输入流类ifstream的文件对象fin从文本文件price.txt中输入数据
fin.open("price.txt"); //打开文本文件
while(true)
{
fin.get(ch); //从文件price.txt中每次读取一个字符
//eof的返回值:true-文件已结束,false-文件未结束
//good的返回值:true-文件正常,false-文件已损坏
if(fin.eof()==true||fin.good()==false)
break; //结束文件输入
std::cout <<ch; //显示所读出的字符ch
}
fin.close(); //关闭所打开的文件price.txt
return 0;
}
结果:
水果名 单价
火龙果 3.02
梨 4.51
fstream:流类以读取和写入文件
表 8: 文件定位标志
模式标志 | 描述 |
---|---|
ios::beg | 从文件头开始计算偏移量 |
ios::end | 从文件末尾开始计算偏移量 |
ios::cur | 从当前位置开始计算偏移量 |
随机读写文件
打开文件后,文件对象与外存文件建立起关联关系。此时,文件对象内部将保存当前读写数据的位置信息。该位置信息保存在被称作文件指针的数据成员中。文件输入流对象包含一个读文件指针,文件输出流对象包含一个写文件指针,而文件输入/输出流对象则分别包含一个读文件指针和一个写文件指针。
通常情况下,打开文件后文件对象的读/写指针都定位于文件头的位置。每执行一次读/写操作,读/写指针将自动后移,移到下一次读/写数据的位置。这就是文件的顺序读/写。
可以调用函数成员seekg和tellg来移动或读取读文件指针的位置,调用函数成员seekp知和tellp来移动或读取写文件指针的位置。程序员通过移动读/写指针,可实现对文件的随机读写。
这4个与文件指针相关函数的原型如下:
文件指针相关函数 | 描述 |
---|---|
istream& seekg(long bytes,ios::seek dir origin ) | 移动读文件指针 |
long tellg() | 返回当前读文件指针的位置 |
ostream& seekp(long bytes,ios::seek_dir origin ) | 移动写文件指针 |
long tellp() | 返回当前写文件指针的位置 |
例13:随机读写文件
#include <iostream>
#include <fstream>
int main()
{
char fruit[20];
double price;
std::ifstream fin;
fin.open("price.dat"); //打开二进制文件
if(fin.is_open()==false) //检查打开文件是否成功
std::cout<<"打开文件price.dat失败"<<std::endl;
else
{
for(int i=0;i<2;++i)
{
fin.read(fruit,7);
//std::cout << fin.tellg() << '\n';
fin.read((char*)&price,8);
std::cout << fin.tellg() << '\n'; //当前读文件指针的位置
std::cout<<fruit<<","<<price<<std::endl; //显示水果名称和单价,验证输入结果
}
fin.seekg(-30L,std::ios::end);//从文件尾向前(即往回)移动一行(一行有30个字节)
fin.read(fruit,7);
std::cout<<fruit<<std::endl;
fin.seekg(8L,std::ios::cur);//当前位置开始向后移动7个字节
fin.read(fruit,7);
std::cout<<fruit<<std::endl;
fin.close(); //关闭所打开的文件price.dat
}
return 0;
}
结果:
15
火龙果,3.02
30
梨,4.51
火龙果
梨
参考资料:
《大道至简—c++stl(标准模板库)精解》
《c++语言程序设计》(第2版)
http://c.biancheng.net/view/1541.html
https://zh.cppreference.com/w/cpp/io/basic_fstream