Linux下文件IO-基础
一. 标准IO的介绍
1、文件类型
(1)常规文件 r
(2)目录文件 d
(3)字符设备文件 c
(4)块设备文件 b
(5)管道文件
(6)套接字文件
(7)符号链接文件
不同的操作系统,支持的文件类型也不相同。
2、标准IO的定义
由ANSI C标准定义一组函数API,通过缓存机制减少系统调用,实现更高效率。
系统调用:
有操作系统情况下,访问硬件,必须通过系统调用。
缓冲机制:
标准IO通过缓存机制,减少系统调用,实现更高效率
3、标准-流
(1)FILE:标准IO用结构体类型来存放打开的文件的相关信息.
标准IO的所有操作都是围绕FILE来进行。
FILE又被称为流(stream)
分为文本流和二进制流
(2)流的缓冲类型
全缓冲:缓存区满或空的时候,才执行操作
行缓存:当输入输出时,遇到换行符(‘\n’),进行IO操作
无缓冲:数据直接写入文件
(3)标准IO预定义三个流
标准输入流:stdin
标准输出流:stdout
标准错误流:stderr
二、 流的打开与关闭
1、打开流
FILE *fopen (const char *path,const char *mode);
成功时返回流指针,错误返回NULL。
2、流的打开方式(r文本流,b二进制流,linux不区别)
(1) r或rb:以只读的方式打开文件,文件必须存在。
(2) r+或r+b:以读写的方式打开文件,文件必须存在
(3) w或wb:以只写的方式打开,文件存在长度清零,不存在创建
(4) w+或w+b:以读写的方式打开,其他同w
(5) a或ab:以只写的方式打开,在文件末尾追加,文件不存在创建
(6) a+或a+b:以读写的方式打开,其他同a
3、fopen新建文件权限
fopen()创建文件默认 访问权限0666(rw-rw-rw-),受系统掩码影响最终权限是644
4、处理错误信息的函数
errno存放错号
perror先输出字符串s ,在输出错误号对应的错误信息
strerror根据错误号返货对应的错误信息
5、关闭流
int fclose(FILE*stream);
fclose()调用成功返回0,失败返回EOF,并设置errno
三、读写流
1、流的读写方式
(1) 读写一个字符:fgetc()/fputc一次读写一个字符
(2) 读写一行:fgets()/fputs一次读写一行
(3) 读写若干个对象:fread()/fwrite()每次读写相同长度的若干个对象。(推荐)
2、注意事项
(1)fgetc读到文件末尾时,返回EOF (-1)
(2)fgets 成功返回s,到文件末尾或出错,返回NULL
fgets(char *s ,int size, FILE *stream )
遇到‘\n’,或读size-1个字符返回,最后追加\0,
(3)fputs 格式:int futs (const char *s,FILE *stream);
成功时返回输出字符个数,出错时返回EOF
put输出结果最后追加换行符,fputs不追加
3、按指定对象读写
(1)
size_t fread(void *ptr, size_t size, size_ n, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_ n, FILE *fp);
*ptr 存放的缓冲区的地址 size 读写的字符的长度 n读写个数
FILE 流的地址
成功时返回读写的对象的个数;出错时返回EOF
既可以读写文本文件,也可以读写数据文件
4、fgetc()/fputc:可以操作文本文件和数据文件,效率低
fgets()/fputs:只可以操作文本文件,效率较高
fread()/fwrite:可以操作文本文件和数据文件,效率也很高(推荐)
四. 刷新流
1、流缓冲区的自动刷新
(1) 缓存区满时,或者出现换行符‘\n’
(2) 流关闭时
(3) 使用fflush函数
2、int fflush(FILE *fp)
(1)成功时返回0,错误返回EOF
(2)将流缓冲区的数据写入实际文件
(3)Linux下只能刷新输出缓冲区
五.定位流
1、
long ftell(FILE *stream);
long fseek(FILE *stream, long offset, int whence);
void rewind(FILE *stream);
2、注意
(1)ftell()成功时返回流的当前读写位置,出错返回EOF。
(2)fseek()定位流,设定流当前读写位置。成功返回0,出错返回EOF
whence参数:SEET_SET/SEEK_CUR/SEEK_END 文件开始位置/文件当前位置/文件结束为止
offset 偏移量,可正可负
(4) rewind()将流定位到文件的开始位置
(5) 读写流时,当前读写位置自动后移
五. 判断流是否出错和结束
1、int ferror(FILE *stream);检测流是否出错
int feof(FILE *STREAM);检测流是否到末尾
2、ferror()返回1,表示流出错;否则返回0
feof()返回1表示文件已经到末尾;否则返回0
六. 格式化输出
1、int printf(const char *fmt,…);
int fprintf(FILE *stream,const char *fmt,…);输出到指定流里
int sprint(char *s, const *fmt, …);输出到缓存区里
成功时返回字符个数;出错时返回EOF
例:输出年-月-日
fprintf( fp, “%d-%d-%d\n”, year, month, date);
sprintf( buf, “%d-%d-%d\n”, year, month, date);
2、time()用来获取系统时间(秒数)
localtime()将系统时间转换成本地时间
sleep()实现程序睡眠
七、 文件IO
1、标准IO:遵循ANSI C标准,带缓冲机制,通过流FILE表示,
文件IO:遵循POSIX规范,无缓冲机制,文件描述符表示。可访问各种文件类型
Linux,标准IO基于文件IO实现
2、文件描述符:一个非负整数。Linux为程序中打开的文件分配一个文件描述符。
从零开始,依次递增。每个程序文件描述符独立。
文件IO操作通过文件描述符来完成。
0,1,2:表示标准输入/输出/错误
3、文件的打开
(1) int open(const char *path, int oflag, …);
(2) 成功时返回文件描述符,出错时返回·EOF,打开使用两个参数,
(3) 只能打开设备文件,
4、文件的关闭
(1) int close(int fd)
(2) 成功返回0,出错EOF
(3) 程序结束时自动关闭所有打开的文件
(4) 文件关闭后,文件描述符不再代表文件
5、读写文件
(1)#include<unistd.h>
ssize_t read(int fd, void *buf, size_t count);
(2)功时返回实际读取字节数;出错时返回EOF
(3)读到末尾时返回0
(4) count值一般不超过buf
(5) 写入文件 ssize_t write(int fd, void *buf, size_t count);
(6) 用法与read一致
6、文件定位
(1) off_t lseek(int fd, off_offset, intt whence);
(2) 成功返回当前文件读写位置,出错返回EOF
(3) 参数用法与fseek完全一样
7、读取目录
(1) 打开文件目录
#include<dirent.h>
DIR *opendir(const char *name);
(2) DIR用来描述一个打开的目录的结构体类型
(3) 成功时返回目录流指针,出错返回NULL
(4) 读取目录流的内容
#include<dirent.h>
struct dirent *readdir(DIR *dirp)
(5) struct dirent描述目录流中的一个目录项的结构体类型
(6) 包含成员插入d_name[256]
(7) 成功时返回目录流dirp中下一个目录项
(8) 出错或到末尾时返回NULL
8、关闭目录
(1) #include<DIR *dirp>
(2) int closedir(DIR *dirp);
9、修改文件访问权限
(1)#include<sys/stat.h>
int chmod(const char *path, mode_t mode);通过路径
int fchmod(int fd, mode_t mode);通过文件描述符
(3) 成功时返回0,出错时返回EOF
(4) root和文件所有者能修改文件访问权限
(5) 示例:chmod(“test.txt”, 0666);
10、获取文件属性
(1) #include<sys/star.h>
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstat(int fd, strct stat *buf);
(2)成功时返回0,失败返回EOF
(3)mode_t st_mode;类型和访问权限
uid_t st_uid:所有者id
uid_t st-gid:用户组id
off_t st_size: 文件大小
time_t st_mtime:最后修改时间
八、库概念
1、库是一个二进制文件,包含的代码可被调用
分为标准c库、数学库、线程库
库有源码,可下载编译,也可直接安装二进制包
存放路径在/lib 或/usr/lib
2、Linux下包含静态库和共享库
3、静态库
(1)编译链接时把静态库相关代码复制到可执行文件中
(2)程序中已包含代码,运行时不再需要静态库
程序运行性无需加载库,运行速度更快
占用更多的磁盘和内存空间
静态库升级后,程序要重新编译·
4、静态库的创建
(1)确定库中的函数的功能、接口
(2)编写库原码 hello.c
(3)编译生成目标文件 gcc -c hello.c -Wall
(4)创建静态库 arcrs libhello.a hello.o
(5)查看库中符号信息 nm libhello.a
(6)编写应用程序 test.c
(7)编译test.c 并链接静态库libhello.a
gcc -o test test.c -L. -lhello
八、 共享库
1、共享库特点:编译链接时仅记录了用到共享库哪些符号,不复制共享库中的相关代码。
(1) 程序不包含库中代码,尺寸小
(2) 多个程序可以共享一个库
(3) 程序运行时需要加载库
(4) 库升级方便,无需重新编译链接
2、 共享库的创建
(1)确定共享库中函数的功能、接口
(2)编写库原码hello.c
(3)编译生成目标文件 gcc -c -fPIC hello.c bye.c -Wall
(4)创建共享库common
(5)gcc -shared -o libcommon.so.1 hello.o bye.o (1:版本号)
(6)为共享库文件创建链接文件
In -s libcommon.so.1 libcommon.so
(7)符号链接文件命名规则 lib<库名>.so
(8)编写库的头文件。在库文件中把所有函数声明一下
(9)编写应用程序并编译 test.c
gcc -o test test.c -L. -lcommon
3、如何找到共享库
(1)把库拷贝到/usr/lib和/lib目录下
(2)在LD_LIBRARY_PATH环境变量中添加库所在路径
(3)添加/etc/ld.so.conf.d/*.conf文件,执行ldconfig刷新