GNU/Linux应用程序开发学习笔记(一) 文件操作
GNU/Linux的文件操作
GNU/Linux的文件操作是通过标准C库实现的,可以用同一个API创建ASCII或二进制文件,其中文件操作函数有很多个,分别对应不同方面的功能,可谓是面面具到,下面就逐一学习。
1.Header file
在C中 ,
#include <stdio.h>
在C++中,
#include <cstdio>
2.Open File
一般用fopen()函数来打开文件,fclose()函数关闭文件。
FILE* fopen(const char* filename, const char* mode);
其中mode是文件访问模式:
* r 打开一个已经存在的文件进行度操作
* w 打开一个文件进行写操作
* a 对文件进行追加操作
* rw 对文件进行读写操作
上面后三个模式中,如果文件不存在,则会创建一个新文件filename,而第一个返回 (FILE*)NULL.
文件字符接口
对文件进行逐个字符操作时,可使用如下两个函数:
int fputc(int c, FILE* stream);
int fgetc(FILE* stream);
其中fputc()中是int类型,别忘了类型转换,示例:
int func()
{
char str[] = "Hey, it's just a test!";
FILE* fin = fopen(filename,"a");
FILE* fout = fopen(filename,"r");
if(fout == (FILE*)NULL || fin == (FILE*)NULL)
exit(-1);
int i = 0;
// write string STR to the file every bytes
while(str[i] != NULL)
{
fputc((int)str[i],fin);
++i;
}
// get bytes from file through fgetc() until the end of the file
while( (ch=fgetc(fout)) != EOF )
{
printf("%c",ch);
}
fclose(fin);
fclose(fout);
return 0;
}
字符串接口
对文件进行逐字符串的操作函数和字符操作函数类似,用法也类似
fputs() , fgets();
ASCII字符文件操作
这类文件操作也是比较常见的操作,应用很广,主要以下几种:
int fprintf(FILE* stream, const char* format, ...);
int fscanf(FILE* stream, const char* format, ...);
int sprintf(char* str, const char* format, ...);
int sscanf(char* str, const char* format, ...);
二进制文件的读写
这类文件操作比较重要,特点是处理快,适用范围广,先看fread和fwrite
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream);
size_t fwrite(const void* ptr, size_t size, size_t nmemb,FILE* stream);
其中ptr指的是所需要处理的对象组,比如字符串或者结构题数组,size代表每个对象的字节数,nmemb代表对象的数目,这里要注意:当对象组是字符串时,nmemb=str_len+1,原因是字符串最后的'\0'不能省略。
void rewind(FILE* stream);
重置文件流指针到文件首。
int fseek(FILE* stream, long offset, int whence);
这个函数是设置文件流指针,offset是偏移值,whence有几个标志:
* SEEK_SET 将指针移到距离文件首offset个字节的位置
* SEEK_CUR 将指针移到距离当前指针位置后offset个字节的位置
* SEEK_END 将指针移到距离文件尾offset个字节的位置
注意:offset为正数时表示指针向后移动,为负数时向前移动,这个地方写了程序各种测试才发现,以前以为SEEK_END是将指针向前移动offset字节....无语......
long ftell(FILE* stream);
此函数返回文件流的指针位置,是long型,通过这个可以方便的查看文件指针的位置。
还有两个和上面功能一样的函数是fgetpos,fsetpos,但是使用目的也不一样,ftell和fseek函数没有对其机制的细节进行抽象,所以推荐使用fgetpos,fsetpos,原型如下:
int fgetpos(FILE* stream, fpos_t* pos);
int fsetpos(FILE* stream, fpos_t* pos);
这两个函数通过对指针位置的抽象操作和细节描述达到比ftell,fseek更加直观的目的,他们返回的不是指针的绝对位置,而是抽象位置,所以就可以用fpos_t类型来对文件位置进行描述。
上面这些是对二进制文件操作的函数,下面是示例:
#include <iostream>
#include <cstdio>
using namespace std;
#define MAXN_STR 40
#define MAXN_OBJECT 3
char file_name[] = "input";
char str[] = "This is a test.";
FILE* fout;
FILE* fin;
typedef struct{
int id;
float x;
float y;
char str[MAXN_STR+1];
}TYPE_NODE;
TYPE_NODE object[MAXN_OBJECT]={
{1,10.2,12.2,"The earth"},
{2,20.9,20.8,"The arm"},
{3,12.3,12.4,"The null"}
};
TYPE_NODE tmp_object;
int main()
{
fin = fopen(file_name,"w");
if(fin == (FILE*)NULL)
{
exit(-1);
}
fwrite((void*)object,sizeof(TYPE_NODE),MAXN_OBJECT,fin);
fwrite((void*)str,sizeof(str[0]),strlen(str)+1,fin);
fclose(fin);
fout = fopen(file_name,"r");
if(fout == (FILE*)NULL)
{
exit(-1);
}
char ss[MAXN_STR];
int pos;
for(int i = 0; i < MAXN_OBJECT; ++i)
{
rewind(fout);
fseek(fout,(i*sizeof(TYPE_NODE)),SEEK_CUR);
pos = ftell(fout);
printf("cur pos %d\n",pos);
fread(&tmp_object,sizeof(TYPE_NODE),1,fout);
printf("%d %f %f %s\n",tmp_object.id,tmp_object.x,
tmp_object.y,tmp_object.str);
}
fread(ss,sizeof(ss[0]),strlen(str)+1,fout);
printf("%s\n",ss);
fclose(fout);
return 0;
}
基础API
这里只写出两个:
ssize_t pread(int filedes, void* buf, size_t nbyte, off_t offset);
ssize_t pwrite(int filedes, void* buf, size_t nbyte, off_t offset);
这两个函数需要设置offset来对文件进行读写,但是不会影响文件指针,比较适合随机查找的情况。
====== 总结之 文件操作API======
FILE* fopen(const char* filename,const char* mode);
FILE* fdopen(int filedes, const char* type);
int fputc(int c,FILE* stream);
int fgetc(FILE* stream);
int fprintf(FILE* stream, const char* format, ...);
int fscanf(FILE* stream, const char* format, ...);
int sprintf(char* str, const char* format, ...);
int sscanf(char* str, const char* format, ...);
size_t fread(void* ptr,size_t size,size_t nmemb,FILE* stream);
size_t fwrite(const void* ptr,size_t size,size_t nmemb,FILE* stream);
void rewind(FILE* stream);
long ftell(FILE* stream);
int fseek(FILE* stream,long offset, int whence);
int lseek(FILE* stream,long offset, int whence);
int fgetpos(FILE* stream, fpos_t* pos);
int fsetpos(FILE* stream, fpos_t* pos);
int fclose(FILE* stream);
int open(const char* pathname, int flags);
int open(const char* pathname, int flags, mode_t mode);