文章目录
- C++017-C++文件读写应用
- C++文件读写应用
- CSP-J目标
- 1. 文件的基本概念、文本文件的基本操作
- 关闭文件
- 文件操作-写入文本文件
- 2.文件读写操作
- 基本案例
- seekg() 和 tellg() 函数来读取文件中的数据
- 2. 文本文件类型与二进制文件类型
- 3. 文件重定向、文件读写等操作
- 在练习:
- 总结
C++017-C++文件读写应用
在线练习:
http://noi.openjudge.cn/
https://www.luogu.com.cn/
C++文件读写应用
参考:
https://space.bilibili.com/627875426
https://blog.csdn.net/kingstar158/article/details/6859379/
CSP-J目标
· 【 2 】文件的基本概念、文本文件的基本操作
· 【 2 】文本文件类型与二进制文件类型
· 【 2 】文件重定向、文件读写等操作
1. 文件的基本概念、文本文件的基本操作
在C++中,文件是一种数据存储方式,它可以是文本文件或二进制文件。文本文件是以文本格式存储数据的文件,每个字符都被存储为其ASCII码值的文本文件,可以用普通的文本编辑器打开和编辑。在C++中,可以使用标准库中的文件流来打开、读取、写入和关闭文件。
打开文件:使用文件流对象(例如 ifstream 或 ofstream)创建一个文件对象并打开文件。打开文件时,可以指定打开模式,例如只读、只写、追加等模式。
读取文件:使用输入流对象(例如 ifstream)从文件中读取数据。可以使用不同的读取函数,例如 getline、get、read等。要读取文件,必须先打开文件。
写入文件:使用输出流对象(例如 ofstream)向文件中写入数据。可以使用不同的写入函数,例如 put、write、<< 运算符等。要写入文件,必须先打开文件。
关闭文件:使用文件流对象的 close() 函数关闭文件。关闭文件后,不能再对其进行读取或写入操作。
#include <fstream>
ofstream //文件写操作 内存写入存储设备 (由ostream引申而来)
ifstream //文件读操作,存储设备读区到内存中 (由ostream引申而来)
fstream //读写操作,对打开的文件可进行读写操作 (由iostream引申而来)
关闭文件
当文件读写操作完成之后,我们必须将文件关闭以使文件重新变为可访问的。成员函数close(),它负责将缓存中的数据排放出来并关闭文件。这个函数一旦被调用,原先的流对象就可以被用来打开其它的文件了,这个文件也就可以重新被其它的进程所访问了。为防止流对象被销毁时还联系着打开的文件,析构函数将会自动调用关闭函数close。
文件操作-写入文本文件
文本文件一般以行的形式组织数据。
在fstream类中,成员函数open()实现打开文件的操作,从而将数据流和文件进行关联,通过ofstream,ifstream,fstream对象进行对文件的读写操作
函数:open()
public member function
void open ( const char * filename,
ios_base::openmode mode = ios_base::in | ios_base::out );
void open(const wchar_t *_Filename,
ios_base::openmode mode= ios_base::in | ios_base::out,
int prot = ios_base::_Openprot);
打开文件的方式在ios类(所以流式I/O的基类)中定义,有如下几种方式:
包含头文件:#include <fstream>
类:ofstream(output file stream)
ofstream打开文件的模式(方式):
对于ofstream,不管用哪种模式打开文件,如果文件不存在,都会创建文件。
ios::out 缺省值:会截断文件内容。
ios::trunc 截断文件内容。(truncate)
ios::app 不截断文件内容,只在文件未尾追加文件。(append)
示例:
#include <iostream>
#include <fstream> // ofstream类需要包含的头文件。
using namespace std;
int main()
{
// 文件名一般用全路径,书写的方法如下:
// 1)"D:\data\txt\test.txt" // 错误。
// 2)R"(D:\data\txt\test.txt)" // 原始字面量,C++11标准。
// 3)"D:\\data\\txt\\test.txt" // 转义字符。
// 4)"D:/tata/txt/test.txt" // 把斜线反着写。
// 5)"/data/txt/test.txt" // Linux系统采用的方法。
string filename = R"(D:\data\txt\test.txt)";
//char filename[] = R"(D:\data\txt\test.txt)";
// 创建文件输出流对象,打开文件,如果文件不存在,则创建它。
// ios::out 缺省值:会截断文件内容。
// ios::trunc 截断文件内容。(truncate)
// ios::app 不截断文件内容,只在文件未尾追加文件。(append)
//ofstream fout(filename);
//ofstream fout(filename, ios::out);
//ofstream fout(filename, ios::trunc);
//ofstream fout(filename, ios::app);
ofstream fout;
fout.open(filename,ios::app);
// 判断打开文件是否成功。
// 失败的原因主要有:1)目录不存在;2)磁盘空间已满;3)没有权限,Linux平台下很常见。
if (fout.is_open() == false)
{
cout << "打开文件" << filename << "失败。\n"; return 0;
}
// 向文件中写入数据。
fout << "你好 淄博1\n";
fout << "你好 淄博2\n";
fout << "你好 淄博3\n";
fout.close(); // 关闭文件,fout对象失效前会自动调用close()。
cout << "操作文件完成。\n";
}
202、文件操作-读取文本文件
包含头文件:#include
类:ifstream
ifstream打开文件的模式(方式):
对于ifstream,如果文件不存在,则打开文件失败。
ios::in 缺省值。
示例:
#include
#include // ifstream类需要包含的头文件。
#include // getline()函数需要包含的头文件。
using namespace std;
int main()
{
// 文件名一般用全路径,书写的方法如下:
// 1)“D:\data\txt\test.txt” // 错误。
// 2)R"(D:\data\txt\test.txt)" // 原始字面量,C++11标准。
// 3)“D:\data\txt\test.txt” // 转义字符。
// 4)“D:/tata/txt/test.txt” // 把斜线反着写。
// 5)“/data/txt/test.txt” // Linux系统采用的方法。
string filename = R"(D:\data\txt\test.txt)“;
//char filename[] = R”(D:\data\txt\test.txt)";
// 创建文件输入流对象,打开文件,如果文件不存在,则打开文件失败。。
// ios::in 缺省值。
//ifstream fin(filename);
//ifstream fin(filename, ios::in);
ifstream fin;
fin.open(filename,ios::in);
// 判断打开文件是否成功。
// 失败的原因主要有:1)目录不存在;2)文件不存在;3)没有权限,Linux平台下很常见。
if (fin.is_open() == false)
{
cout << "打开文件" << filename << "失败。\n"; return 0;
}
第一种方法。
//string buffer; // 用于存放从文件中读取的内容。
文本文件一般以行的方式组织数据。
//while (getline(fin, buffer))
//{
// cout << buffer << endl;
//}
第二种方法。
//char buffer[16]; // 存放从文件中读取的内容。
注意:如果采用ifstream.getline(),一定要保证缓冲区足够大。
//while (fin.getline(buffer, 15))
//{
// cout << buffer << endl;
//}
// 第三种方法。
string buffer;
while (fin >> buffer)
{
cout << buffer << endl;
}
fin.close(); // 关闭文件,fin对象失效前会自动调用close()。
cout << "操作文件完成。\n";
}
203、文件操作-写入二进制文件
二进制文件以数据块的形式组织数据,把内存中的数据直接写入文件。
包含头文件:#include
类:ofstream(output file stream)
ofstream打开文件的模式(方式):
对于ofstream,不管用哪种模式打开文件,如果文件不存在,都会创建文件。
ios::out 缺省值:会截断文件内容。
ios::trunc 截断文件内容。(truncate)
ios::app 不截断文件内容,只在文件未尾追加文件。(append)
ios::binary 以二进制方式打开文件。
操作文本文件和二进制文件的一些细节:
1)在windows平台下,文本文件的换行标志是"\r\n"。
2)在linux平台下,文本文件的换行标志是"\n"。
3)在windows平台下,如果以文本方式打开文件,写入数据的时候,系统会将"\n"转换成"\r\n";读取数据的时候,系统会将"\r\n"转换成"\n"。 如果以二进制方式打开文件,写和读都不会进行转换。
4)在Linux平台下,以文本或二进制方式打开文件,系统不会做任何转换。
5)以文本方式读取文件的时候,遇到换行符停止,读入的内容中没有换行符;以二制方式读取文件的时候,遇到换行符不会停止,读入的内容中会包含换行符(换行符被视为数据)。
6)在实际开发中,从兼容和语义考虑,一般:a)以文本模式打开文本文件,用行的方法操作它;b)以二进制模式打开二进制文件,用数据块的方法操作它;c)以二进制模式打开文本文件和二进制文件,用数据块的方法操作它,这种情况表示不关心数据的内容。(例如复制文件和传输文件)d)不要以文本模式打开二进制文件,也不要用行的方法操作二进制文件,可能会破坏二进制数据文件的格式,也没有必要。(因为二进制文件中的某字节的取值可能是换行符,但它的意义并不是换行,可能是整数n个字节中的某个字节)
示例:
#include
#include // ofstream类需要包含的头文件。
using namespace std;
int main()
{
// 文件名一般用全路径,书写的方法如下:
// 1)“D:\data\bin\test.dat” // 错误。
// 2)R"(D:\data\bin\test.dat)" // 原始字面量,C++11标准。
// 3)“D:\data\bin\test.dat” // 转义字符。
// 4)“D:/tata/bin/test.dat” // 把斜线反着写。
// 5)“/data/bin/test.dat” // Linux系统采用的方法。
string filename = R"(D:\data\bin\test.dat)“;
//char filename[] = R”(D:\data\bin\test.dat)";
// 创建文件输出流对象,打开文件,如果文件不存在,则创建它。
// ios::out 缺省值:会截断文件内容。
// ios::trunc 截断文件内容。(truncate)
// ios::app 不截断文件内容,只在文件未尾追加文件。(append)
// ios::binary 以二进制方式打开文件。
//ofstream fout(filename, ios::binary);
//ofstream fout(filename, ios::out | ios::binary);
//ofstream fout(filename, ios::trunc | ios::binary);
//ofstream fout(filename, ios::app | ios::binary);
ofstream fout;
fout.open(filename, ios::app | ios::binary);
// 判断打开文件是否成功。
// 失败的原因主要有:1)目录不存在;2)磁盘空间已满;3)没有权限,Linux平台下很常见。
if (fout.is_open() == false)
{
cout << "打开文件" << filename << "失败。\n"; return 0;
}
// 向文件中写入数据。
struct st_girl { // 超女结构体。
char name[31]; // 姓名。
int no; // 编号。
char memo[301]; // 备注。
double weight; // 体重。
}girl;
girl = { "西施",3,"中国历史第一美女。" ,45.8 };
fout.write((const char *)& girl, sizeof(st_girl)); // 写入第一块数据。
girl = { "冰冰",8,"也是个大美女哦。",55.2};
fout.write((const char*)&girl, sizeof(st_girl)); // 写入第二块数据。
fout.close(); // 关闭文件,fout对象失效前会自动调用close()。
cout << "操作文件完成。\n";
}
204、文件操作-读取二进制文件
包含头文件:#include
类:ifstream
ifstream打开文件的模式(方式):
对于ifstream,如果文件不存在,则打开文件失败。
ios::in 缺省值。
ios::binary 以二进制方式打开文件。
示例:
#include
#include // ifstream类需要包含的头文件。
using namespace std;
int main()
{
// 文件名一般用全路径,书写的方法如下:
// 1)“D:\data\bin\test.dat” // 错误。
// 2)R"(D:\data\bin\test.dat)" // 原始字面量,C++11标准。
// 3)“D:\data\bin\test.dat” // 转义字符。
// 4)“D:/tata/bin/test.dat” // 把斜线反着写。
// 5)“/data/bin/test.dat” // Linux系统采用的方法。
string filename = R"(D:\data\bin\test.dat)“;
//char filename[] = R”(D:\data\bin\test.dat)";
// 创建文件输入流对象,打开文件,如果文件不存在,则打开文件失败。。
// ios::in 缺省值。
// ios::binary 以二进制方式打开文件。
//ifstream fin(filename , ios::binary);
//ifstream fin(filename , ios::in | ios::binary);
ifstream fin;
fin.open(filename, ios::in | ios::binary);
// 判断打开文件是否成功。
// 失败的原因主要有:1)目录不存在;2)文件不存在;3)没有权限,Linux平台下很常见。
if (fin.is_open() == false)
{
cout << "打开文件" << filename << "失败。\n"; return 0;
}
// 二进制文件以数据块(数据类型)的形式组织数据。
struct st_girl { // 超女结构体。
char name[31]; // 姓名。
int no; // 编号。
char memo[301]; // 备注。
double weight; // 体重。
}girl;
while (fin.read((char*)&girl, sizeof(girl)))
{
cout << "name=" << girl.name << ",no=" << girl.no <<
",memo=" << girl.memo << ",weight=" << girl.weight << endl;
}
fin.close(); // 关闭文件,fin对象失效前会自动调用close()。
cout << "操作文件完成。\n";
}
205、文件操作-随机存取
一、fstream类
fstream类既可以读文本/二进制文件,也可以写文本/二进制文件。
fstream类的缺省模式是ios::in | ios::out,如果文件不存在,则创建文件;但是,不会清空文件原有的内容。
普遍的做法是:
1)如果只想写入数据,用ofstream;如果只想读取数据,用ifstream;如果想写和读数据,用fstream,这种情况不多见。不同的类体现不同的语义。
2)在Linux平台下,文件的写和读有严格的权限控制。(需要的权限越少越好)
二、文件的位置指针
对文件进行读/写操作时,文件的位置指针指向当前文件读/写的位置。
很多资料用“文件读指针的位置”和“文件写指针的位置”,容易误导人。不管用哪个类操作文件,文件的位置指针只有一个。
1)获取文件位置指针
ofstream类的成员函数是tellp();ifstream类的成员函数是tellg();fstream类两个都有,效果相同。
std::streampos tellp();
std::streampos tellg();
2)移动文件位置指针
ofstream类的函数是seekp();ifstream类的函数是seekg();fstream类两个都有,效果相同。
方法一:
std::istream & seekg(std::streampos _Pos);
fin.seekg(128); // 把文件指针移到第128字节。
fin.seekp(128); // 把文件指针移到第128字节。
fin.seekg(ios::beg) // 把文件指针移动文件的开始。
fin.seekp(ios::end) // 把文件指针移动文件的结尾。
方法二:
std::istream & seekg(std::streamoff _Off,std::ios::seekdir _Way);
在ios中定义的枚举类型:
enum seek_dir {beg, cur, end}; // beg-文件的起始位置;cur-文件的当前位置;end-文件的结尾位置。
fin.seekg(30, ios::beg); // 从文件开始的位置往后移30字节。
fin.seekg(-5, ios::cur); // 从当前位置往前移5字节。
fin.seekg( 8, ios::cur); // 从当前位置往后移8字节。
fin.seekg(-10, ios::end); // 从文件结尾的位置往前移10字节。
三、随机存取
随机存取是指直接移动文件的位置指针,在指定位置读取/写入数据。
示例:
#include
#include // fstream类需要包含的头文件。
using namespace std;
int main()
{
string filename = R"(D:\data\txt\test.txt)";
fstream fs;
fs.open(filename, ios::in | ios::out);
if (fs.is_open() == false)
{
cout << "打开文件" << filename << "失败。\n"; return 0;
}
fs.seekg(26); // 把文件位置指针移动到第26字节处。
fs << "我是一只傻傻的小菜鸟。\n";
/*string buffer;
while (fs >> buffer)
{
cout << buffer << endl;
}*/
fs.close(); // 关闭文件,fs对象失效前会自动调用close()。
cout << "操作文件完成。\n";
}
202、文件操作-打开文件的模式(方式)
一、写文件
如果文件不存在,各种模式都会创建文件。
ios::out 1)会截断文件;2)可以用seekp()移动文件指针。
ios:trunc 1)会截断文件;2)可以用seekp()移动文件指针。
ios::app 1)不会截断文件;2)文件指针始终在文件未尾,不能用seekp()移动文件指针。
ios::ate 打开文件时文件指针指向文件末尾,但是,可以在文件中的任何地方写数据。
ios::in 打开文件进行读操作,即读取文件中的数据。
ios::binary 打开文件为二进制文件,否则为文本文件。
注:ate是at end的缩写,trunc是truncate(截断)的缩写,app是append(追加)的缩写。
206、文件操作-缓冲区及流状态
一、文件缓冲区
文件缓冲区(缓存)是系统预留的内存空间,用于存放输入或输出的数据。
根据输出和输入流,分为输出缓冲区和输入缓冲区。
注意,在C++中,每打开一个文件,系统就会为它分配缓冲区。不同的流,缓冲区是独立的。
程序员不用关心输入缓冲区,只关心输出缓冲区就行了。
在缺省模式下,输出缓冲区中的数据满了才把数据写入磁盘,但是,这种模式不一定能满足业务的需求。
输出缓冲区的操作:
1)flush()成员函数
刷新缓冲区,把缓冲区中的内容写入磁盘文件。
2)endl
换行,然后刷新缓冲区。
3)unitbuf
fout << unitbuf;
设置fout输出流,在每次操作之后自动刷新缓冲区。
4)nounitbuf
fout << nounitbuf;
设置fout输出流,让fout回到缺省的缓冲方式。
二、流状态
流状态有三个:eofbit、badbit和failbit,取值:1-设置;或0-清除。
当三个流状成都为0时,表示一切顺利,good()成员函数返回true。
1)eofbit
当输入流操作到达文件未尾时,将设置eofbit。
eof()成员函数检查流是否设置了eofbit。
2)badbit
无法诊断的失败破坏流时,将设置badbit。(例如:对输入流进行写入;磁盘没有剩余空间)。
bad()成员函数检查流是否设置了badbit。
3)failbit
当输入流操作未能读取预期的字符时,将设置failbit(非致命错误,可挽回,一般是软件错误,例如:想读取一个整数,但内容是一个字符串;文件到了未尾)I/O失败也可能设置failbit。
fail()成员函数检查流是否设置了failbit。
4)clear()成员函数清理流状态。
5)setstate()成员函数重置流状态。
示例1:
#include
#include // ofstream类需要包含的头文件。
#include <unistd.h>
using namespace std;
int main()
{
ofstream fout(“/oracle/tmp/bbb.txt”); // 打开文件。
fout << unitbuf;
for (int ii = 0; ii < 1000; ii++) // 循环1000次。
{
fout << “ii=” << ii << “,我是一只傻傻傻傻傻傻傻傻傻傻傻傻傻傻的鸟。\n”;
//fout.flush(); // 刷新缓冲区。
usleep(100000); // 睡眠十分之一秒。
}
fout.close(); // 关闭文件。
}
示例2:
#include
#include // ifstream类需要包含的头文件。
#include // getline()函数需要包含的头文件。
using namespace std;
int main()
{
ifstream fin(R"(D:\data\txt\test.txt)", ios::in);
if (fin.is_open() == false) {
cout << "打开文件" << R"(D:\data\txt\test.txt)" << "失败。\n"; return 0;
}
string buffer;
/*while (fin >> buffer) {
cout << buffer << endl;
}*/
while (true) {
fin >> buffer;
cout << "eof()=" << fin.eof() << ",good() = " << fin.good() << ", bad() = " << fin.bad() << ", fail() = " << fin.fail() << endl;
if (fin.eof() == true) break;
cout << buffer << endl;
}
fin.close(); // 关闭文件,fin对象失效前会自动调用close()。
}
2.文件读写操作
基本案例
#include <iostream>
#include <fstream>
using namespace std;
int main() {
// 打开文件
ofstream outfile("data.txt");
if (!outfile.is_open()) {
cout << "无法打开文件" << endl;
return 1;
}
// 写入数据
outfile << "Hello, world!" << endl;
outfile << "Hello, world222" << endl;
// 关闭文件
outfile.close();
// 重新打开文件
ifstream infile("data.txt");
if (!infile.is_open()) {
cout << "无法打开文件" << endl;
return 1;
}
// 读取数据
string line;
// getline(infile, line);
// cout << line << endl;
while (getline(infile,line))
{
cout<<line<<endl;
}
// 关闭文件
infile.close();
return 0;
}
seekg() 和 tellg() 函数来读取文件中的数据
判断文件是否打开:可以使用文件流对象的 is_open() 函数来判断文件是否成功打开。如果打开成功,该函数将返回 true,否则返回 false。
获取文件位置:可以使用输入流对象的 tellg() 函数获取当前的读取位置,使用输出流对象的 tellp() 函数获取当前的写入位置。这些函数返回的值是一个指针,指向当前位置的字节偏移量。
移动文件位置:可以使用输入流对象的 seekg() 函数和输出流对象的 seekp() 函数移动读取或写入位置。这些函数的第一个参数是一个指针,指定要移动的位置的字节偏移量,第二个参数指定相对于哪个位置进行移动,例如 ios::beg(文件开头)、ios::cur(当前位置)或 ios::end(文件末尾)。
判断文件结束:可以使用输入流对象的 eof() 函数判断是否已经到达文件末尾。如果已经到达文件末尾,该函数将返回 true,否则返回 false。
#include <iostream>
#include <fstream>
using namespace std;
int main() {
// 打开文件
ofstream outfile("data.txt");
if (!outfile.is_open()) {
cout << "无法打开文件" << endl;
return 1;
}
// 写入数据
//outfile << "Hello, world!" << endl;
outfile << "Hello, world!1" << endl;
outfile << "Hello, world!1"<<endl;
// 关闭文件
outfile.close();
// 打开文件
ifstream infile("data.txt");
if (!infile.is_open()) {
cout << "无法打开文件" << endl;
return 1;
}
// 获取文件大小
infile.seekg(0, ios::end);
int length = infile.tellg();
infile.seekg(0, ios::beg);
cout<<"长度为:"<<length<<endl;
// 读取数据
char* buffer = new char[length+1];
cout<<"buffer长度为:"<<sizeof(buffer)<<endl;
infile.read(buffer, length);
buffer[length] = '\0';
// 输出数据
cout << buffer << endl;
// 释放内存并关闭文件
delete[] buffer;
infile.close();
return 0;
}
2. 文本文件类型与二进制文件类型
在C++中,文件是一种数据存储方式,它可以是文本文件或二进制文件。文本文件是以文本格式存储数据的文件,每个字符都被存储为其ASCII码值的文本文件,可以用普通的文本编辑器打开和编辑。在C++中,可以使用标准库中的文件流来打开、读取、写入和关闭文件。
3. 文件重定向、文件读写等操作
在C++中,文件是一种数据存储方式,它可以是文本文件或二进制文件。文本文件是以文本格式存储数据的文件,每个字符都被存储为其ASCII码值的文本文件,可以用普通的文本编辑器打开和编辑。在C++中,可以使用标准库中的文件流来打开、读取、写入和关闭文件。
在练习:
http://noi.openjudge.cn/
总结
本系列为C++学习系列,会介绍C++基础语法,基础算法与数据结构的相关内容。本文为C++指针及其应用案例,包括相关案例练习。