初识文件IO

1.文件

何为文件?在Linux中一切皆文件,这是贯穿Linux这个整个操作系统的概念,但站在内核里来看(网络接口不是的),其它都一律使用Linux独有的虚拟文件系统VFS来管理,这样做的最终目的是为了将各种不同的设备用“文件”这个概念来加以封装和屏蔽,来简化应用层编程的难度让我们这程序员来使用。

2.文件的类型

文件的类型都有:

一、常规文件:ASCII码文件、二进制文件

二、目录文件

三、字符设备文件

四、块设备文件

五、有名管道文件

六、套接口文件

七、符号链接文件

3.文件IO和标准IO

对文件我们都有两种不同的操作方式:1.文件IO 2.标准IO

一、文件IO是Lunx系统直接提供的

这里称作为:系统调用。当我们的应用程序要使用一些底层的功能时,我们得向系统请求,不应该自行访问底层。系统反馈给我们的就是一些函数又称作为系统函数。

文件IO的特点:

1.不带缓冲区

2.操作系统直接提供的函数接口

3.调用系统函数很浪费资源

二、标准IO是由C库直接提供的。

标准IO是由C库函数直接在系统调用接口之上封装的接口,一个C库函数封装着多个系统调用函数。

标准IO的特点

1.带缓冲区

2.提高了效率

3.增加了代码的可移植性,复用性

标准IO函数

普遍用到的标准IO函数:fopen、fclose、fgetc、fputc、fgets、fputs、fread、fwrite

1.fopen函数

功能:打开文件。

函数原型:FILE *fopen(const char *path,const char *mode);
参数:path:文件的路径名 "文件路径名"、mode:打开的方式
    打开方式:r:只读的方式打开文件,文件必须存在
        	r+:读写的方式打开文件,文件必须存在
            w:只写的方式打开文件,(文件存在则清空 || 文件不存在则创建)
            w+:读写的方式打开文件,(文件存在则清空 || 文件不存在则创建)
            a:以追加的方式打开文件(读),(文件不存在则创建 || 文件存在则追加在文件的末尾)
            a+::以追加的方式打开文件(读写),(文件不存在则创建 || 文件存在则追加在文件的末尾
函数的返回值:
           成功:返回FILE *(流指针 == 也是一个结构体指针)
           失败:NULL

例:FILE *p=("./bin","w+");

//出错处理

sterror(errno);//:参数就是错误码errno

perror("fopen"); //参数就是字符串

FILE:系统会自动为使用的文件在内存中开辟一片空间,来存储文件的详细信息,这个空间的数据类型为结构体类型,是由系统自己设计的。

FILE *:流指针,在标准IO中,每次打开一个文件都会返回一个流指针,我们也得用同样类型的FILE *去接收这个流指针,这个流指针则描述了一个文件,所有的标准IO都是围绕着文件来进行的。

同一个文件可以存在多个流指针

标准IO函数测试当前系统最大能打开的文件个数为1021,其实为:1024。因为在系统中我们使用的输入、输出、错误提示都是文件,这就证实了linux下一切皆文件嘛。

这三个文件分别是:标准输入流、标准输出流、标准错误流,占了1024里的0、1、2。

打开我们的终端时系统就默认打开了3个流指针 :

stdin (标准输入,终端进行输入)

stdout(标准输出,终端打印出来)

stderr(标准错误,终端打印出来)

2.fclose

int fclose(FILE *fp);
功能:close意味着关闭嘛,也就是关闭我们fopen打开的文件
参数:
	fp:流指针
例:fclose(fp);

为什么要关闭一个文件呢?

一、防止其它进程操作这个文件

二、释放掉这个结构体的占用的资源

虽然在程序结束时,系统会自动回收资源,但是回收的不完全,每打开一个文件,都释放掉打开这个文件的结构体最好。

3.freopen

FILE *freopen(const char *path, const char *mode, FILE *stream);
功能:改变流指针的指向
参数:
	path: 文件的路径名
  	mode: 打开方式
  	stream:流指针

4.fgetc

int fgetc(FILE *stream);
功能:读取一个字节的数据
参数:
	stream:流指针
返回值:
	成功:返回这个字节
	失败:-1

5.fputc

int fputc(int c,FILE *stream);
功能:写入一个字节的数据
参数:
    int c:字节
    stream:流指针

小练习

向我们的终端循环打印 'X'

因为每一个终端都是一个文件: pts/xxx 这个就是终端对应的文件,这个文件的名字是以数字命名的 这个文件存储在 : /dev/pts/xxx 这些文件是由linux系统自动创建。当打开一个终端时,就会重建一个新的文件与之对应 stdin、stdout、stderr都指向的是同一个文件(终端文件)。

 #include <stdio.h>
  8 #include <unistd.h>
  9 int main(int argc, char *argv[])
 10 {
 11     FILE *fp = fopen("/dev/pts/1","r+");//:以读写的方式打开我们新开的终端文件
 12         if(NULL == fp){
 13             perror("fopen");//:判断返回值
 14             return -1;
 15         }
 16         while(1){
 17             fputc('x',fp);//:调用函数fputc循环打印x
 18             fputc('\n',fp);
 19             sleep(2);//:用延时函数2秒打印一个
 20         }
 21 
 22     return 0;
 23 }
​

编译好程序后并运行,就可以掉出我们另外一个新开的终端就可以看见它在每隔2秒得循环打印 'X' 这个字符。这就是一切皆文件!

缓冲区

前面提到过,标准IO是有缓冲区的,而文件IO并没有。缓冲区也分为:行缓存、无缓存、全缓存。

一、行缓存

printf、stdin、stdout是行缓存。

缓冲区的大小是1024byte == 1kbyte。

行缓存的特点:

1.行缓存满了或遇到 ’\n' 输出条件

2.fflush可以强制刷新

3.文件关闭的时候fclose(stdout)

4.程序结束的时候exit或者return

#include <stdio.h>
  8 #include <stdlib.h>
  9 int main(int argc, char *argv[])
 10 {
 11     printf("hello world");
 12 /*    fclose(stdout);
 13     fflush(stdout);
 14    int i=0;           //:中间是注释掉的部分
 15     for(;i<1014;i++){
 16         fputc('x',stdout);
 17     }*/
 18     while(1);
 19 
 20     return 0;
 21 }

当我们这个程序中的printf函数遇到while(1)时,它是打印不出hello world的。

一、当我们在printf函数后加上'\n'则可以打印出我们要的字符串了。

 #include <stdio.h>
  8 #include <stdlib.h>
  9 int main(int argc, char *argv[])
 10 {
 11     printf("hello world\n");
 12 /*    fclose(stdout);
 13     fflush(stdout);
 14    int i=0;
 15     for(;i<1014;i++){
 16         fputc('x',stdout);
 17     }*/
 18     while(1);
 19 
 20     return 0;
 21 } 
 

 

二、当我们使用fflush强制刷新也是可以的,注意去掉字符串后的'\n'

#include <stdio.h>
  8 #include <stdlib.h>
  9 int main(int argc, char *argv[])
 10 {
 11     printf("hello world");
 12     fflush(stdout);
 13  /*   fclose(stdout);
 14    int i=0;
 15     for(;i<1014;i++){
 16         fputc('x',stdout);
 17     }*/
 18     while(1);
 19 
 20     return 0;
 21 } 

 

三、利用flcose(stdout)关闭标准输出流的操作来达到

#include <stdio.h>
  8 #include <stdlib.h>
  9 int main(int argc, char *argv[])
 10 {
 11     printf("hello world");
 12 //    fflush(stdout);
 13    fclose(stdout);
 14 /*   int i=0;
 15     for(;i<1014;i++){
 16         fputc('x',stdout);
 17     }*/
 18     while(1);
 19 
 20     return 0;
 21 }
 

 

四、程序结束的时候exit或者return

#include <stdio.h>
  8 #include <stdlib.h>
  9 int main(int argc, char *argv[])
 10 {
 11     printf("hello world");
 12         exit(0);
 13 //    fflush(stdout);
 14 //   fclose(stdout);
 15 /*   int i=0;
 16     for(;i<1014;i++){
 17         fputc('x',stdout);
 18     }*/
 19     while(1);
 20 
 21     return 0;
 22 }
 

 

五、补充一下1里面的当行缓存满的情况,这里我们要了解到行缓存最大是1024个字节,我需要打印的字符串占了11个字节,然后for循环例循环得给标准输出流输出1013个字节,使行缓存占满了,所以就打印出来了。

#include <stdio.h>
  8 #include <stdlib.h>
  9 int main(int argc, char *argv[])
 10 {
 11     printf("hello world");
 12 //        exit(0);
 13 //    fflush(stdout);
 14 //   fclose(stdout);
 15     int i=0;
 16     for(;i<1014;i++){
 17         fputc('x',stdout);
 18     }
 19     while(1);
 20 
 21     return 0;
 22 }
​

二、无缓冲

函数stderr。

#include <stdio.h>
  8 
  9 int main(int argc, char *argv[])
 10 {
 11     fputc('x',stderr);
 12     while(1);
 13 
 14     return 0;
 15 }

三、全缓存

通过fopen函数打开的流指针,这个流指针fp的缓冲区大小是 4*1024 4Kbyte 1.缓存区满 2.fclose(fp) 3.return 4.exit 5.fflush(fp)

只是这个全缓存是通过流指针打开的一个缓存区,注意这个缓存区的大小不是1024,而是4*1024,其它的函数用法基本无差异。

#include <stdio.h>
  8 
  9 int main(int argc, char *argv[])
 10 {
 11     FILE *fp = fopen("./e.txt","a");
 12         if(NULL == fp){
 13             perror("fopen");
 14             return -1;
 15         }
 16         fputc('x',fp);
 17         fputc('x',fp);
 18         fputc('x',fp);
 19         fputc('x',fp);
 20         fputc('x',fp);
 21 //        printf("size=%ld ",fp->_IO_buf_end - fp->_IO_buf_base);
 22         fclose(fp);
 23 /*        int i=0;
 24         for(;i<4096;i++){
 25             fputc('a',fp);
 26         }*/
 27         while(1);
 28 
 29     return 0;
 30 }

通过流指针打开文件e.txt,然后往文件里写入5个'X字符

'

执行完程序后,我们打开被fopen打开的e.txt文件查看

6、fgets

函数解释:

char *fgets(char *s,int size,FILE *stream)
功能:从文件读取一行的数据并且写入到内存空间
参数:
    s:内存地址,也可以在内存上定义一片空间
    size:内存空间的大小 N
    stream:流指针
返回值:
      成功:返回读取字符的首地址
      失败:NULL

代码演示

#include <stdio.h>
  8 
  9 int main(int argc, char *argv[])
 10 {
 11     FILE * fp = fopen("./dict.txt","r");//:打开我这里事先准备好的一个单词文件,里面都是单词。
 12     if(NULL == fp){
 13         perror("fopen");
 14         return -1;
 15     }
 16     char buf[10000]={0};
 17     int count=0;
 18     while(1){
 19         char *p = fgets(buf,sizeof(buf),fp);//:读出来的每一行数据都写入buf这个数组里,buf就是开辟的内存空间、sizeof就是buf这个空间的大小、fp:流指针
 20         if(NULL == p){
 21             perror("fgets");
 22             break;
 23         }else{
 24             count++;//:count是用来计数的,因为上面是定义了一个循环,每读一行就加1.
 25         }
 26     }
 27     printf("%d \n",count);
 28 
 29     return 0;
 30 }

char * p来接受这个fgets函数的返回值是因为,之前函数原型提到过,这个函数的返回值成功则是一个字符串的首地址。

显示我们的函数使用成功,返回的正常字符串首地址,7987说明我打开的文件里有7987哥单词(特别说明:因为fgets是读取一行的函数,所以在我打开的文件里一个单词是占一行的)。

7、fputs

函数解释:

int fputs(const char *s,FILE *stream)
功能:向文件写入一行数据
    参数:
        S:内存地址,开辟的存储空间已经有数据存在
        stream:流指针
返回值:
    成功:1
    失败:-1

代码演示:

#include <stdio.h>
  8 
  9 int main(int argc, char *argv[])
 10 {
 11     FILE *fp = fopen("./aa.txt","w");//:打开这个文件。
 12         if(NULL == fp){
 13             perror("fopen");
 14             return -1;
 15         }
 16         char buf[100]="hello world";//:系统通过我们自己的定义给我们开辟了一个数组内此外空间,并且里面我们存着"hello world"这个字符串。
 17         int n=fputs(buf,fp);//:通过buf向我们打开的文件里写入这个字符串。
 18         printf("n=%d \n",n);//:查看函数的返回值。
 19 
 20     return 0;
 21 }

结果:

这里的1便就是函数的返回值,返回了1说明函数是成功的。

文件里也被我们写入了这个字符串。

小练习

用前面学到的知识写一个copy指令:把一个文件的内容复制到另一个文件内

代码:

#include <stdio.h>
  8 #include <stdlib.h>
  9 #include <string.h>
 10 int main(int argc, char *argv[])
 11 {
 12     if(argc != 3){
 13         printf("%s src_file dest_file\n",argv[0]);//如果命令行参数少于3个,则打印提示信息
 14     }
 15     FILE *fp1 = fopen(argv[1],"r");//定义第一个流指针,命令行第二个参数写文件名,打开这个文件
 16         if(NULL == fp1){
 17         perror("fopen");
 18         return -1;
 19      }
 20     FILE *fp2 = fopen(argv[2],"w");//定义第二个流指针,命令行第二个参数写文件名,打开这个文件
 21         if(NULL ==  fp2){
 22             perror("open");
 23             return -1;
 24         }
 25     char buf[100]={0};//我们从第一文件读的数据得存储到内存
 26     while(1){
 27     char *p = fgets(buf,sizeof(buf),fp1);//判断函数是否成功执行
 28         if(NULL == p){
 29             perror("fgets");
 30             break;
 31         }
 32         if(strncmp(buf,"quit",4) == 0){
 33             break;
 34         }
 35         fputs(buf,fp2);把内存的内容写入到第二个流指针打开的文件中
 36     }
 37     printf("Copy Sucess..\n");
 38     fclose(fp1);
 39     fclose(fp2);
 40 
 41     return 0;
 42 }

结果

a.txt里的内容就这样被复制到额e.txt了。

8、fseek

函数原型

int fseek(FILE *stream, long offset, int whence);
功能:定位文件指针
参数:
  stream: 流指针
  offset: 偏移量 
            100:向后偏移100个字节
            -100:向前偏移100个字节
  whence: 基点 
      SEEK_SET: 文件开头
      SEEK_END: 文件末尾
      SEEK_CUR: 文件当前位置
返回值:
    成功:0
    失败:-1
例:
  定位到文件末尾:   fseek(fp,   0  , SEEK_END);
  定位到文件末尾的前一个字节: fseek( fp, -1, SEEK_END );

1、ftell

long ftell(FILE *stream);
返回值:当前文件指针的位置(大小)

2、rewind

void rewind(FILE *stream);
功能:文件指针返回到文件开头

代码:

#include <stdio.h>
  8 
  9 int main(int argc, char *argv[])
 10 {
 11     FILE * fp = fopen("./a.txt","r+");
 12         if(NULL == fp){
 13             perror("fopen");
 14             return -1;
 15         }
 16         int ret = fseek(fp,-4,SEEK_END);//把指针移动到文件的到数第4个地址
 17         int n = ftell(fp);//统计文件的大小,也就算统计文件的位置。
 18         printf("文件的位置(大小):%d \n",n);
 19         rewind(fp);//把文件的指针返回到文件的开头
 20         int m = ftell(fp);
 21         printf("文件的位置(大小):%d \n",m);//指针返回到文件开头再来看指针的位置。
 22 
 23 
 24     return 0;
 25 }
​

文件里的内容大小:

运行结果:

9、fread

函数原型:

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:读取数据
参数:
    ptr: 内存地址  eg: char ptr[];
    size: 字节数
    nmemb: 块数
    stream: 流指针
返回值:
    成功:块数
    失败:-1

内存地址如下面开辟的buf:

char buf[1000] = {0};
​
函数的用法:
fread(buf, 100, 10, fp);  //读取1000个字节的数据
​
fread(buf, 10, 100, fp);
​
fread(buf, 1, 1000, fp);
​
fread(buf, 1000, 1, fp);
​
fread(buf, 20, 50, fp);
.......

代码:

#include <stdio.h>
  8 
  9 int main(int argc, char *argv[])
 10 {
 11     FILE *fp = fopen("./1.txt","rb");//打开文件
 12         if(NULL == fp){
 13             perror("fopen");
 14             return -1;
 15         }
 16         char buf[100]={0};
 17         int n = fread(buf,100,1,fp);//读取文件到BUF
 18         printf("%d \n",n);
 19         printf("%s \n",buf);
 20         fclose(fp);
 21 
 22     return 0;
 23 }

10、fwrite

只要有读,那就肯定有写了

函数原型:

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:写入数据
参数:
    ptr: 内存地址  eg: char ptr[];
    size: 字节数
    nmemb: 块数
    stream: 流指针
返回值:
    成功:块数
    失败:-1

代码:

 #include <stdio.h>
  8 #include <string.h>
  9 struct xiaomao{
 10     char sex[10];
 11     int age;
 12     int tall;
 13 };
 14 int main(int argc, char *argv[])
 15 {
 16     FILE *fp = fopen("./2.txt","wb+");//:打开文件,注意这里的打开方式为读写,W后面有个b是说明二进制文件。
 17         if(NULL == fp){
 18             perror("fopen");
 19             return -1;
 20         }
 21        // char arr1[20]="123xiaomao456";
 22        // char arr2[20]={0};
 23         struct xiaomao a={"man",23,175};//定义一个结构体
 24         struct xiaomao b;
 25         fwrite(&a,sizeof(a),1,fp);//把结构体不同类型的数据通过流指针写入到文件中
 26         printf("Write sucess..\n");
 27         rewind(fp);//因为上面的写入函数执行后,就把文件的指针移位了,这里使用rewind函数使文件指针回到文件的开头
 28         fread(&b,sizeof(b),1,fp);//如果我们不执行上一步操作的话,这里的fread就不会从文件开头读并写入到结构体B中
 29         printf("%s %d %d",b.sex,b.age,b.tall);//打印结构体b的数据
 30 
 31     return 0;
 32 }

运行结果:

printf相关函数

11、fprintf(组装数据)

函数原型:

int  fprintf(FILE  *stream,  const  char *format, ...);
功能:按照格式把数据放在流指针指向的文件中(组装数据到文件中)
参数:
  stream: 流指针
  format: 格式控制符
  ...:不定参数

例:

fprintf(fp, "%d-%d-%d", 2023,2,15);

12、sprintf

函数原型:

int sprintf(char *str, const char *format, ...);
功能:按照格式把数据放在内存中(组装数据到内存中)
参数:
  stream: 流指针
  format: 格式控制符
  ...:不定参数

13、sscanf(提取数据)

函数原型:

int sscanf(const char *str, const char *format, ...);
功能:把内存中的数据提取到不定参数中
参数:
  str: 内存地址
  format: 格式控制符
  ...:不定参数

代码例:

#include <stdio.h>
  8 
  9 int main(int argc, char *argv[])
 10 {
 11     char buf[100]="2023-2-15 hello wrold";//定义好一个数组,里面放好数据
 12     int a,b,c;
 13     char arr1[10];
 14     char arr2[10];
 15 
 16     sscanf(buf,"%d-%d-%d %s %s",&a,&b,&c,arr1,arr2);//提取buf数组里的值放在后面定义的三个不定参数里
 17     printf("%d %d %d %s %s",a,b,c,arr1,arr2);
 18     puts(" ");
 19 
 20     return 0;
 21 }

14、fscanf

函数原型

int fscanf(FILE *stream, const char *format, ...);
功能:把文件中的数据提取到不定参数中
参数:
  str: 流指针
  format: 格式控制符
  ...:不定参数

这里只需要打开文件,然后定义不定参数,运用fscanf就行了。

时间相关函数

15、time

#include <time.h>
#include <unistd.h>
​
time_t t; //函数的传参相关变量
time_t time(time_t *t);
功能:从1970-1-1 0:0:0开始到现在的秒数
参数:
    t:  &t / NULL
返回值:
    成功:从1970-1-1 0:0:0开始到现在的秒数
    失败:-1
#include <time.h>
​
time_t t;
struct tm *localtime(const time_t *timep);
功能:从1970-1-1 0:0:0开始到现在的秒数转化成日历
参数:
    timep: &t
返回值:
    成功:struct tm *
    失败:NULL
struct tm {
   int tm_sec;    /* Seconds (0-60) */
   int tm_min;    /* Minutes (0-59) */
   int tm_hour;   /* Hours (0-23) */
   int tm_mday;   /* Day of the month (1-31) */
   int tm_mon;    /* Month (0-11) */
   int tm_year;   /* Year - 1900 */
};

小练习

获取系统时间并输出打印

代码:

#include <stdio.h>
  8 #include <time.h>
  9 #include <unistd.h>
 10 int main(int argc, char *argv[])
 11 {
 12  /*   FILE *fp = fopen("./time.txt","w+");
 13         if(NULL == fp){
 14             return -1;
 15         }*/
 16         time_t t;//定义time相关函数传参变量
 17         struct tm *p;//因为localtime函数返回的是一个结构体的地址,我们这里就需要定义一个结构体指针来接受这个返回的地址
 18         while(1){
 19             time(&t);
 20             p=localtime(&t);
 21             printf("%d-%d-%d %d:%d:%d\n",p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
 22 //            fprintf(fp,"%d-%d-%d %d:%d:%d\n",p->tm_year+1900,p->tm_mon+1,p->tm_mday,p->tm_hour,p->tm_min,p->tm_sec);
 23             sleep(1);
 24 //            fflush(fp);
 25         }
 26 //        fclose(fp);
 27 
 28     return 0;
 29 }

这里屏蔽掉文件呢,是把时间直接打印到终端,如果不屏蔽就是使用上面学到的fprintf函数把时间这个数据组装到文件里同时也要打印到终端。

运行结果:

文件IO

1、文件描述符

文件描述符实际上是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符,进程使用它来标识打开的文件。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。

Linux系统为程序中每个打开的文件都分配一个文件描述符,文件IO操作通过文件描述符来完成。

文件描述符在形式上是一个顺序分配的非负整数。从0开始分配,依次递增。比如 0,1,2表示 stdin stdout stderr,一般最大打开的文件描述符数量为1024(0~1023)

2、fdopen

函数原型:

FILE *fdopen(int fd, const char *mode);
功能:文件IO转换成标准IO
参数;
  fd: 文件描述符
  mode: 打开方式
返回指:
    成功:流指针
    失败:NULL

代码例:

#include <stdio.h>
  8 
  9 int main(int argc, char *argv[])
 10 {
 11    FILE *fp =  fdopen(1,"w");//这里的1就算文件描述符stdout
 12     fprintf(fp,"%d-%d-%d\n",2023,2,15);//用fprintf函数组装数据,再通过流指针fp打开的标准输出文件stdout来在终端打印
 13 
 14     return 0;
 15 }
​

运行结果

2、open

函数原型:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
​
//打开文件,文件已经存在
int open(const char *pathname, int flags);
​
//创建文件,文件不存在
int open(const char *pathname, int flags, mode_t mode);
参数:
    pathname: 文件的路径名
    flags: 打开方式
                O_RDONLY:只读
                O_WRONLY:可写
                O_RDWR:读写
                O_APPEND:追加
                O_TRUNC:清零
                O_CREAT:创建    
    mode: 文件的权限 0666
返回指:    
    成功:文件描述符fd
    失败:-1
标准IO        文件IO
    r           O_RDONLY
    r+          O_RDWR
    w           O_WRONLY | O_CREAT | O_TRUNC
    w+          O_RDWR   | O_CREAT | O_TRUNC
    a           O_WRONLY | O_CREAT | O_APPEND
    a+          O_RDWR   | O_CREAT | O_APPEND

代码:

#include <stdio.h>
  8 #include <sys/types.h>
  9 #include <sys/stat.h>
 10 #include <fcntl.h>
 11 #include <unistd.h>
 12 int main(int argc, char *argv[])
 13 {
 14     int fd = open("./4.txt",O_RDONLY | O_CREAT,0666);//如果成功打开文件,返回的就是文件对应的文件描述符,如果打开失败就返回-1.
 15         if(fd<0){
 16             perror("open");
 17             return -1;
 18         }
 19     printf("open sucess..\n");
 20     close(fd);//通过上面接受到的文件描述符来关闭打开的文件。
 21     return 0;
 22 }

3、close

对应标准IO,又打开文件函数就有关闭文件函数

函数原型:

#include <unistd.h>
​
int close(int fd);

4、read

函数原型:

ssize_t read(int fd, void *buf, size_t count);
功能:从文件中读取count字节的数据到内存
参数:
    fd: 文件描述符
    buf: 内存地址
    count: 读取的字节数 100个字节
返回值:
    成功: 
        >0  返回实际读取到的字节数
        == 0 读到文件的末尾
    失败:
        <0 读取失败

代码:

#include <stdio.h>
  8 #include <stdio.h>
  9 #include <sys/types.h>
 10 #include <sys/stat.h>
 11 #include <fcntl.h>
 12 #include <unistd.h>
 13 int main(int argc, char *argv[])
 14 {
 15     int fd = open("./4.txt",O_RDONLY,0666);//:打开指定文件(文件里的内容为“hello world").
 16         if(fd == -1){
 17             perror("open");
 18             return -1;
 19         }
 20         char buf[100]={0};//自己定义一个数组
 21         int n = read(fd,buf,5);//使用read函数把文件里前5个字节的数据读取到buf内存中
 22         if(n<0){
 23             perror("read");
 24             return -1;
 25         }
 26         puts(buf);//打印数组内的内容
 27         close(fd);//关闭文件
 28 
 29     return 0;
 30 }

运行结果:

5、write

函数原型:

ssize_t  write(int  fd,  const void *buf, size_t count);
功能:把内存中的数据写入到文件中
参数:
    fd: 文件描述符
    buf: 内存地址
    count: 写入的字节数 100个字节
返回值:
    成功:返回实际写入的字节数
    失败:-1

代码思路跟上面一样,不过这里是直接给内存一个数据,再写入到文件中。

6、lseek

函数原型:

off_t lseek(int fd, off_t offset, int whence);
功能:定位文件指针
参数:
  fd: 文件描述符
  offset: 偏移量
    100:向后偏移100个字节
    -100:向前偏移100个字节
  whence: 基点
    SEEK_SET:文件开头
    SEEK_END:文件末尾
    SEEK_CUR:文件当前位置
返回值:
    成功:0
    失败:-1

目录操作函数

1、opendir

函数原型:

#include <sys/types.h>
#include <dirent.h>
​
DIR *opendir(const char *name);
功能:打开目录
参数:
  name: 目录的路径名
返回值:
   成功: DIR *
   失败: NULL

2、readdir

函数原型:

struct dirent *readdir(DIR *dirp);
功能:读取目录信息
参数:
  dirp: opendir的返回值
返回值:
   成功: struct dirent *
   失败: NULL(一直遍历,直到遍历目录完成返回NULL)
​
​
struct dirent {
   ino_t          d_ino;       /* inode number */
   off_t          d_off;       /* not an offset; see NOTES */
   unsigned short d_reclen;    /* length of this record */
   unsigned char  d_type;      /* type of file; not supported
                                  by all filesystem types */
   char           d_name[256]; /* filename */
};

3、closedir

函数原型:

int closedir(DIR *dirp);

小练习

查看目录下的文件(不看隐藏文件)

代码演示

#include <stdio.h>
  8 #include <sys/types.h>
  9 #include <dirent.h>
 10 #include <string.h>
 11 int main(int argc, char *argv[])
 12 {
 13     DIR *pdir = opendir("./");//打开当前目录文件
 14         if(NULL == pdir){
 15             perror("opendir");
 16             return -1;
 17         }
 18         struct dirent *p;//readdir返回值是一个结构体的地址,所以我们必须定义一个结构体指针来接受地址
 19         while(1){        //遍历整个目录
 20         p=readdir(pdir);
 21         if(NULL == p){
 22             break;
 23         }
 24         if(strncmp(p->d_name,".",1)==0){//判断是否为隐藏文件,我们这里只打印普通文件,若为隐藏文件,则执行if语句的continue语句来跳过次循环不让它打印该文件。
 25             continue;
 26         }
 27     printf("%s \n",p->d_name);
 28         }
 29     closedir(pdir);//关闭目录文件。
 30     return 0;
 31 }
​

运行结果:

文件信息函数

1、stat

函数原型:

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
​
struct stat mybuf;
​
int stat(const char *path, struct stat *buf);
功能:得到文件的属性
参数:
    path:文件路径名
    buf: &mybuf
​
-rw-rw-r-- 1 farsight farsight   593  4月 19 09:26 01picture.c
-rw-rw-r-- 1 farsight farsight   537  4月 19 09:53 02readdir.c
-rw-rw-r-- 1 farsight farsight   161  4月 19 10:23 03stat.c
-rwxrw-rw- 1 farsight farsight 97893  4月 19 09:26 5.jfif
-rwxrwxr-x 1 farsight farsight  7357  4月 19 09:53 a.out
    
//查看设备号
major   minor
  
    

struct stat {
    dev_t     st_dev;     /* ID of device containing file */
    ino_t     st_ino;     /* inode number */
    mode_t    st_mode; 文件的权限、文件的类型   /* protection */
    nlink_t   st_nlink;   /* number of hard links */
    uid_t     st_uid;  所属用户ID   /* user ID of owner */ 
    gid_t     st_gid;  所属组ID   /* group ID of owner */
    dev_t     st_rdev;    /* device ID (if special file) */
    off_t     st_size; 文件的大小   /* total size, in bytes */
    blksize_t st_blksize; /* blocksize for filesystem I/O */
    blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
    time_t    st_atime; 最后一次访问时间  /* time of last access */
    time_t    st_mtime; 最后一次修改时间  /* time of last modification */
    time_t    st_ctime; 最后一次文件文件属性修改时间  /* time of last status change */
};

2、getpwuid

函数原型:

struct passwd *getpwuid(uid_t uid);
获取用户名
​
struct passwd {
   char   *pw_name;       /* username */
   char   *pw_passwd;     /* user password */
   uid_t   pw_uid;        /* user ID */
   gid_t   pw_gid;        /* group ID */
   char   *pw_gecos;      /* user information */
   char   *pw_dir;        /* home directory */
   char   *pw_shell;      /* shell program */
};

3、getgrgid

函数原型:

struct group *getgrgid(gid_t gid);
获取组名
​
struct group {
    char   *gr_name;       /* group name */
    char   *gr_passwd;     /* group password */
    gid_t   gr_gid;        /* group ID */
    char  **gr_mem;        /* group members */
};

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值