Linux文件
·
目录
1.文件IO与标准IO的区别
linux标准文件描述符

文件 IO :是直接调用内核提供的系统调用函数 , 头文件是 unistd.h
标准 IO :是间接调用系统调用函数,头文件是 : stdio.h
缓存的概念 :
1. 我们的程序中的缓存,就是你想从内核读写的缓存(数组) ---- 用户空间的缓存
2. 每打开一个文件,内核在内核空间中也会开辟一块缓存,这个叫内核空间的缓存
文件 IO 中的写即是将用户空间中的缓存写到内核空间的缓存中。
文件 IO 中的读即是将内核空间的缓存写到用户空间中的缓存中。
3. 标准 IO 的库函数中也有一个缓存,这个缓存称为 ---- 库缓存。
C 库缓存的特点:
1. 遇到 \n 时,会将库缓存的内容写到内核缓存中,即调用了系统调用函数。
2. 库缓存写满时(1024字节),会调用系统调用函数,将库缓存内容写到内核缓存中。
验证库缓存存在:
此时程序运行但不会输出hello world ,如果我们在输出后面加上一个\n
程序依旧是死循环,但输出了hello world,说明缓存存在。
2.三类读写函数
一类:行缓存 ,遇到换新行( \n ),或者写满缓存时,即调用系统调用函数
读: fgets,gets,printf,fprintf,sprintf
写: fputs,puts,scanf
二类:无缓存 只要用户调这个函数,就会将其内容写到内核中
三类:全缓存 只有写满缓存再调用系统调用函数
读: fread
写: fwrite
行缓存的读写函数fgets和 fputs:
int fputs(const char *s,FILE *stream);
第一个参数:缓存,即写什么内容
第二个参数:写到哪里去
返回值:若成功则为非负值,若出错则为 EOF (-1 ) 。
这里写入文件是因为fclose 关闭一个文件流,使用fclose就可以把缓冲区内最后剩余的数据输出到磁盘文件中,并释放文件指针和有关 的缓冲区.
如果加上一个死循环,程序没有通过fclose,则无法写入。
char *fgets (char *s, int size,FILE *stream)
第一个参数:缓存,即读到哪里去
第二个参数:读多少个字节
第三个参数:从什么地方读
返回值:若成功则为 s (缓存的地址),若已处文件尾端或出错则为 null
实例:
此处用到fseek因为在fputs函数调用以后a.c文件指针到文件末尾,需要重新定位文件指针才能读取文件内部字符串。
rewind(FILE *fp) 用于设定流的文件位置指示为文件开始,该函数调用成功无返回值。
rewind() 等价于 (void)fseek(fp 0, SEEK_SET) ;
刷新缓存函数:
ffluash ( FIFE *fp ) 把库函数中的缓存内容强制写到内核中。
实例:
无缓存函数:
stderr 只要用户调这个函数,就会将其内容写到内核中
实例:
行缓存的读写函数 gets 和 puts:
char *gets(char*s);
实例:
gets
fgets:
gets 与 fgets 的区别:
gets() 时不能指定缓存的长度,这样就可能造成缓存越界(如若该行长于缓存长度),写到缓存之后的存储空
间中,从而产生不可预料的后果;
gets() 只能从标准输入中读;
gets() 与 fgets() 的另一个区别是 :gets() 并不将新行符存入缓存中 , fgets 将新行符存入缓存中 ;
int puts(constchar *s);
实例:
puts 与 fputs 的区别:
puts() 只能向标准输出中写;
puts() 与 fputs() 的另一个区别是 : puts 输出时会添加一个新行符, fputs 不会添加。
fprintf 、 printf 、 sprintf 行缓存的函数
int fprintf(FILE *stream,” 字符串格式 ”)
fprintf 可以输出到文件中,也可输出到显示器。
printf 只能输出到显示器中。
intsprintf(str *, “ 字符串格式 ”)
输出内容到一个字符串中
实例:
fprintf:
sprintf:
一个字符读写函数 fgetc 和 fputc
int fgetc(FILE *fp)
功能:从文件中读取一个字符;
参数:文件流
返回值:正确为读取的字符,到文件结尾或出错时返回 EOF 。
实例:
第一次运行代码发现打印到的字符不正确,后发现文件指针位置可能不正确,在把文件指针位置定位到开始后再运行代码,发现正确,所以错误为未改正文件指针位置
int fputc(int c, FILE *fp)
功能:写一个字符到文件中
参数:第一个参数为要写的字符,第二个参数为文件流
返回值:成功则返回输入的字符,出错返回 EOF 。
实例:
证明fputc有缓存,但不是行缓存函数:
可以证明是有缓存的
在加上\n后还是无法写入文件,说明它有缓存但不是行缓存。
int feof(FILE *stream);
功能:判断是否已经到文件结束
参数:文件流
返回值:到文件结束,返回为非 0 ,没有则返回 0
int ferror(FILE *stream);
功能:判断是否读写错误
参数:文件流
返回值:是读写错误,返回为非 0 ,不是则返回 0
void clearerr(FILE *stream);
功能:清除流错误
参数:文件流
cat 命令的实现
3.静态库和动态库
Linux 操作系统支持的函数库分为:
静态库, libxxx.a ,在编译时就将库编译进可执行程序中。
优点:程序的 运行环境 中不需要外部的函数库。
缺点:可执行程序大
动态库,又称共享库, libxxx.so ,在运行时将库加载到可执行程序中。
优点:可执行程序小。
缺点:程序的 运行环境 中必须提供相应的库。
函数库目录:/lib /usr/lib。
静态库的制作:
1. 生成目标文件: gcc -c file.c .o
2. 静态函数库创建命令 ar
ar ‐cr libfile.a file.o
‐c: create 的意思
‐r: replace 的意思,表示当插入的模块 file.o 已经存在 libfile.a 中,则覆盖。反之 ar 显示一个错误消息。
静态库的编译: gcc -o main main.c -L. -lfile 编译 main.c 就会把静态函数库整合进 main 。
其中 :
-L 指定静态函数库的位置供查找,注意 L 后面还有 '.' ,表示静态函数库在本目录下查找。
-l 则指定了静态函数库名,由于静态函数库的命名方式是 lib***.a ,其中的 lib 和 .a 忽略。
删除 libaddsub.a 后 main 依然可以运行,因为静态库的内容已经整合进去了。
先写一个main函数和一个sub函数
然后通过静态库的制作来使main调用sub函数。
动态函数库的制作 :
1. 生成目标文件: gcc -c file.c
2.gcc -shared -fpic -o libfile.so file.o
‐fpic :产生位置无关代码。
‐shared :生成共享库。
用上述命令生成 libaddsub.so 动态函数库。
gcc ‐o out main.c ‐L. ‐lfile
此时还不能立即 ./out ,因为在动态函数库使用时,会查找 /usr/lib /lib 目录下的动态函数库,而此时我们生成的库不在里边。
第一种方法:
libaddsub.so放到/usr/lib 或/lib中去。
第二种方法,假设libfile.so在/home/linux/file 环境变量方法
export LD_LIBRARY_PATH=/home/linux/addsub:$LD_LIBRARY_PATH
第三种方法:
在/etc/ld.so.conf文件里加入我们生成的库的目录,然后/sbin/ldconfig。
/etc/ld.so.conf是非常重要的一个目录,里面存放的是链接器和加载器搜索共享库时要检查的目录,默认是
从/usr/lib /lib中读取的,所以想要顺利运行,可以把我们库的目录加入到这个文件中并执行/sbin/ldconfig
更多推荐



所有评论(0)