C/C++之文件流
最近经常要用到C++来读写文件处理训练数据,尤其对于目标检测领域,我知道的YOLO的数据标注软件-YOLO_MARK就是用C++编写,网上流传的一些关于SSD训练数据标注的工具也由C++编写,此类软件都涉及交互与文件流。平时经常会用到,零零碎碎…,这种感觉真的很难受,话休絮烦,开始吧。
一、C++标准库头文件—#include
图1 类关系
数据类型 |
描述 |
ofstream |
该数据类型表示输出文件流,用于创建文件并向文件写入信息。 |
ifstream |
该数据类型表示输入文件流,用于从文件读取信息。 |
fstream |
该数据类型通常表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。 |
图2 类说明
1、打开文件à读写文件à关闭文件
在从文件读取信息或者向文件写入信息之前,必须先打开文件。ofstream 和 fstream 对象都可以用来打开文件进行写操作,如果只需要打开文件进行读操作,则使用 ifstream 对象。下面是 open() 函数的标准语法,open() 函数是 fstream、ifstream和 ofstream 对象的一个成员。
void open(const char *filename, ios::openmode mode);
ios::in |
打开文件用于读取。 |
ios::out |
打开文件用于写入。 |
ios::ate |
文件打开后定位到文件末尾。 |
ios::app |
追加模式。所有写入都追加到文件末尾。 |
ios::binary |
二进制方式 |
ios::trunc |
如果文件已存在则先删除该文件 |
打开模式可结合使用,打开文件通常和close()配合使用。简单使用的小代码:
#include
#include
int main() {
std::ofstream out;
std::ifstream in;
std::fstream in_out;
out.open("out.txt", std::ios::app | std::ios::out);
in.open("in.txt", std::ios::in | std::ios::binary);
in.open("inout.txt", std::ios::out | std::ios::binary|std::ios::ate);
//写
out<<"hello I am writing"<< std::endl;
//读
//read 1
char data[100];
in>>data;
//read 2
char buffer[256];
if (!in.is_open()){
std::cout<<"Error opening file"; exit(1);
}
while (!in.eof()){
in.getline(buffer,100);
std::cout<< buffer << std::endl;
}
//可读可写 std::fstreamin_out; 上面两种对象的结合体
//关闭文件
in.close();
out.close();
in_out.close();
return 0;
}
2、文件位置指针:
我们可以通过使用以下成员函数来读出或配置这些指向流中读写位置的流指针:
1)tellg() 和 tellp()
这两个成员函数不用传入参数,返回pos_type 类型的值(根据ANSI-C++标准) ,就是一个整数,代表当前get流指针的位置 (用tellg-----ifstream) 或 put 流指针的位置(用tellp-----ostream).
2)seekg() 和seekp()
这对函数分别用来改变流指针get 和put的位置。两个函数都被重载为两种不同的原型:
seekg ( pos_type position );
seekp ( pos_type position );
使用这个原型,流指针被改变为指向从文件开始计算的一个绝对位置。要求传入的参数类型与函数 tellg 和tellp 的返回值类型相同。
seekg ( off_type offset,seekdir direction );-----ifstream
seekp ( off_type offset, seekdir direction );-----ostream
使用这个原型可以指定由参数direction决定的一个具体的指针开始计算的一个位移(offset)。它可以是:
ios::beg |
从流开始位置计算的位移 |
ios::cur |
从流指针当前位置开始计算的位移 |
ios::end |
从流末尾处开始计算的位移 |
Eg1:
int main() {
std::ifstream fileObject;
fileObject.open("test.txt", std::ios::out | std::ios::binary);
int n = 10;
// 定位到 fileObject 的第 n 个字节(假设是 ios::beg)
fileObject.seekg(n);
// 把文件的读指针从 fileObject 当前位置向后移 n 个字节
fileObject.seekg(n,std::ios::cur);
// 把文件的读指针从 fileObject 末尾往回移 n 个字节
fileObject.seekg(n,std::ios::end);
// 定位到 fileObject 的末尾
fileObject.seekg(0,std::ios::end);
return 0;
}
Eg 2:
// obtaining file size 二进制
#include
#include
constchar * filename = "test.txt";
int main() {
long l, m;
std::ifstream in(filename, std::ios::in | std::ios::binary);
l= in.tellg();
in.seekg(0,std::ios::end);
m= in.tellg();
in.close();
std::cout<<"size of "<< filename;
std::cout<<" is "<< (m - l) <<" bytes.\n";
return 0;
}
二、C语言之FILE结构体
(1)文件打开
FILE *fopen(char *file, char *open_mode);
Param1:文件路径 Param2:打开模式
文件打开模式 |
说明 |
r |
打开文件,进行读取。 |
w |
创建文件,以进行写入。如果文件已经存在,则删除当前内容。 |
a |
追加,打开或创建文件以在文件尾部写入。 |
r+ |
打开文件以进行更新(读取和写入)。 |
w+ |
创建文件以进行更新。如果文件已经存在,则删除当前内容。 |
a+ |
追加,打开或者创建文件以进行更新,在文件尾部写入。 |
如果处理的是二进制文件,则需使用下面的访问模式来取代上面的访问模式:"rb","wb", "ab", "rb+", "r+b", "wb+","w+b", "ab+", "a+b"
(2)关闭文件
int fclose(FILE *fp);
(3)一些基本操作的案例
1)顺序读取文件内容(按照行)
//读取单个字符
int fgetc(FILE * fp);
//读取字符串读取字符串,函数 fgets() 从 fp 所指向的输入流中读取 n - 1 //个字符。它会把读取的字符串复制到缓冲区 buf,并在最后追加一个 null //字符来终止字符串。如果这个函数在读取最后一个字符之前就遇到一个换行//符 '\n' 或文件的末尾 EOF,则只会返回读取到的字符,包括换行符
char *fgets(char *buf, intn, FILE *fp);
//int fscanf(FILE *fp, const char*format, ...) 函数来从文件中读取字符串,但是在遇到第一个空格字符时,它会停止读取
int fscanf(FILE *fp, constchar *format, ...);
EG1:
#include
int main()
{
FILE *fp = NULL;
char buff[255];
fp= fopen("test.txt", "r");
fscanf(fp,"%s", buff);
printf("1: %s\n", buff);
fgets(buff,255, (FILE*)fp);
printf("2: %s\n", buff);
fgets(buff,255, (FILE*)fp);
printf("3: %s\n", buff);
fclose(fp);
}
输出:
//首先,fscanf()方法只读取了 This,因为它在后边遇到了一个空格。其次,调用fgets() 读取剩余的部分,直到行尾。最后,调用 fgets() 完整地读取第二行。
EG2:
#include
int main()
{
int account;
char name[30];
double balance;
FILE *cfPtr;
if ((cfPtr = fopen("clients.txt", "r")) == NULL){ //打开
printf("File could not be opened.\n");
}
else{
//行读取
while (!feof(cfPtr)){
//从文件指针读取到内存语句
fscanf(cfPtr,"%d%s%lf", &account, &name, &balance);
printf("%d %s %lf \n", account, name, balance);
}
//关闭文件
fclose(cfPtr);
}
return 0;
}
2)顺序写入文本文件
//int fputc(int c, FILE *fp); //写入整型数值C
//int fputs(const char *s, FILE *fp); //写入字符串s到文件
//int fprintf(FILE *fp,const char *format, ...) //把一个字符串写入到文件中
#include
int main() {
//打开
FILE *fp = NULL;
fp= fopen("test.txt", "w+");
//写入
fprintf(fp,"This is testing for fprintf...\n");
fputs("This is testing for fputs...\n", fp);
//关闭文件
fclose(fp);
}