文章的函数说明只是简单的说明,具体还得查看man手册
Linux文件说明
linux下一切皆是文件。
Linux 下的文件类型:
学习内容
man 手册如何查询:
例如查看open()这个函数在哪一本man手册
1 $man - f open // 通过 man -f 来查询 open 出现在哪些手册中2 open ( 1 ) - start a program on a new virtual terminal ( VT ).3 open ( 2 ) - open and possibly create a file
man手册说明
1 Executable programs or shell commands ->第一本是命令手册
2 System calls (functions provided by the kernel)->第二本是系统函数手册
3 Library calls (functions within program libraries)->第三本是程序库函数手册
4 Special files (usually found in /dev)
5 File formats and conventions, e.g. /etc/passwd
6 Games
7 Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7), man-pages(7)
8 System administration commands (usually only for root)
9 Kernel routines [Non standard]
man 2 open
系统IO 函数学习
打开文件
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 以可读写方式打开文件 .上述三种旗标是互斥的 , 也就是不可同时使用 , 但可与下列的旗标利用 OR ( | ) 运算符组合 .O_CREAT 若欲打开的文件不存在则自动建立该文件 .O_EXCL 如果 O_CREAT 也被设置 , 此指令会去检查文件是否存在 . 文件若不存在则建立该文件 , 否则将导致打开文件错误。此外,若 O_CREAT与O_EXCL同时设置,并且将要 打开的文件为符号连接,则将导致打开文件失败O_NOCTTY 如果欲打开的文件为终端机设备时 , 则不会将该终端机当成进程控制终端机 . O_TRUNC 若文件存在并且以可写的方式打开时 , 此旗标会令文件长度清为 0 , 而原来存于该文件的资料将被清除。 O_APPEND 当读写文件时会从文件尾开始移动 , 也就是所写入的数据会以附加的方式加入到文件后面。 O_NONBLOCK 以非阻塞方式打开文件,即使无法立即进行读写操作也不会被阻塞。O_NDELAY 同 O_NONBLOCK .O_SYNC 以同步的方式打开文件 .O_NOFOLLOW 如果参数 pathname 所指的文件为一符号连接 , 则会令打开文件失败 . O_DIRECTORY 如果参数 pathname 所指的文件并非为一目录 , 则会令打开文件失败 .mode --> 文件的初始化权限(只有在创建新文件的时候生效)返回值:成功返回一个新的文件描述符 ( new file descriptor )int --> 整型 --> 编号 --> 该文件在本进程中的编号失败返回 - 1 , 错误号码会被设置
代码例子
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>int main1()
{int FD = open("abc.c", O_RDONLY);//以只读的形式打开abc.c,如果abc.c不在当前目录下就报错if(-1 ==FD){//int fprintf(FILE *stream, const char *format, ...)//stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。//format -- 这是 C 字符串,包含了要被写入到流 stream 中的文本。//它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。// errno 是 C 标准库中的一个宏,定义在 <errno.h> 头文件中。它用于指示在程序运行过程中发生的错误。//errno 实际上是一个整数变量,用于存储错误代码。库函数在发生错误时,会设置 errno 为适当的错误代码,以便程序可以检查和处理这些错误。//C 库函数 char *strerror(int errnum) 从内部数组中搜索错误号 errnum,并返回一个指向错误消息字符串的指针。//strerror 生成的错误字符串取决于开发平台和编译器。fprintf(stderr,"open abc.c error:%s\n",strerror(errno));exit(-1);}else{printf("open abc.c success , file_number:%d",FD);}
}int main()
{int FD = open("abc.c", O_RDONLY|O_CREAT,0666);//以只读的形式打开abc.c,如果当前目录下没有abc.c则创建abc.c文件文件权限为0666if(-1 ==FD){fprintf(stderr,"open abc.c error:%s\n",strerror(errno));exit(-1);}else{printf("open abc.c success , file_number:%d",FD);}
}
运行结果
main1()
jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ touch abc.c
jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ gcc open.c
jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ ./a.out
open abc.c success , file_number:3jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ rm abc.c
main()
open abc.c success , file_number:3jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ rm abc.c
jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ gcc open.c
jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ ./a.out
open abc.c success , file_number:3jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$
注意
如果程序是以只读的权限打开时出现以下错误:
注意umask:
如果我们在使用Open 来创建文件时, 文件的权限值会受到umask的影响实际的权限值为设置 - umask (0666 - 0022 = 0644)一般情况下系统默认设置为 0002
写入文件
1 头文件:2 #include < unistd . h >34 定义函数:5 ssize_t write ( int fd , const void * buf , size_t count );6 ssize_t read ( int fd , void * buf , size_t count );7 参数分析:8 fd --> 需要写入的文件的描述符9 buf --> 需要写入的数据所在的内存地址10 count --> 需要写入的字节数1 2 返回值:13 返回实际写入的字节数 .14 当有错误发生时则返回 - 1 , 错误代码存入 errno 中
注意
如果文件以只读的形式打开那么就不能向文件写入内容否则系统会直接报错
测试
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define OpenfilePath "./tag.txt"
int main(int argc, char const *argv[])
{
int FD = open(OpenfilePath,O_WRONLY| O_CREAT| O_TRUNC,0666);//打开,创建,清0、tag.txt
if(-1 ==FD)
{
fprintf(stderr,"open abc.c error:%s\n",strerror(errno));
exit(-1);
}
else
{
printf("open abc.c success , file_number:%d",FD);
}
int flag_value = -1;
flag_value = write(FD,"hello work",sizeof("hello work"));
if(-1 == flag_value)
{
perror("写入文件失败\n");
}
else
{
printf("写入%d个字节\n",flag_value);
}
close(FD);
return 0;
}
读取文件
头文件:2 #include < unistd . h >34 定义函数:5 ssize_t read ( int fd , void * buf , size_t count );67 参数分析:8 fd --> 需要读取的文件的描述符9 buf --> 读取到的数据存放的位置(用户的缓冲区)10 count --> 需要读取的字节数1112 返回值:13 成功 返回实际读到的字节数(如果返回值比count 小,则有可能到大文件的末尾)14 错误 发生时则返回 - 1 , 错误代码存入 errno 中
测试
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <unistd.h>#define OpenfilePath "./tag.txt"int main(int argc, char const *argv[]) {int FD = open(OpenfilePath,O_RDONLY);//打开,创建,清0、tag.txtif(-1 ==FD){fprintf(stderr,"open abc.c error:%s\n",strerror(errno));exit(-1);}else{printf("open abc.c success , file_number:%d\n",FD);}long flag_value = -1;flag_value = lseek(FD, 1, SEEK_SET);printf("偏移了%ld个字节\n",flag_value);flag_value = -1;char buffer[128];bzero(buffer, sizeof(buffer) ); // 清空内存区flag_value = read(FD, buffer, sizeof(buffer));if(-1 == flag_value){perror("读取文件失败\n");}else{printf("读取成功,读取到%ld个字节\n读取的内容%s\n",flag_value,buffer);}close(FD);return 0; }
经过测试如果读取不设置偏移量,默认从文件起始位置开始读取。
移动文件的读写位置
1 头文件:2 #include < sys / types . h >3 #include < unistd . h >45 定义函数 :6 off_t lseek ( int fildes , off_t offset , int whence );78 参数分析:9 fildes --> 需要移动读写位置的文件的描述符10 offset --> 偏移量设置11 whence --> 偏移的模式12 SEEK_SET 参数 offset 即为新的读写位置 .13 SEEK_CUR 以目前的读写位置往后增加 offset 个位移量 .14 SEEK_END 将读写位置指向文件尾后再增加 offset 个位移量 .15 当 whence 值为 SEEK_CUR 或 SEEK_END 时 , 参数 offet 允许负值的出现 .1617 返回值:18 成功时则返回目前的读写位置 , 也就是距离文件开头多少个字节 .19 若有错误则返回 - 1 , errno 会存放错误代码
关闭文件
1 头文件:2 #include < unistd . h >34 定义函数:5 int close ( int fd );67 参数看看:8 fd --> 需要关闭的文件的描述符910 返回值:11 若文件顺利关闭则返回 0 ,12 发生错误时返回 - 1.
复制文件
1 cp 1. c abc . c2 . / a . out 1. c abc . c
思路:
linux系统的栈空间有8MB,如果要复制一个超过8MB的文件我们就不能直接定义一个超过8MB的数组来存放我们读取的内容。就好比抄作业不能一次性把别人的作业全记住在往自己的本子上写。我们需要在堆中开辟一个小空间来作为我们的缓存,一点一点的复制。
int main(int argc, char const *argv[])这是一个标准的main函数argc使我们调用参数的个数,这些参数会保存在argv[]这个数组里。
实现:
以程序的方式进行复制
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>#define TrgPath "./abc.c"
#define SrcPath "./open.c"int main(int argc, char const *argv[])
{//打开文件int SrcPathFD = open(SrcPath,O_RDONLY );//打开,创建,清0、tag.txtif(-1 ==SrcPathFD){fprintf(stderr,"open SrcPath error:%s\n",strerror(errno));close(SrcPathFD);exit(-1);}//int TrgPathFD = open(TrgPath,O_WRONLY|O_CREAT|O_TRUNC,0666);//打开,创建,清0、tag.txtint TrgPathFD = open(TrgPath,O_WRONLY| O_CREAT | O_TRUNC , 0666);//打开,创建,清0、tag.txtif(-1 ==TrgPathFD){fprintf(stderr,"open TrgPath:%s\n",strerror(errno));close(TrgPathFD);exit(-1);}//建立缓冲区char *bufferaddr = (char *)calloc(1,128);if(NULL == bufferaddr){printf("堆空间不足");return -1;}//复制内容//复制结束的条件读到的字节个数小于128那就说明读完了long flag_value = -1;do{flag_value = read(SrcPathFD, bufferaddr, 128);//不能sizeof(bufferaddr)if(-1 == flag_value){perror("读取文件失败\n");break;}else{printf("读取成功,读取到%ld个字节\n",flag_value);}flag_value = write(TrgPathFD,bufferaddr,flag_value);if(-1 == flag_value){perror("写入文件失败\n");break;}else{printf("写入%ld个字节\n",flag_value);}}while(flag_value >= 128);close(SrcPathFD);close(TrgPathFD);return 0;
}
以命令的方式进行
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <stdlib.h> #include <unistd.h>int main(int argc, char const *argv[]) {if(argc != 3){printf("请输入正确的参数\n");return -1;}//打开文件int SrcPathFD = open(argv[0],O_RDONLY );//打开,创建,清0、tag.txtif(-1 ==SrcPathFD){fprintf(stderr,"open SrcPath error:%s\n",strerror(errno));close(SrcPathFD);exit(-1);}int TrgPathFD = open(argv[1],O_WRONLY| O_CREAT | O_TRUNC , 0666);//打开,创建,清0、tag.txtif(-1 ==TrgPathFD){fprintf(stderr,"open TrgPath:%s\n",strerror(errno));close(TrgPathFD);exit(-1);}//建立缓冲区char *bufferaddr = (char *)calloc(1,argv[3]);if(NULL == bufferaddr){printf("堆空间不足");return -1;}//复制内容//复制结束的条件读到的字节个数小于128那就说明读完了long flag_value = -1;do{flag_value = read(SrcPathFD, bufferaddr, argv[3]);//不能sizeof(bufferaddr)if(-1 == flag_value){perror("读取文件失败\n");break;}else{printf("读取成功,读取到%ld个字节\n",flag_value);}flag_value = write(TrgPathFD,bufferaddr,flag_value);if(-1 == flag_value){perror("写入文件失败\n");break;}else{printf("写入%ld个字节\n",flag_value);}}while(flag_value >= argv[3]);close(SrcPathFD);close(TrgPathFD);return 0; }
jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ gcc copy.c jiejie@DESKTOP-1HU808H:/mnt/e/Shared_WSL/我的程序/文件IO/系统IO$ ./a.out ./open.c ./abc.c 128 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到128个字节 写入128个字节 读取成功,读取到13个字节 写入13个字节
两种运行方式效果完全相同,命令的方式可以让我们很好的利用这个程序达到我们复制文件的效果。命令的方式可以设置复制文件的格式名称。