LinuxC语言文件i/o笔记(第十八天)
文件i/o
标准i/o的特点是,其使用ANSI C标准(即标准c语言),文件i/o为POSI X标准(系统文件规范),前者带有缓冲区,为流——FILE,后者不带缓冲区,为文件描述符——fcl。
在linux下,标准i/o是基于文件i/o实现的。
使用的头文件为<unistd.h>
文件描述符:
每个打开的文件都对应一个文件描述符,
其不为负,linux系统里每打开一个文件都会自动分配一个文件符。
文件i/o通过文件描述符对文件进行操作(标准i/o的输入输出流)。
文件打开:
使用函数open:
int open(const char *path,int oflag,...);
第一个参数为文件名称(地址),第二个为打开的参数(后续讲),第三个就是文件若要建立的权限(使用8进制描述)。
成功返回文件描述符,失败返回EOF。
oflag的参数:
与标准i/o相似,也有只读读写什么的:
O_ RDONLY:只读方式打开文件。
O_ WRONLY:可写方式打开文件。
O_ RDWR:读写方式打开文件。
O_CREAT:如果该文件不存在,就创建一个新的文件, 并用第三的参数为其设置权限。
O_EXCL: 如果使用O_ CREAT时文件存在,则可返回错误消息。这一参数可测试文件是否存在
O_NOCTTY:使用本参数时,如文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端。
O_TRUNC:如文件已经存在,那么打开文件时先删除文件中原有数据。
O_APPEND:以添加方式打开文件,所以对文件的写操作都在文件的末尾进行。
也可以选择多个参数,如我想实现如果只读一个文件,有就清空,无则新建,权限为0666:
O_ RDONLY|O_CREAT|O_TRUNC
整个函数为
fd = open("1.txt",O_ RDONLY|O_CREAT|O_TRUNC,0666);
文件的关闭:
int close(int fd);
fd为该文件的文件描述符。
成功返回0,出错返回EOF。
程序结束会自动关闭所以文件。
文件读取:
使用read函数:
ssize_t read(int fd,void *buf,size_t count);
和标准i/o按对象输入差不多,fd为文件描述符,第二个参数为缓冲区,用于存储读取的数据,第三个是要读取的数量。
成功会返回读取的实际个数,失败返回EOF。
都到末尾会返回0。
文件写入:
ssize_t write(int fd,void *buf,size_t count);
和read大致一致。
成功返回实际写入的数量,出错返回EOF。
文件的定位:
off_t lseek(int fd,off_t offset,intt whence);
成功返回当前文件读取的位置,参数与标准i/o一致。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#define N 64
int main(int argc,char *argv[]){int fds,fdt,n;char buf[N];if(argc < 3){printf("Usage : %s <sre_file> <dst_file>\n",argv[0]);return -1;}if((fds = open(argv[1],O_RDONLY)) == -1){fprintf(stderr,"open %s : %s\n",argv[1],strerror(errno));return -1;}if((fdt = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666)) == -1){fprintf(stderr,"open %s : %s\n",argv[2],strerror(errno));return -1;}while((n = read(fds,buf,N)) > 0){write(fdt,buf,N);}close(fds);close(fdt);return 0;
}
库:
我们写程序的时候会用到头文件,也叫什么什么库,但是在编程过程中,如果想调用其他程序的函数,不一定要使用头文件的引用的方式,还有静态库和动态库。
静态库:
静态库是一个二进制文件,包含的代码可以被程序调用。
编译链接的时候,程序会把用得到的相关代码复制到可执行文件中,可执行程序就含有了此代码,后续运行使用都不再需要源文件,但是会占用更大的磁盘和内存。若静态库升级,还需要重新编译链接代码。
静态库程序和标准程序类似,但可以不存在int main函数,但是要有main函数。
在写完之后,原本是使用gcc -o test test.c生成可执行程序,改为 gcc -c test.c 生成二进制中间文件test.o。
再输入ar crs 静态库名称 .o文件 创建静态库,其中静态库名称由三部分组成1、lib,2、库名称,3、.a后缀,上述文件就是 ar crs libtest.a test.o。
编辑好主程序后,正在编译过程链接静态库:
gcc -o main main.c -L. -ltest
其中.c文件后面的 -L.为静态库路径,单个.表示当前目录,后续-l加库名称。
就可以实现链接啦。
动态库:
动态库是可执行文件在执行的时候才调用需要的代码模块的,多个程序可共享该库,但运行程序的时候需要源文件,否侧会报错,但升级方便,无需重新编译主程序。
动态库和静态库程序一样,但编译的时候不同:
gcc -c -fPLC test.c
才能生成动态库的二进制文件,然后建立共享库:
gcc -shared -o libcommon.so.1 test.0
其中-shared为关键字,libcommon.so.1为共享库名称,其中包括lib是固定格式,common为库名称,.so为共享库后缀,至于后面的.1是为方便管理版本什么的进行标记的。
然后还有创建关系链接:
ln -s libcommon.so.1 libcommon.so
这个就不可以有数字了
然后就是和主程序连接
gcc -o main mian.c -L. -lcommon
就可以啦。
库和头文件的对比:
| 特点 | 静态库 | 共享库 | 头文件库 |
|---|---|---|---|
| 文件大小 | 大(代码嵌入可执行文件) | 小(代码在共享库中) | 大(代码嵌入可执行文件) |
| 编译方式 | 编译时链接 | 运行时链接 | 编译时包含 |
| 运行依赖 | 无 | 需要共享库文件 | 无 |
| 更新难度 | 难(需重新编译程序) | 易(只需替换共享库文件) | 易(需重新编译程序) |
| 适用场景 | 小型项目、启动速度快 | 大型项目、更新频繁 | 小型库、模板库 |
