概要
本文将从文件IO的几个方面来总结操作文件的方式:
打开文件
方式 | 头文件 | 调用 | 参数说明 | 返回值 | 功能 | 注意点 |
---|---|---|---|---|---|---|
system call |
sys/types.h sys/stat.h fcntl.h
|
int open(const char* name, int flags, mode_t mode); |
name :文件名flags :访问文件方式mode :文件许可 |
int : file descriptor(fd),若打开成功则返回文件句柄,失败则返回-1并设置errno 为相应值 |
打开文件并赋以相应模式和许可操作 | figure和errno |
system call | creat | |||||
c | stdio.h |
FILE* fopen(const char* path, const char* mode); |
path :文件路径mode :打开模式 |
FILE* :file pointer,若打开成功则返回FILE*,失败则返回NULL 并设置errno
|
以mode 指定方式打开文件 |
FILE* 和fd 区别 |
c++ | fstream |
std::ofstream(const char* filename, ios_base::openmode mode = ios_base::out) or ifstream (const char* filename, ios_base::openmode mode = ios_base::in);
|
filename :文件名openmode :打开方式 |
非函数调用,而是通过构造函数生成一个fstream 对象 |
生成一个指定openmode 的文件对象 |
好的风格要指定openmode ,虽然有默认值 |
读文件
方式 | 头文件 | 调用 | 参数说明 | 返回值 | 功能 | 注意点 |
---|---|---|---|---|---|---|
system call | <unistd.h> |
ssize_t read(int fd, void* buf, size_t len); |
fd :文件句柄buf :将数据读入指针值指向的位置len :读入len Bytes |
1.若成功读入len Bytes返回值等于len 2.返回值大于0但小于 len ,产生信号中断,或读到EOF(即没有剩余数据可读)3.返回0,即该次read已经读到EOF处 4.返回-1,若 errno 为EINTR orEAGAIN 可reissue,否则发生错误。 |
从文件当前position开始向buf 读入len Bytes |
注意return value 和errno 的处理. |
C | <stdio.h> |
int fgetc(FILE* stream); |
stream :file pointer |
将读入的一个unsigned char 以int 返回 |
读入当前位置的后一个Byte | 返回值要用int 去接而不是char
|
C | 同上行 | char* fgets(char* str, int size, FILE* stream); |
str :数据读入的字符串size :读入Bytesstream :file pointer |
若成功读size-1 Bytes或者读到newline返回str指针,但返回NULL 如果遇到EOF或发生错误 |
可读取整行数据,如果size 足够大,超过行字节数。 |
实际上读size-1 Bytes,最后一字节为'\0' ,如果读到新的一行,\n 也会被存入str ,同时注意若读到EOF是返回NULL
|
C | 同上行 | size_t fread(void* buf, size_t size, size_t nr, FILE* stream); |
两个关键:nr :最多读nr "块"size :每"块"读size Bytes |
返回值为一个小于等于nr 的值 |
可用于读取struct 结构 |
1.注意返回值,若小于nr 则需要用ferror() 和feof() 判断是属于哪种情况2.尽量符合内存对齐原则 |
C++ | <fstream> |
常用:>> 、getline 等(见附录) |
写文件
方式 | 调用 | 参数说明 | 返回值 | 功能 | 注意点 |
---|---|---|---|---|---|
system call | ssize_t write(int fd, const void* buf, size_t count); |
buf :写入的数据,注意const 保护fd :文件句柄count :写入的字节数 |
若成功,返回成功写入字节数并且更新文件当前position,失败则返回-1 ,也可返回0 代表未写入任何数据 |
将buf 中的count Bytes数据写入文件 |
注意对buf 的const 保护,以及count 存在上限SSIZE_MAX
|
C | int fputc(int c, FILE* stream); |
c :要存入的一个Byte(cast to unsigned char)stream :file pointer |
若成功则返回c ,失败则返回EOF
|
向文件写入一个字节的数据 | 虽然参数是int ,但实际转化为unsigned char 存入 |
C | int fputs(const char* str, FILE* stream); |
str :要写入的字符串 |
成功返回一个非负整数,失败则返回EOF
|
向文件写入字符串 | 返回值为整数 |
C | size_t fwrite(void* buf, size_t size, size_t nr, FILE* stream); |
nr :最多写nr "块"size :每"块"写入size Bytes |
返回成功写入的块数,若失败则返回一个小于nr 的值 |
向文件写入每块为size 的nr 块数据 |
注意返回值check |
C++ | 常用<< 操作符 |
关闭文件
方式 | 调用 | 参数说明 | 返回值 | 功能 | 注意点 |
---|---|---|---|---|---|
system call | int close(int fd); |
成功则返回0 ,失败返回-1
|
关闭以fd 为句柄的文件 |
每次系统调用都要check error value | |
C | int fclose(FILE* fp); |
成功关闭则返回0 ,否则返回-1 |
关闭文件 | 同上 | |
C++ | 成员函数close()
|
各种用法demo
第一部分:system call
若文件存在则清空,不存在则以0644许可创建(owner可读可写,其他只可读)
int fd;
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if(-1 == fd){
//error
}
读指定Bytes
unsigned long word;
ssize_t nr;
nr = read(fd, &word, sizeof(unsigned long));
if(-1 == nr){
//error
}
读所有bytes
//fstat()获取文件长度(C library)
struct stat st;
if(fstat(fd, &st)){
//error
}
size_t len = st.st_size;
//read all bytes
ssize_t ret;
while(len != 0 && (ret = read(fd, buf, len)) != 0){
if(-1 == ret){
if(EINTR == errno) continue;
perror("read");
break;
}
len -= ret;
buf += ret;
}
写一些bytes
unsigned long word = 1720;
size_t count = 0;
ssize_t nr = 0;
count = sizeof(word);
nr = write(fd, &word, count);
if(-1 == nr){
//error,and check errno
}
else if(nr != count){
//only write part bytes
}
ssize_t ret = 0, nr = 0;
while(0 != len && (ret = write(fd, buf, len)) != 0){
if(-1 == ret){
if(EINTR == errno) continue;
perror("write");
break;
}
len -= ret;
buf += ret;
}
第二部分:C语言
通过FILE*打开文件
FILE* stream = nullptr;
stream = fopen(path, "r");
if(!stream){
//error
}
通过File Descriptor打开文件
FILE* stream = nullptr;
stream = fdopen(fd, "r");
if(!stream){
//error
}
读写一个字节
//read
int c = 0;
c = fgetc(stream);
if(EOF == c){
//error
}
//write
if(fputc(c, stream) == EOF){
//error
}
读写一个字符串
//read
char buf[BUFFER_SIZE];
if(!fgets(buf, BUFFER_SIZE, stream)){
//error
}
//write
if(fputs(buf, stream) == EOF){
//error
}
读写binary data
//read
char buf[64];
size_t nr;
nr = fread(buf, sizeof(buf), 1, stream);
if(0 == nr){
//error
}
//write
struct pirate{
char name[100];
unsigned long booty;
unsigned int beard_len;
}blackbeard = {"JACK", 950, 48};
if(!fwrite(&blackbeard, sizeof(struct pirate), 1, stream)){
//error
}
第三部分:C++
打开文件
//打开可读文件
ifstream in(path, ios::in);
if(!in){
//error
}
//打开可写文件
ofstream out(path, ios::out);
if(!out){
//error
}
读写文件
//读
//用相应数据类型以及>>组合使用
//学号 姓名 课程 成绩
int id, score;
string name, course;
while(in >> id >> name >> course >> score){
//do
}
//写
//将vector<int>写入文件
vector<int> data{1,2,3,4};
for(int i = 0; i < data.size(); i++){
out << data[i] << endl;
}
附录
参考资料:
c++方式可以参考<<c++ primer(第五版)>>
c/system call可以参考<<Linux System Programming,第二版>>
理解文件打开关系
参考link/文献/引用
fstat() : https://www.go4expert.com/articles/understanding-linux-fstat-example-t27449/
ifstream:http://www.cplusplus.com/reference/fstream/ifstream/
ofstream:http://www.cplusplus.com/reference/fstream/ofstream/