IO学习总结
什么是IO
input、output输入输出
1、 在Linux中一切皆文件,文件有以下几个分类
d:目录文件
-:普通文件
c:字符设备文件
b:块设备文件
l:链接文件
p:管道文件
s:套接字文件
2、IO的分类
2.1 、按存储类型分
**文本文件:**存储的是ASCII码(0~127),以EOF End Of File (-1)作为结束符。
一般存储数据量比较大的信息,读取的速度慢
**二进制文件:**是数据在内存上的原样存储,存储的是二进制的形式。
一般存储中间变量,数据量比较小的信息,读取的速度快。
2.2 、按操作方式分
带缓冲区的操作:(标准IO)高级的文件操作,系统会自动的在内存上给我们分配缓冲区。
不带缓冲区的操作:(文件IO)低级的文件操作,系统是不会自动的给我们的程序分配空间,但是如果需要
缓冲区的机制,缓冲区就得自己定义了。
3、标准IO和文件IO
3.1、区别
标准IO: 文件IO:
1.标准IO是由库函数系统提供的,由ANSI C标准定义 1.文件IO是由操作系统提供的,由POSIX(可移植操作系统接口)定义
2.是带缓冲区的操作,运行效率较高 2.没有缓冲区,运行效率没有标准IO高
3.支持跨平台的 3.不支持跨平台的
4.标准IO操作的依据一般是流指针 4.文件IO操作的依据一般是文件描述符(非负整数)
4、系统调用和库函数
**系统调用:**操作系统提供给用户直接操作硬件的一组接口
**库函数:**对系统调用的二次封装
4.2、系统调用和库函数的区别
1.系统调用一般提供基础的功能,库函数提供较为复杂的功能
2.系统调用一般不能重写,库函数可以重写
3.系统调用运行的时间属于机器时间,库函数运行时间属于用户时间
4.系统调用运行空间属于内核空间,库函数运行空间属于用户空间
5.系统调用的返回值一般是非负整数,库函数的返回值不一定
6.系统调用的运行效率没有库函数的高
7.系统调用的移植性没库函数的好
5、文件描述符
5.1、文件流指针
标准IO的核心对象就是流,用标准IO打开一个文件时就会创建一个FILE结构体描述该文件,我们把这个FILE结构体形象的称为流
5.2、文件描述符
是一个非负整数,本质时数组下标
6、标准IO
6.1、缓冲区的方式
6.1.1、全缓冲:
缓冲区满了才刷新缓冲区,或者强制刷新缓冲区(fflush(stdout))
6.1.2、行缓冲:
碰到换行符刷新缓冲区、缓冲区满了刷新、或者强制刷新缓冲区,例如\n
6.1.3、不缓冲:
所有的信息到缓冲区之后直接到文件
6.2、对文件进行操作
6.2.1、打开文件
fopen:
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
函数功能:打开由参数1描述的文件,打开的方式由参数2确定
函数参数1:需要被打开的文件的路径
函数参数2:打开的方式
r : 以只读的形式打开文件,文件存在则打开,不存在则报错
r+ : 以读、写的形式打开文件,文件存在则打开,不存在则报错
w : 以只写的形式打开文件,文件存在则清空打开,文件不存在则新建
w+ : 以读、写的形式打开文件,文件存在则清空打开,文件不存在则新建
a : 以追加的形式打开文件,文件存在则追加,文件不存在则新建
a+ : 以可读可写(追加)的形式打开文件,文件存在则追加,文件不存在则新建
函数返回值:成功返回:文件流指针
失败返回NULL,并且更新errno
6.2.2、操作文件
6.2.2.1、以字符读写
fputc 和fgetc
#include <stdio.h>
int fgetc(FILE *stream);
函数功能:从stream指示的文件中读取字符
函数参数:需要读字符的文件流
函数返回值:成功返回读到的字符可以是(EOF,表示读完了),失败返回-1
6.2.2.2、以行读写
fgets
#include <stdio.h>
int fgetc(FILE *stream);
char *fgets(char)
函数功能:按行读
函数参数1:读到哪
函数参数2:读多少(实际读到的是size-1,最后一个空间给\0预留) 所以fgets相较于gets是安全的
函数参数3:从哪读
函数返回值:成功返回非0,返回NULL的时候是出错或者没有可读的字符了
fputs
#include <stido.h>
int fputs(int c, FILE *stream);
int fputs(const char *s, FILE *stream);
函数功能:给文件写
函数参数1:从哪写
函数参数2:给谁写
函数返回值:成功返回非负整数,失败返回-1
6.2.2.3、以对象读写
fread
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
函数功能:读
函数参数1:读到哪
函数参数2:一次读多少
函数参数3:总共读多少次数
函数参数4:从哪读
函数返回值:成功返回成功读或写的成员的个数,失败返回0
fwrite
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
函数功能:写
函数参数1:从哪写
函数参数2:一次写读多少
函数参数3:总共写多少次
函数参数4:往哪写
函数返回值:成功返回成功读或写的成员的个数,失败返回0
6.2.2.4、以格式化读写
fscanf
#include <stdio.h>
int scanf(const char *format, ...);
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
函数功能:从指定的流里面获取信息
函数参数1:指定的流
函数参数2……:同scanf
fprintf
#include <stdio.h>
int printf(const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
int dprintf(int fd, const char *format, ...);
int sprintf(char *str, const char *format, ...);
int snprintf(char *str, size_t size, const char *format, ...);
函数功能:往指定的流里面输出东西
函数参数1:指定的流
函数参数2……:同printf
6.2.3、关闭文件
fclose
#include <stdio.h>
int fclose(FILE *stream);
函数功能:关闭由参数stream指示的流
函数参数:需要被关闭的流
函数返回值:成功返回0,失败返回-1并且设置errno
6.3、main函数传参
#include <stdio.h>
int main(int argc, const char *argv[])
{
printf("argc = %d\n", argc);
for(int i=0; i<argc;i++)
{
printf("argv[%d] = %s\n", i, argv[i]);
}
return 0;
}
6.4、标准IO相关函数
fflush:
#include <stdio.h>
int fflus(FILE *stream);
函数功能:强制刷新由参数1指定的流
函数参数如果为NULL,则会刷新所有已打开的输出流
函数返回值:成功返回0,失败返回-1并且更新errno
feof:
判断文件是否到末尾
#include <stdio.h>
void clearerr(FILE *stream);
int feof(FILE *stream);
time函数:
time()
#include <time.h>
time_t time(time_t *tloc);
函数功能:返回一个从计算机元年到现在的秒数(1970-1-1 0:0:0)
函数参数:如果参数不为NULL,返回值也可以传址调用的形式返回
函数返回值:成功返回到现在的秒数,失败返回-1,并且更新errno
localtime()
#include <time.h>
struct tm *localtime(const time_t *timep);
函数功能:获取本地时间
函数参数:秒数
函数返回值:指向年月日结构体的指针
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 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
光标移动:
fseek()
函数功能:给指定的流从参数3描述的位置移动参数2个大小的位置
参数1:给谁移动光标
参数2:移动多少
参数3:从那开始:
SEEK_SET 从文件开头移动
SEEK_CUR 从文件当前光标指向的位置开始移动
SEEK_END 从文件末尾开始移动
返回值:
成功返回0,失败返回-1并且更新errno
获取光标位置
ftell()
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence);
long ftell(FILE *stream);
函数功能:计算由参数stream指示的流当前光标处在的位置
函数参数:指定的文件流
函数返回值:成功返回当前处在的位置,失败返回-1,并更新errno
fileno
#include <stdio.h>
int fileno(FILE *stream);
函数功能:获取文件流指针里面的文件描述符
7、文件IO
7.1、打开文件
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);
int creat(const char *pathname, mode_t mode);
函数功能:打开文件
函数参数1:需要打开的文件路径
函数参数2:打开的方式
必须包含如下的其中一个
O_RDONLY : 只读
O_WRONLY : 只写
O_RDWR : 可读可写
还可以有以下的:
O_APPEND: 以追加的形式打开
O_CREAT : 文件存在则打开,不存在则按照mode参数描述的权限创建一个普通文件
函数参数3:如果文件存在则打开,不存在则按照此参数描述的创建一个普通文件
函数返回值:成功返回文件描述符(非负的最小整数)file description fd
失败返回-1,并且更新errno
7.2、操作文件
read
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
函数功能:从fd描述的文件中读取count个字节的数据给buf开始的空间
函数参数1:从哪读
函数参数2:读到哪
函数参数3:读多少
函数返回值:成功返回实际上读到的数目,失败返回-1,并且更新errno
write
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
函数功能:把数据从buf指示的空间里面写道fd里,写了count个
函数参数1:往哪写
函数参数2:从哪写
函数参数3:写多少
函数返回值:成功返回写入的个数,失败返回-1并且更新errno
7.3、关闭文件
close
#include <unistd.h>
int close(int fd);
函数功能:关闭文件
函数参数:需要关闭的文件的文件描述符
函数返回值:成功返回0,失败返回-1并且更新errno
8、对目录文件的操作
8.1、打开目录
opendir
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
函数功能:打开目录
函数参数:需要被打开的目录
函数返回值:成功返回目录流指针,失败返回NULL,并更新errno
8.2、操作目录
8.2.1、读目录
readdir
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
函数功能:读目录
函数参数:要读取的目录
函数返回值:成功返回结构体指针,读完了返回NULL,失败返回NULL
stat
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
函数功能:获取指定文件的全部信息
函数参数1:需要获取的是谁(文件)
函数参数2:保存信息的结构体
函数返回值:成功返回0,失败返回-1,并且更新errno
lstat 和 stat 本身没有什么区别,但是当pathname表示的是一个链接文件的时候,返回的成员信息是链接本身而不是链接指向的文件
8.2.2、关闭目录
closedir
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
函数功能:关闭指定的目录文件
函数参数:需要关闭的目录
函数返回值:成功返回0,失败返回-1,并更新errno
9、动态库、静态库
9.1、库
是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于windows和linux的本质不同,因此二
者库的二进制是不兼容的。
9.1.1、动态库
静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。
动态库把对一些库函数的链接载入推迟到程序运行的时期(runtime)。
可以实现进程之间的资源共享。
将一些程序升级变得简单。
甚至可以真正做到链接载入完全由程序员在程序代码中控制。
----》编译时仅记录用到哪个共享库中的哪个符号,不复制共享库中的相关代码
优点:程序不包含库中代码,体积比较小,库升级方便,无需重新编译
缺点:在运行需要加载共享库
1、编写源代码
vim file_length.c/vim file_Line.c
2、分别生成相应的.o文件
gcc -c -fPIC file_Length.c -o file_length.o
注意:-fPIC要生成与位置无关的代码
3、生成动态库(共享库)
动态库的命名方式:lib+库名.so.版本号---->用数字来表示版本号
gcc -shared -o libfile.so.1 *.o
4、为共享库文件创建软连接文件
创建软链接文件的目的就是为了能够让我们的编译器在编译时找到共享库
ln -s libfile.so.1 libfile.so
5、编译并链接共享库(同时指明库路径)
gcc main_test.c -o myAPP -L. -lfile
6、运行时需要链接动态库
9.1.2、静态库
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动
态库存在,因此代码体积较小。
静态库对函数库的链接是放在编译时期(compile time)完成的。
程序在运行时与函数库再无瓜葛,移植方便
浪费空间和资源,因为所有相关的对象文件(object file)与牵涉到的函数库(library)被链接合成一个可执
行文件(executable file)。
---》编译时把静态库中的相关代码复制到可执行程序中
优点:程序运行时,无需加载库,运行速度更快
缺点:占用更多磁盘和内存空间,静态库升级后,需要重新编译链接
1、编写源代码
eg:只要是一个文件,文件的内容是一个子函数即可(目的是为了生成库)
vim file_length.c / vim file_Line.e
2、生成相应的.o文件
gcc -c file_length.c -o file_length.o
gcc -c file_Line.c -o file_Line.o
3、创建成相应的静态库
静态库的命名方式:lib+库名.a
ar rcs libfile *.o 注意:libfile.a中的file是库名
ar---->用来创建静态库
r----->在库中插入模块
c----->创建一个库,不管库是否存在,都将创建
s----->创建目标文件索引,这在创建较大的库是能加快时间
4、编译时链接静态库
gcc test.c -o test -L. -life 注意:-L. 中的点代表当前路径(库的位置)
5、运行
./可执行文件名
文件(object file)与牵涉到的函数库(library)被链接合成一个可执
行文件(executable file)。
—》编译时把静态库中的相关代码复制到可执行程序中
优点:程序运行时,无需加载库,运行速度更快
缺点:占用更多磁盘和内存空间,静态库升级后,需要重新编译链接
```制作静态库
1、编写源代码
eg:只要是一个文件,文件的内容是一个子函数即可(目的是为了生成库)
vim file_length.c / vim file_Line.e
2、生成相应的.o文件
gcc -c file_length.c -o file_length.o
gcc -c file_Line.c -o file_Line.o
3、创建成相应的静态库
静态库的命名方式:lib+库名.a
ar rcs libfile *.o 注意:libfile.a中的file是库名
ar---->用来创建静态库
r----->在库中插入模块
c----->创建一个库,不管库是否存在,都将创建
s----->创建目标文件索引,这在创建较大的库是能加快时间
4、编译时链接静态库
gcc test.c -o test -L. -life 注意:-L. 中的点代表当前路径(库的位置)
5、运行
./可执行文件名