目录
前言
学习IO的课堂笔记
一、文件概念
文件:一组相关文件的有序集合(视频,音频)
文件名:这个数据集合的名字
二、文件类型
-:普通文件
a、ASCII码文件(文本文件) b、二进制文件(图片、视频)
d:目录文件
i:链接文件
b:块设备文件
c:字符设备文件
p:管道文件
s:套接字文件
三、标准IO
特点:
1.可以在Windows和Linux中使用(跨平台)
2.标准I/O库由ANSI C标准说明
3.有缓冲机制(仅标准IO有)
4.通过文件流指针(FILE *)来操作
3.1 系统调用
系统:操作系统 调用:调用函数
系统调用:操作系统提供给应用程序的接口(函数)
3.2 缓冲区
作用:IO通过缓冲区减少系统调用的次数
全缓存:当缓冲区满,或者强制刷新缓冲区时,
行缓存:当缓冲区满,程序运行结束,强制刷新,或者遇到换行符等情况下,会刷新缓冲区
不缓存:当程序运行起来后,有三个文件已经默认打开,标准输入,标准输出,标准出错;它们对应的流指针分别为:stdin、stdout、stderr
3.3 FILE指针和流
FILE指针
每个被使用的文件都在内存中开辟一个区域,用来存放文件的有关信息,这些信息是保存在一个结构体类型的变量中,该结构体类型是由系统定义的,取名为FILE;
标准I/O库的操作都是围绕流(strea),在标准IO中所有操作都是由FILE*来进行的
流(stream)
字节的进进出出;
注意:只有标准IO有流的概念。
1. 文本流:‘2’,‘0’,‘0’,‘1’——>50,48,48,49
2. 二进制流:2001——>00000111 11010001
3.4 标准IO相关函数
文件操作步骤
打开文件(open)
FILE *fopen(const char *pathname, const char *mode);
函数功能:打开文件
参数1:要打开的文件路径;
参数2:打开方式
r(rb):以只读方式打开文件,文件不存在则出错
r+(r+b):以可读可写的方式打开文件,文件不存在则出错
w(wb):以只写的方式打开文件,文件存在则清空文件内容后写入,文件不存在则新建写入
w+(wb+或w+b):以可读可写的方式打开文件,文件存在则清空文件内容后写入,文件不存在则新建写入
a(ab):以追加的方式打开只写文件,文件存在则追加到文件末尾,文件不存在则新建
a+(a+b或ab+):以可读可写的方式打开文件,文件存在则追加到文件末尾,文件不存在则新建
返回值:成功返回文件流指针(FILE *类型);失败返回
操作文件(读/写)
按字符读:
getchar()从键盘输入
fgetc():int fgetc(FILE *stream),既可以从键盘输入,也可以从文件中读取
函数功能:从指定的流中读取一个字符
参数:fopen的返回值,已经打开的文件流指针
返回值:成功返回读到的ASCII码值,读到文件末尾或失败返回-1
按字符写:
putchar()
fputc():int fgetc(int c,FILE *stream)
函数功能:从指定的流中输出一个字符
参数:fopen的返回值,已经打开的文件流指针
参数1:要输出的字符
参数2:文件流指针
返回值:成功返回写入的ASCII码值,失败返回-1
int feof(FILE *stream)
函数功能:判断文件是否达到文件末尾
参数:要操作的流指针
返回值:如果非0表示到达文件末尾,为0则表示没有到达文件末尾
注意:feof既可以文本文件是否到达文件末尾,又可以判断二进制文件是否到达文件末尾
按行读写:
gets()、fgets()
char *fgetc(char *s,int size,FILE *stream)
函数功能:从指定流中读取字符串
参数1:保存读取到的内容的首地址
参数2:空间的大小
参数3:要操作的文件流指针
返回值:成功返回读取到的内容的首地址,失败返回NULL
注意:fgets最多读取size-1个字符,并且会将换行符也读取进去
int *fputs(conse char *s,FILE *stream)
函数功能:从指定流中输出字符串
参数1:要输出的内容的首地址
参数2:要操作的文件流指针
返回值
总结区别:
fgets和gets
1.fgets比gets更安全
2.fgets会读取换行符,gets不会
按块读写
读:
size_t fread(void *ptr,size_t size,size_t nmemb,FILE *stream)
功能:按块读取内容
参数1:读取内容的空间首地址
参数2:块的大小
参数3:块的个数
参数4:要操作的文件流指针
返回值:成功返回读到的块数,失败返回-1
案例:读取100字节,块大小20,读取5次
注意:不足1块时,按0处理;
一般情况下size设置成1,返回值就是读到的字节数
写:
size_t fwrite(conse void *ptr,size_t size,size_t nmemb,FILE *stream)
函数功能:向指定流中写入数据
参数1:要写入空间的首地址
参数2:块的大小
参数3:块的个数
参数4:要操作的文件流指针
返回值:成功返回写入的块数,失败返回-1
关闭文件(fclose)
int fclose(FILE *stream);
参数:文件流指针,fopen的返回值
返回值:成功返回0,失败返回-1(EOF)
注意:EOF只能判断是否到达文本文件末尾,不能判断是否到达二进制文件末尾
frell
long ftell(FILE * steam)
函数参数:获取文件当前违章
参数:要操作的文件流指针
返回值:返回文件当前指示
fseek
参数1:要操作的流指针
参数2:偏移量
参数3:偏移的位置
SEEK_SET:文件开头
SEEK_CUR:文件当前位置
SEEK_END:文件末尾
案例:fseek(fp,0,SEEK_SET)//文件开头
四、文件IO
4.1 文件IO
特点:
1.是POSIX(可移植操作系统)定义的一组函数
2.不带缓冲,每次执行都是系统调用
3.文件描述符(非负的整数)
4.大多用于设备文件的操作
4.2 相关函数
1、打开文件
头文件:#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int open(conse char *pathname,int flags)
int open(conse char *pathname,int flags,mode_t mode)
参数1:文件路径
参数2:打开方式,以下三个必选其一:
O_RDONLY O_WRONLY O_RDWR
其余的,和上面进行或运算
O_CREAT:如果文件不存在,则新建(必须使用第三个参数)
O_EXCL:如果新建文件时文件存在则报错
O_NOCTTY:如果文件为终端,那么终端不可以作为调用open()系统调用的那个进程的控制终端
O_TRUNC:如果文件已经存在,那么打开文件时先删除文件中原有数据
O_APPEND:以追加的方式打开文件,如果文件存在,则追加在文件的末尾
参数3:文件的权限一般用8进制数据表示
返回值:成功返回已经打开的文件描述符,失败返回-1
2、关闭文件
头文件: #include<unistd.h>
int close(int fd);
参数:已经打开的文件描述符
返回值:成功返回0,失败返回-1
文件掩码:
777
111 111 111
文件掩码 000 000 010 取反:&111 111 101
两者进行与运算:111 111 101 (775)
案例:测试操作系统。最多同时打开多少文件
默认打开的三个文件:stdin,stdout ,stderr
3、操作文件
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数 1:文件描述符
参数2:读到内容空间的首地址
参数3:要读的字节数
返回值:成功返回读到的字节数,为0表示到达文件末尾,失败返回-1
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数1:文件描述符
参数2:要写入的内容的空间的首地址
参数3:要写的字节数
返回值:成功返回写入的字节数,失败返回-1
lseek
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
参数1:文件描述符
参数2:偏移量
参数3:偏移位置
创建空洞文件
1、以读写的方式打开文件
2、从文件开头向后偏移1G
3、在文件末尾添加"\0"
4、关闭文件
五、操作目录
1、打开目录
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
参数:打开的路径
返回值:成功返回DIR *,失败返回NULL
2、读目录
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
返回值:成功返回struct dirent*结构体指针,,读到文件末尾或者失败返回NULL
3、关闭目录
#include <dirent.h>
int closedir(DIR *dirp);
参数:opendir的返回值
返回值:成功返回0,失败返回-1
案例:实现 ls
六、静态库和动态库
库:库是一个二进制文件,包含的代码可以被程序调用
静态库特点:
1、编译时将静态库中相关代码复制到可执行文件中
2、程序运行时无须加载库,运行速度块
3、占用更多的磁盘和内存空间,静态库升级后程序需要重新编译(库升级不方便)
创建静态库:
1、编写源代码
2、将源代码生成对应的.o文件
3、静态库的命名规范:lib.库名.a
ar:库文件维护程序的名称
c:创建一个库,不管库是否存在,都将创建
r:在库中创建模板
s:创建目标文件索引,在创建较大库的时候能加快时间
4、链接一个静态库
注意:-L . 指的是是当前文件,
5、运行
动态库特点:
1、编译时仅记录使用了哪个共享库(动态库)中的哪个函数,不复制共享库的相关代码,运行时加载共享库
2、程序不包含共享库中的代码,代码尺寸小
3、库升级方便,无须重新编译程序
4、使用最广泛的是共享库(动态库)
创建动态库:
1、编写源代码
2、将源代码生成对应的.o文件
-fPIC 生成与位置无关代码,可以在任意位置运行
3、共享库的命名规范:libxxx.so.版本号(一般数字表示)
4、-shared:生成动态链接库
5、给共享库创建软链接
创建软链接是为了能让编译器在编译的时候能找到共享库
6、编译
7、运行
如上图所示,找不到共享库
8、将共享库复制到系统库路径下
/usr/lib
9、运行
可执行文件