一、概念
1.文件输入/输出流类
C++ 提供以下类来执行文件的字符输出和输入:
ofstream
:输出流写入文件的流类ifstream
:输入流从文件中读取的流类fstream
:流类以读取和写入文件
打开文件
在从文件读取信息或者向文件写入信息之前,必须先打开文件。ofstream 和 fstream 对象都可以用来打开文件进行写操作,如果只需要打开文件进行读操作,则使用 ifstream 对象。
open() 函数是 fstream、ifstream 和 ofstream 对象的一个成员。
void open(const char *filename, ios::openmode mode); //第一参数指定要打开的文件的名称和位置,第二个参数定义文件被打开的模式。
模式标志 | 描述 |
---|---|
ios::app | 追加模式。所有写入都追加到文件末尾。 |
ios::ate | 文件打开后定位到文件末尾。 |
ios::in | 打开文件用于读取。 |
ios::out | 打开文件用于写入。 |
ios::trunc | 如果该文件已经存在,其内容将在打开文件之前被截断,即把文件长度设为 0。 |
例如,如果您想要以写入模式打开文件,并希望截断文件,以防文件已存在,那么您可以使用下面的语法:
ofstream outfile;
outfile.open("file.dat", ios::out | ios::trunc );
类似地,您如果想要打开一个文件用于读写,可以使用下面的语法:
fstream afile;
afile.open("file.dat", ios::out | ios::in );
(参考https://blog.csdn.net/bestsort/article/details/82858916)
2.ofstream 构造输出流对象
- ofstream myFile("filename"); 可以在调用默认构造函数之后使用open成员函数打开文件
- ofstream myFile; //声明一个静态文件输出流对象
myFile.open("filename"); //打开文件,使流对象与文件建立联系
- ofstream myFile("filename", ios_base::out | ios_base::binary);//在构造对象或用open打开文件时可以指定模式//以二进制模式打开文件filename,如文件不存在则创建新文件
ofstream myFile("filename");等同
eg:向文件输出
#include <fstream>
using namespace std;
struct Date {
int mon, day, year;
};
int main() {
Date dt = { 6, 10, 92 };
ofstream file("date.dat", ios_base::binary);
file.write(reinterpret_cast<char *>(&dt),sizeof(dt));
//write函数把内存中的一块内容写到一个文件输出流中
file.close();
return 0;
}
3.ifstream 构造输入流对象
- ifstream myFile("filename"); 可以在调用默认构造函数之后使用open成员函数打开文件
- ifstream myFile; //声明一个静态文件入出流对象
myFile.open("filename"); //打开文件,使流对象与文件建立联系
- ifstream myFile("filename", ios_base::in | ios_base::binary);//在构造对象或用open打开文件时可以指定模式//以二进制模式打开文件filename,如文件不存在则创建新文件
eg:从一个payroll文件读一个二进制记录到一个结构中
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
struct SalaryInfo {
unsigned id;
double salary;
};
int main() {
SalaryInfo employee1 = { 600001, 8000 };
ofstream os("payroll", ios_base::out | ios_base::binary);
os.write(reinterpret_cast<char *>(&employee1), sizeof(employee1));
os.close();
ifstream is("payroll", ios_base::in | ios_base::binary);
if (is) {
SalaryInfo employee2;
is.read(reinterpret_cast<char *>(&employee2), sizeof(employee2));
cout << employee2.id << " " << employee2.salary << endl;
} else {
cout << "ERROR: Cannot open file 'payroll'." << endl;
}
is.close();
return 0;
}
表1:检查流特定状态
成员函数 | 意义 |
good() | 是否发生错误 |
eof() | 是否到达文件末尾 |
二、例题
11-3 使用I/O流以文本方式建立一个文件test1.txt,写入字符“已成功写入文件!”,用其它字处理程序(例如windows的记事本程序Notepad)打开,看看是否正确写入。
//法1
#include<fstream>
#include<iostream>
#include<cstring>
using namespace std;
int main(){
ofstream myfile("test1.txt");
char c[]="已成功写入文件1";
myfile.write(c,strlen(c));
myfile.close();
}
//法2
#include<fstream>
#include<iostream>
using namespace std;
int main(){
ofstream myfile("test1.txt");
myfile<<"已成功写入文件";
myfile.close();
}
11-4 使用I/O流以文本方式打开上一题建立的文件test1.txt,读出其内容显示出来,看看是否正确。
#include<fstream>
#include<iostream>
using namespace std;
int main(){
fstream myfile("test1.txt");//ifstream还是ofstream无所谓
char ch;
while(myfile.get(ch)) //这里尝试while(!myfile.eof())还有good()失败了记住这个get
{
cout << ch ;
}
myfile.close();
}
11-5 使用I/O流以文本方式打开上题建立的文件test1.txt,在次此文件后面添加字符“已成功添加字符!”,然后读出整个文件的内容显示出来,看看是否正确。
#include<fstream>
#include<iostream>
using namespace std;
int main(){
fstream myfile1("test1.txt",ios::app);//加 ios::app不然会覆盖重写不是添加
myfile1<<"已成功添加字符!";
myfile1.close();
fstream myfile2("test1.txt");//myfile2改名 后调用 不然不会显示
char ch;
while(myfile2.get(ch))
{
cout << ch ;
}
myfile2.close();
}
11-6 定义一个dog类,包含体重和年龄两个成员变量及相应的成员函数,声明一个实例dog1,体重为5,年龄为10,使用I/O流把dog1的状态写入磁盘文件,再声明另一个实例dog2,通过读文件把dog1的状态赋给dog2。分别使用文本方式和二进制方式操作文件,看看结果有何不同;再看看磁盘文件的ASCII码有何不同。
解:
以两种方式操作,程序运行结果一样,但磁盘文件的ASCII码不同,使用二进制方式时,磁盘文件的ASCII码为05 00 00 00 0A 00 00 00,使用文本方式时,磁盘文件的ASCII码为05 00 00 00 0D 0A 00 00 00,这是因为此时系统自动把0A转换为了0D 0A
二进制方式(生成txt中内容乱码)
#include<fstream>
#include<iostream>
using namespace std;
class dog
{
public:
dog():age(0),weight(0){
}
dog(int a1,int a2):age(a1),weight(a2){
}
~dog(){
}
int GetWeight()const { return weight; }
int GetAge() { return age; }
private:
int age;
int weight;
};
int main()
{
dog dog1(10,5);
ofstream myfile1("dog1.txt",ios::out|ios::binary);//fstream默认以二进制模式打开文件 txt文档输入内容乱码
if (!myfile1)//fstream会unable ofstream就好了
{
cout << "Unable to open for writing.\n";
return(1);
}
myfile1.write((char*) &dog1,sizeof(dog1));//myfile1.write(reinterpret_cast<char*>(&dog1), sizeof(dog1));
myfile1.close();
dog dog2;
ifstream myfile2("dog1.txt",ios::out|ios::binary);//fstream默认以二进制模式打开文件 txt文档输入内容乱码
if (!myfile2)//fstream会unable ofstream就好了
{
cout << "Unable to open for writing.\n";
return(1);
}
cout<<dog2.GetAge()<<" "<<dog2.GetWeight() <<endl;
myfile2.read((char*) &dog2,sizeof(dog2));//从一个文件读字节到一个指定的内存区域,由长度参数确定要读的字节数
cout<<dog2.GetAge()<<" "<<dog2.GetWeight() <<endl;
myfile2.close();
}
文本方式(生成txt内容正常)
#include <fstream>
#include <iostream>
#include <sstream> // For stringstreams
using namespace std;
class dog {
public:
dog(): age(0), weight(0) {}
dog(int a1, int a2): age(a1), weight(a2) {}
int GetWeight() const { return weight; }
int GetAge() const { return age; }
// Function to write the dog's state to a stream in text format
void WriteToStream(ostream& os) const {
os << age << " " << weight;
}
// Function to read the dog's state from a stream in text format
void ReadFromStream(istream& is) {
is >> age >> weight;
}
private:
int age;
int weight;
};
int main() {
dog dog1(10, 5);
// Write dog1's state to a text file
{
ofstream myfile1("dog_text.txt");
if (!myfile1.is_open()) {
cout << "Unable to open for writing.\n";
return 1;
}
dog1.WriteToStream(myfile1);
myfile1.close();
}
dog dog2;
// Read dog1's state from the text file into dog2
{
ifstream myfile2("dog_text.txt");
if (!myfile2.is_open()) {
cout << "Unable to open for reading.\n";
return 1;
}
dog2.ReadFromStream(myfile2);
myfile2.close();
}
cout << "dog2's age: " << dog2.GetAge() << ", weight: " << dog2.GetWeight() << endl;
return 0;
}
11-7 观察下面的程序,说明每条语句的作用,看看程序执行的结果。
#include <iostream>
using namespace ::std;
int main()
{
ios_base::fmtflags original_flags = cout.flags(); //1 保存现在的格式化参数设置,以便将来恢复这些设置;
cout<< 812<<'|'<<endl;
cout.setf(ios_base::left,ios_base::adjustfield); //2把对齐方式由缺省的右对齐改为左对齐;
cout.width(10); //3把输出域的宽度由缺省值0改为10;
cout<< 813 << 815 << '\n';
cout.unsetf(ios_base::adjustfield); //4清除对齐方式的设置;
cout.precision(2);
cout.setf(ios_base::uppercase|ios_base::scientific); //5更改浮点数的显示设置;
cout << 831.0 <<endl;
cout.flags(original_flags); //6恢复原来的格式化参数设置。
}
setiosflags的参数
- ios_base::skipws 在输入中跳过空白 。
- ios_base::left 左对齐值,用填充字符填充右边。
- ios_base::right 右对齐值,用填充字符填充左边(缺省对齐方式)。
- ios_base::internal 在规定的宽度内,指定前缀符号之后,数值之前,插入指定的填充字符。 ios_base::dec 以十进制形式格式化数值(缺省进制)。
- ios_base::oct 以八进制形式格式化数值 。
- ios_base::hex 以十六进制形式格式化数值。
- ios_base::showbase 插入前缀符号以表明整数的数制。
- ios_base::showpoint 对浮点数值显示小数点和尾部的0 。
- ios_base::uppercase 对于十六进制数值显示大写字母A到F,对于科学格式显示大写字母E 。 ios_base::showpos 对于非负数显示正号(“+”)。
- ios_base::scientific 以科学格式显示浮点数值。
- ios_base::fixed 以定点格式显示浮点数值(没有指数部分) 。 ios_base::unitbuf 在每次插入之后转储并清除缓冲区内容。
11-8 提示用户输入一个十进制整数,分别用十进制、八进制和十六进制形式输出。
#include <iostream>
using namespace std;
int main() {
int n;
cout << "请输入一个十进制整数:";
cin >> n;
cout << "这个数的十进制形式为:" << dec << n << endl;
cout << "这个数的八进制形式为:" << oct << n << endl;
cout << "这个数的十六进制形式为:" << hex << n << endl;
}
//程序运行输出:
//请输入一个十进制整数:15
//这个数的十进制形式为:15
//这个数的八进制形式为:17
//这个数的十六进制形式为:f
11-9 编写程序实现如下功能:打开指定的一个文本文件,在每一行前加行号。
#include<fstream>
#include<iostream>
#include<string>
using namespace std;
int main() {
const char* inputFile = "append.txt"; // 指定要读取的文本文件
const char* outputFile = "output.txt"; // 指定输出文件,带行号的文本
ifstream inFile(inputFile); // 输入文件流
ofstream outFile(outputFile); // 输出文件流
if (!inFile.is_open()) {
cerr << "无法打开输入文件:" << inputFile << endl;
return 1;
}
if (!outFile.is_open()) {
cerr << "无法打开输出文件:" << outputFile << endl;
inFile.close();
return 1;
}
string line;
int lineNumber = 1;
while (getline(inFile, line)) { // 逐行读取
outFile << lineNumber++ << ". " << line << endl; // 输出行号和内容
}
inFile.close();
outFile.close();
cout << "行号已添加并输出到文件:" << outputFile << endl;
return 0;
}