1、在Linux系统中,几乎一切都是文件。目录(使用vi目录名验证),内存(查看/proc/进程号/maps文件验证),硬盘(查看/dev文件可验证)以及其他的各种硬件设备都可以看成文件。比如:文件/dev/tty可以看成键盘和显示器。
2、在标准C中的文件操作:用FILE*代表fopen打开的一个文件;而在UC中用文件描述符(一个非负整数)代表打开一个文件。
3、文件描述符自身不存储任何文件信息,信息都存在文件表(本身比较庞大)中。文件描述符对应文件表。就像用UID代表进程一样。
4、在Linux来说,一个进程最多同时打开256个文件,描述符从3开始,0~2的描述符系统占用,他们分别表示标准输入,标准输出和标准错误。
5、文件函数:open(),close(),read(),write(),ioctl()。
open() 打开一个文件,返回一个文件描述符
read() 读一个文件
write() 写一个文件
close() 关闭一个文件
ioctl() 控制文件的读写
6、函数原型int open(const char *pathname, int flags);和int open(const char *pathname, int flags, mode_t mode);创建成功返回文件描述符,失败返回-1。
第一个参数:文件路径包括文件名
第二个参数:文件描述符权限标记
flags取值:
O_RDONLY 只读方式打开 \
O_WRONLY 只写方式打开 --> 三种权限必选其一
O_RDWR 以可读可写方式打开 /
O_APPEND 从文件尾以追加方式打开。
创建标识:
O_CREAT 如果文件存在则打开,文件不存在就创建。
O_EXCL 如果文件文件不存在,创建文件;如果文件存在,返回-1,代表出错。
O_TRUNC 清空文件内容后打开
多个描述符一起使用要用按位或"|"连接。
第三个参数:只有在创建文件时指定文件权限。该权限是指文件在硬盘上的操作权限(某些权限由于系统出于安全考虑会屏蔽某些权限)。
7、函数原型:ssize_t read(int fd, void *buf, size_t count);也可以为int read(int fd, void* buf, size_t size);
参数:
fd文件描述符,就是open的返回值
buf是读文件的首地址,任意类型都可
size是buf的大小(有可能读不满)
返回值:正数 真实读到文件的字节数
0 什么都没读取
-1 出现错误
8、函数原型:ssize_t write(int fd, const void *buf, size_t count);也可以为int write(int fd, void* buf, size_t lenght)
参数:
参数:
fd文件描述符,就是open的返回值
buf是写文件的首地址,任意类型都可
lenght是真实想要写入的字节数
返回值:正数 真实写入文件的字节数
0 什么都没写
-1 出现错误
实例:
(1)文件写入比较:
C语言版:
#include <stdio.h>
#include <stdlib.h>
int main(){
FILE * p_file = fopen("a.txt","wb");
if(!p_file){
perror("fopen"),exit(-1);
}
int i = 0;
for(i = 0; i < 100000; i++){
fwrite(&i,sizeof(int),1,p_file);
}
close(p_file);
return 0;
}
UC普通版:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(){
int fd = open("b.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);
if(fd == -1){
perror("open"),exit(-1);
}
int i = 0;
for(i = 0; i < 100000; i++){
write(fd,&i,4);
}
close(fd);
return 0;
}
UC优化版:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(){
char buf[100000] = {}; //自定义缓冲区
int fd = open("c.txt",O_WRONLY | O_CREAT | O_TRUNC,0664);
if(fd == -1){
perror("open"),exit(-1);
}
int i = 0;
for(i = 0; i < 100000; i++){
buf[i%100000] = i;
if(i%100000 == 99999){
write(fd,buf,sizeof(buf)); //将缓冲区的内容写入到文件
}
}
close(fd);
return 0;
}
执行时间对比:
原因:所有的标C函数都在用户层定义了输入/输出缓冲区,作用就是累计到了一定数量以后再进入内核读/写一次。
所有的UC函数都没有定义缓冲区,但是可以由程序员自定义缓冲区提升效率,更加灵活。
(2)文件拷贝:
/*
文件拷贝练习
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main(void){
//打开第一个文件,用于读取里面的内容
int fdr = open("1.png",O_RDONLY);
if(-1 == fdr){ //检测文件打开是否失败
perror("open1"),exit(-1);
}
//打开第二个文件,用于存储复制第一个文件的内容
int fdw = open("2.png",O_WRONLY | O_CREAT | O_TRUNC, 0666);
if(-1 == fdw){ //检测文件打开是否失败
perror("open2"),exit(-1);
}
char buf[4096] = {};
while(1){
//读取文件内容
int res = read(fdr,buf,sizeof(buf)); //读取第一个文件的内容
if(-1 == res){ //判断是否读取有误
perror("read");
break;
}
if(!res){ //判断是否读到了文件末尾
break;
}
//写入文件中
write(fdw,buf,res); //将第一个文件的内容写到第二个文件中
}
//关闭文件
close(fdr);
close(fdw);
return 0;
}