1. 先介绍下 open 和 fopen 之间的区别

   1)open是系统调用,返回的是文件句柄,文件的句柄是文件在文件描述副表里的索引。fopen是ANSIC标准中的C语言库函数,返回的是一个指向文件结构的指针。

      在不同的系统中应该调用不同的内核api。linux中的系统函数是open,fopen是其封装函数,fopen的实现要调用open。

   2)fopen和open最主要的区别是是否有缓存:fopen用户态下就有了缓存,它使用了FILE这个结构保存缓冲数据。在进行read和write的时候减少了用户态和内核态的切换。

      open没有缓存,每次读操作都直接从文件系统中获取数据。在进行read和write的时候每次都需要进行内核态和用户态的切换。

      表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列快;如果随机访问文件open要比fopen快。

   3)一般用fopen打开普通文件,用open打开设备文件。

 

2. fopen函数打开文件

   下面列举出一些常用的函数:

/* 按mode模式打开一个文件 */
FILE* fopen(const char* filename, const char* mode);

/* 关闭一个文件流,可以把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。 */
int fclose(FILE* stream);

/* 
   1. 从给定输入流stream读取最多count个对象到数组buffer中,把buffer当作unsigned char数组并顺序保存结果。
      不论是二进制模式还是文本模式,fread都是按一个一个字符来读的。
   2. 文本模式和二进制模式存取文件的差别仅仅体现在回车换行符的处理上:
      Linux下的换行符是'\n', windows下的是'\r\n',所以差别就只存在在windows上。
      文本方式写时,每遇到一个'\n'(0AH换行符),它将其换成'\r\n'(0D0AH,回车换行),然后再写入文件。
      当文本读取时,它每遇到一个'\r\n'将其转为'\n',然后送到读缓冲区。所以会发生:fread的返回值--实际读取字节数
      要比文件定位符的跳转的数量小。正因为文本方式有'\n'<->'\r\n'之间的转换,其存在转换耗时。
      二进制读写时,其不存在任何转换,直接将写缓冲区中数据写入文件.
*/
size_t fread(void* ptr, size_t size, size_t count, FILE* stream);

// 向指定的文件中写入count字节数据,如成功执行则返回实际写入的字节数
size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream);

/*
   设置文件指针stream的位置,如果执行成功,stream将指向以origin为基准,偏移offset个字节的位置。
   SEEK_SET: Beginning of file
   SEEK_CUR: Current position of the file pointer
   SEEK_END: End of file *
 */
int fseek(FILE* stream, long int offset, int origin);

// 用于得到文件位置指针当前位置相对于文件首的偏移字节数
long int ftell(FILE* stream);

// 从文件指针stream指向的文件中读取一个字符,读取一个字节后,光标位置后移一个字节
int fgetc(FILE* stream);

// 从指定的流中读取数据,每次读取一行
char* fgets(char* str, int num, FILE* stream);

// 将字符ch写到文件指针fp所指向的文件的当前写指针的位置, 光标位置后移一个字节
int fputc(int ch, FILE* stream);

// 向指定的文件写入一个字符串(字符串包含结束符,但结束符不被写入),成功写入一个字符串后,文件的位置指针会自动后移
int fputs(const char* str, FILE* stream);

// 从一个流中执行格式化输入,fscanf遇到空格和换行时结束
int fscanf(FILE* stream, const char* format, ...);

// 根据指定的格式,向输出流写入数据
int fprintf(FILE* stream, const char * format, ...);

// 检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0
int feof(FILE* stream);

// 将文件内部的指针重新指向一个流的开头
void rewind(FILE* stream);

   下面我们来看一个例子:

int main () 
{
    FILE * pFile;
    long lSize;
    char* buffer;
    size_t result;

    pFile = fopen("myfile.bin" , "rb" );
    if(pFile == NULL) {
        fputs ("File error", stderr); 
        exit (1);
    }

    // obtain file size:
    fseek(pFile , 0 , SEEK_END);
    lSize = ftell(pFile);
    rewind(pFile);

    // allocate memory to contain the whole file:
    buffer = (char*)malloc(sizeof(char) * lSize);
    if(buffer == NULL) {
        fputs("Memory error", stderr); 
        exit (2);
    }

    // copy the file into the buffer:
    result = fread(buffer, 1, lSize, pFile);
    if (result != lSize) {
        fputs("Reading error", stderr); 
        exit (3);
    }

    // terminate
    fclose (pFile);
    free (buffer);
    return 0;
}

 

3. open函数打开文件

   这个是Linux下的函数,需要包含的头文件如下:

#include <sys/types.h>    
#include <sys/stat.h>    
#include <fcntl.h>

   具体等使用到再来详述。