操作系统--文件操作

1、简介

Linux操作系统对文件的操作接口主要有系统调用接口,如 open、read、write、access、lseek、close以及C库函数接口,如 fopen、fread、fwrite、fseek、fclose、feof等,由于最近需要做SD卡的录像存储,因此对这些接口的使用做一个整体的记录。

2、使用方法

2.1 fopen和open函数

2.1.1 fopen:

  1. 函数原型:
    FILE *fopen(const char *filename, const char *mode);
  2. 函数参数:
  • filename-- 这是 C 字符串,包含了要打开的文件名称。
  • mode-- 这是 C 字符串,包含了文件访问模式。
  1. 函数功能:
    使用给定的模式 mode 打开 filename 所指向的文件。文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回 NULL,并把错误代码存在 error 中。该函数位于C 标准库<stdio.h>中。

mode 有下列几种形态字符串:
在这里插入图片描述
上述的形态字符串都可以再加一个b字符,如rb、w+b或ab+等组合,加入b 字符用来告诉函数库以二进制模式打开文件。如果不加b,表示默认加了t,即rt,wt,其中t表示以文本模式打开文件。由fopen()所建立的新文件会具有S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH (0666)权限,此文件权限也会参考umask 值。
有些C编译系统可能不完全提供所有这些功能,有的C版本不用"r+“,“w+”,“a+”,而用"rw”,“wr”,"ar"等,读者注意所用系统的规定。

  1. 二进制和文本模式的区别
    1.在windows系统中,文本模式下,文件以"\r\n"代表换行。若以文本模式打开文件,并用fputs等函数写入换行符"\n"时,函数会自动在"\n"前面 加上"\r"。即实际写入文件的是"\r\n" 。
    2.在类Unix/Linux系统中文本模式下,文件以"\n"代表换行。所以Linux系统中在文本模式和二进制模式下并无区别。

  2. 示例代码:

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
    
    
   FILE * fp;
 
   fp = fopen ("file.txt", "w+");
   fprintf(fp, "%s %s %s %d", "We", "are", "in", 2014);
   
   fclose(fp);
   
   return(0);
}

2.1.2 open

  1. 函数原型:
    int open(const char *path, int oflags,mode_t mode);
  2. 函数参数:
  • path:路径名或者文件名。
  • oflags:打开文件所采取的动作。可能值:必须指定下面某一种:
    1) O_RDONLY(只读),
    2) O_WRONLY(只写),
    3) O_RDWR(可读可写)
    打开/创建文件时,至少得使用上述三个常量中的一个,以下常量是选用的:
    4) O_APPEND 每次写操作都写入文件的末尾
    5) O_CREAT 如果指定文件不存在,则创建这个文件
    6) O_EXCL 如果要创建的文件已存在,则返回 -1,并且修改errno的值
    7) O_TRUNC 如果文件存在,并且以只写/读写方式打开,则清空文件全部内容
    8) O_NOCTTY 如果路径名指向终端设备,不要把这个设备用作控制终端。
    9) O_NONBLOCK 如果路径名指向 FIFO/块文件/字符文件,则把文件的打开和后继 I/O设置为非阻塞模式(nonblocking mode).
  1. 函数功能:open函数一般用于打开或者创建文件,在打开或创建文件时可以制定文件的属性及用户的权限等各种参数。使用open时,需要包含以下头文件,#include < sys/types.h >,#include < sys/stat.h >,#include < fcntl.h >。

2.2 read和read函数

2.2.1 fread

  1. 函数原型:size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

  2. 函数参数:
    在这里插入图片描述

  3. 函数功能:从给定输入流stream读取最多count个对象到数组buffer中(相当于以对每个对象调用size次fgetc),把buffer当作unsigned char数组并顺序保存结果。流的文件位置指示器前进读取的字节数。若出现错误,则流的文件位置指示器的位置不确定。若没有完整地读入最后一个元素,则其值不确定。成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。

  4. 示例代码:

#include <stdio.h>
#include <string.h>
 
int main()
{
    
    
   FILE *fp;
   char c[] = "This is runoob";
   char buffer[20];

   /* 打开文件用于读写 */
   fp = fopen("file.txt", "w+");
 
   /* 写入数据到文件 */
   fwrite(c, strlen(c) + 1, 1, fp);
 
   /* 查找文件的开头 */
   fseek(fp, 0, SEEK_SET);
 
   /* 读取并显示数据 */
   fread(buffer, strlen(c)+1, 1, fp);
   printf("%s\n", buffer);
   fclose(fp);
   
   return(0);
}

2.2.2 read

  1. 函数原型:size_t read (int fd, void *buf, size_t count);
  2. 函数参数:
  • fd为文件描述符;
  • buf表示读出数据缓冲区地址;
  • count表示读出的字节数。
  1. 函数功能:参数count是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后移。
    在这里插入图片描述

2.3 wrire和fwrite函数

2.3.1 fwrite

  1. 函数原型:size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
  2. 函数参数:
  • ptr: 这是指向要被写入的元素数组的指针。
  • size: 这是要被写入的每个元素的大小,以字节为单位。
  • nmemb: 这是元素的个数,每个元素的大小为 size 字节。
  • stream: 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
  1. 函数功能:把ptr所指向的数组中的数据写入到给定流stream中。如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个错误。
  2. 示例代码:
#include<stdio.h>
 
int main ()
{
    
    
   FILE *fp;
   char str[] = "This is runoob.com";
 
   fp = fopen( "file.txt" , "w" );
   fwrite(str, sizeof(str) , 1, fp );
 
   fclose(fp);
  
   return(0);
}

2.3.2 write

  1. 函数原型:size_t write(int fd, const void *buf, size_t count);
  2. 函数参数:
  • fd: 文件描述符
  • buf: 存放要写入的数据的缓冲区首地址
  • count:想要写入的字节数
  1. 函数功能:
    write()会把参数buf所指的内存写入count个字节到参数fd所指的文件内。
    在这里插入图片描述

2.4 lseek和fseek函数

2.4.1 fseek

  1. 函数原型:int fseek(FILE *stream, long offset, int fromwhere);
  2. 函数参数:
  • fp 为文件指针,也就是被移动的文件。
  • offset 为偏移量,也就是要移动的字节数。之所以为 long 类型,是希望移动的范围更大,能处理的文件更大。offset 为正时,向后移动;offset 为负时,向前移动。
  • origin 为起始位置,也就是从何处开始计算偏移量。C语言规定的起始位置有三种,分别为文件开头、当前位置和文件末尾,每个位置都用对应的常量来表示
    偏移起始位置(基准):
    文件头(SEEK_SET);
    当前位置SEEK_CUR),
    文件尾(SEEK_END)
  1. 函数功能:
    重定位流(数据流/文件)上的文件内部位置指针, 这个函数可以用来统计文件的大小,移动文件的位置,设置空文件的大小。成功返回当前位置到开始的长度,失败返回-1并设置errno。
  2. 示例代码:
#include <stdio.h>

int main ()
{
    
    
   FILE *fp;

   fp = fopen("file.txt","w+");
   fputs("This is runoob.com", fp);
  
   fseek( fp, 7, SEEK_SET );
   fputs(" C Programming Langauge", fp);
   fclose(fp);
   
   return(0);
}

2.4.2 lseek

  1. 函数原型:off_t lseek(int fd, off_t offset, int whence);
  2. 函数参数:
  • fd:文件描述符
  • offset:偏移量
  • whence:位置
SEEK_SET:The offset is set to offset bytes. offset为0时表示文件开始位置。
SEEK_CUR:The offset is set to its current location plus offset bytes. offset为0时表示当前位置。
SEEK_END:The offset is set to the size of the file plus offset bytes. offset为0时表示结尾位置
  1. 函数功能:
    重定位流(数据流/文件)上的文件内部位置指针,这个函数可以用来统计文件的大小,移动文件的位置,设置空文件的大小。成功返回当前位置到开始的长度,失败返回-1并设置errno。

2.5 close和fclose函数

2.5.1 fclose

  1. 函数原型:
    int fclose( FILE *fp );
  2. 函数参数:
    stream-- 这是指向 FILE 对象的指针,该 FILE 对象指定了要被关闭的流。
  3. 函数功能:
    fclose是一个函数名,功能是关闭一个流。注意:使用fclose()函数就可以把缓冲区内最后剩余的数据输出到内核缓冲区,并释放文件指针和有关的缓冲区。如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)
  4. 示例代码:
#include <stdio.h>

int main ()
{
    
    
   FILE *fp;

   fp = fopen("file.txt","w+");
   fputs("This is runoob.com", fp);
  
   fseek( fp, 7, SEEK_SET );
   fputs(" C Programming Langauge", fp);
   fclose(fp);
   
   return(0);
}

2.5.2 close

  1. 函数原型:
    int close(int fd);
  2. 函数参数:
    fd:需要关闭的文件fd。
  3. 函数功能:
    close() 成功返回零。上的错误,则返回-1,errno设置为合适。

2.6 access函数

  1. 函数原型:
    int access(const char* pathname, int mode)
  2. 函数参数:
    pathname 是文件的路径名+文件名;
    mode:指定access的作用,取值如下
F_OK 值为0,判断文件是否存在
X_OK 值为1,判断对文件是可执行权限
W_OK 值为2,判断对文件是否有写权限
R_OK 值为4,判断对文件是否有读权限
注:后三种可以使用或“|”的方式,一起使用,如W_OK|R_OK
  1. 函数功能:
    access函数用来判断指定的文件或目录是否存在(F_OK),已存在的文件或目录是否有可读(R_OK)、可写(W_OK)、可执行(X_OK)权限。F_OK、R_OK、W_OK、X_OK这四种方式通过access函数中的第二个参数mode指定。如果指定的方式有效,则此函数返回0,否则返回-1。
  2. 示例代码:
#include"stdio.h"
#include"unistd.h"
#include "string.h"
#define fileNAME1 "test"
#define fileNAME2 "./liang"
 
int main(void)
{
    
    
    char name[BUFSIZ];//文件名字
    int flag = 1;//退出标志,0 exit
    printf("\t\t\t程序开始\n");
    printf("请输入要检查的文件(可包含路径,EOF退出):");
    scanf("%s",name);
 
    if( strcmp(name,"EOF") == 0 ){
    
    
        flag = 0;
    }
    while(flag){
    
    
        if(access(name,F_OK)==0){
    
    
            printf("文件存在\n");
            if(access(name,R_OK|W_OK)==0){
    
    
                printf("文件可读可写\n");
            }else
                printf("文件不可读或不可写\n");
            if(access(name,X_OK)==0){
    
    
            printf("文件可执行\n");
            }else
                printf("文件不可执行\n");
        }else
            printf("文件不存\n");
        printf("\n请输入要检查的文件(可包含路径,EOF退出):");
        scanf("%s",name);
        if( strcmp(name,"EOF") == 0 ){
    
    
            flag = 0;
        }
    }//while
    printf("\t\t\t程序结束\n");
    return 0;
}

2.7 feof 函数

  1. 函数原型:
    int feof(FILE *stream);
  2. 函数参数:
    stream-- 这是指向 FILE 对象的指针,该 FILE 对象指定了要被检测的流。
  3. 函数功能:
    feof是C语言标准库函数,其原型在stdio.h中,其功能是检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0(即,文件结束:返回非0值;文件未结束:返回0值)。
  4. 示例代码:
#include<stdio.h>
int main(void)
{
    
    
    FILE *stream;
    /*open a file for reading*/
    stream = fopen("DUMMY.FIL", "r");
    /*read a character from the file*/
    fgetc(stream);
    /*check for EOF*/
    if(feof(stream))
        printf("We have reached the end of file\n");
    /*close the file*/
    fclose(stream);
    return 0;
}

feof(fp)有两个返回值:如果遇到文件结束,函数feof(fp)的值为非零值,否则为0。

3、 总结

关于两套函数的差异,以open函数和fopen函数为例:

  1. 从来源的角度看:
  • open是LUNIX系统调用函数,返回文件描述符(File Descriptor),它是文件在文件描述符表里的索引。
  • fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。
  1. 从移植角度:
  • fopen是C标准函数,有良好的移植性;
  • open是LUNIX系统调用,移植性有限。如windows下相似的功能使用API函数CreateFile
  1. 从适用范围:
  • open返回文件描述符,LUNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
  • fopen是用来操纵普通正规文件(Regular File)
  1. 从缓冲角度:
  • open无缓冲;
  • fopen有缓冲。缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问。缓冲就是先对缓冲区操作,然后再对文件操作。比如执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满再写入文件。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出。

参考资料:
《https://www.runoob.com/cprogramming/c-standard-library-stdio-h.html》
《https://blog.csdn.net/jinmie0193/article/details/79875662》

猜你喜欢

转载自blog.csdn.net/jisuanji111111/article/details/125231467