一 IO的基础
1.1 认识内核对象
Linux不允许直接访问内核设备和内存,但可以通过内核系统函数去访问
对每个内核对象进行编号ID
如果访问内核对象,只能通过内核ID
编程模型:
申请得到一个内核ID
在内核系统函数中使用内核ID得到对应的内核对象数据
1.2 怎么访问文件
使用函数,传递一个文件名,系统打开文件,加载文件至内核,返回一个内核ID
使用函数,传递内核ID,得到数据
使用函数,传递内核ID,告诉系统释放文件
ID:文件描述符,file description(fd)
1.3 每个程序默认打开三个文件设备:
0:标准输入
1:标准输出
2:错误输出
1.4 操作文件描述符
ssize_t write(int fd,
void* buf,//要写入内核对象的数据
size_t size);//写入数据的大小
返回:
> 0 实际写入的数据
-1 写入错误
ssize_t read(int fd,
void* buf,//返回数据的空间
size_t size);//空间大小
返回:
> 0 实际读取的数据
= 0 碰到文件结束符号 EOF
-1 读取错误
二 基于文件的描述符
2.1 获取/释放文件描述符
a.文件类型
目录文件d
普通文件f
字符设备文件c
块设备文件b (/dev/sda 硬盘)
软连接文件l
管道文件p
socket文件s
b.文件属性
2.2 通过文件描述符读写各种数据
2.3 文件描述符与重定向
三 IO与文件映射
3.1 IO的共享与效率
read与write其中数据缓冲的大小
读取数据的缓冲:getpagesize
3.2 定位与定位读取
read与write在操作的时候,自动移动读取位置
lseek改变读取位置
pread/pwrite 在指定的位置读写数据,改变读写位置
pread == lseek + read
pwrite == lseek + write
3.3 文件的其他操作
fstat 获取文件状态
ftruncate 改变文件大小
3.4 文件映射
虚拟地址映射到内存
虚拟地址可以映射到文件:可以用内存的方式读写文件
mmap/munmap
案例:
1.使用内存方式写入数据
2.使用内存方式读取数据
四 文件描述符的操作(IO锁)
文件描述符是整数
文件描述符对应内核的上下文
4.1 dup dup2 拷贝文件描述符
4.2 fcntl对文件描述符的属性的修改
4.2.1 拷贝文件描述符
4.2.2 修改判定文件的描述标记
4.2.3 修改判定文件的状态标记
不可修改 O_RDONLY O_WRONLY O_RDWR O_CREAT O_EXCL
可修改 O_APPEND O_ASYN异步方式
4.2.4 设置强制锁 (重新编译内核)
4.2.5 设置建议锁(默认)
4.2.6 设置IO的信号
文件IO实例:
socket_server_send是对send函数的一个封装,读者可以自行实现
//读取指定文件并传送到客户端
void SendFile(const char* filename,int conn_id)
{
int fd=0;
char path[256]={0};
int loc=0;
sprintf(path,"./file/%s",filename);
fd = open(path,O_RDONLY);
if(-1 == fd)
{
printf("FileManager::SendFile open error\n");
return ;
}
struct stat info;
fstat(fd,&info);
printf("file %s size is %d\n",filename,info.st_size);
short total_size = 4;
total_size += sizeof(int);
total_size += strlen(filename);
short package_size = total_size - 2;
char* buf = (char*)malloc(total_size);
memcpy(buf,&package_size,2);
char type='F';
memcpy(buf+2,&type,1);
char extra = 0;
memcpy(buf+3,&extra,1);
int file_size = info.st_size;
memcpy(buf+4,&file_size,4);
memcpy(buf+8,filename,strlen(filename));
printf("total_size:%d\n",total_size);
socket_server_send(ss,conn_id,buf,total_size);
char buffer[2048]={0};
while(1)
{
lseek(fd,loc,SEEK_SET);
short size = read(fd,buffer,1024);
if(-1 == size)
{
printf("file_manager: file read error\n");
break;
}
else if(0 == size)
{
printf("file_manager: file send over!\n");
break;
}
printf("file send package size:%d\n",size);
loc += size;
total_size = size+4;
buf = (char*)malloc(total_size);
package_size = total_size-2;
memcpy(buf,&package_size,2);
memcpy(buf+2,&type,1);
extra = 1;
memcpy(buf+3,&extra,1);
memcpy(buf+4,buffer,size);
socket_server_send(ss,conn_id,buf,total_size);
}
close(fd);
}