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 */
};