File I/O
文件I/O
在Unix系统中,文件I/O大多数的使用五大函数来实现:open,read,write,lseek 和close.
术语unbuffered的意思是每个read或者write函数向内核请求一个系统调用
对于内核而言,每一个打开的文件都有相应的file descriptors(非负整数).
open 函数
#include
int open(const char* pathname,int oflag,......,/* mode_t mode */);
如果正确返回file descriptor,否则返回 -1
pathname是文件名的路径,oflag是option flag,选项标签这里的选项是宏定义
oflag宏:
O_RDONLY 只可读
O_WRONLY 只可写
O_RDWR 可读写
O_APPEND 对于每个write函数的写入点从当前文件末尾开始
O_CREAT 如果文件不存在,就创建这个文件。
当然这个对于open函数使用的选项需要和函数的第三个参数mode一起,mode用于描述新建文件的权限
O_EXCL 如果使用了O_CREAT宏,并且这个文件已经存在了,于是 产生一个错误
O_TURNC 如果文件存在了并且被每一个write或者read函数成功的打开了,这个选项将“命令“open函数去清空所有文件内容,使之文本长度为0.
O_NOCTTY 如果pathname提及的是terminal设备,不允许设备被作为controling terminal
O_DSYNC 使得write等待每一个物理I/O完成自己的工作,但是不等待那种不影响读取刚写入的数据的文件
O_RSYNC 在任何write操作对于某一文件的同一部分写入操作完成之前,让被read操作的file descriptor所指的文件保持等待
/***************
just a demo
***************/
#include"apue.h"
#include"fcntl.h"
#include"stdio.h"int main()
{int file_descriptor &#61; 0;if(file_descriptor &#61; open("./text.t",O_RDONLY) <0){printf("open error\nprocess end\n");return 0;}else{printf("open success\n");close(file_descriptor);//if there is not close function ,it would be OK...}return 0;
}
creat 函数
#include
int creat(const char* pathname,mode_t mode);
如果函数成功就返回打开的文件的file descriptor&#xff0c;否则返回-1
mode &#xff1a;
S_IRUSR 用户可读
S_IWUSR 用户可写
S_IXUSR 用户可执行
#include
#include
#include#define RWX (S_IRUSR | S_IWUSR | S_IXUSR)int main()
{int file_descriptor &#61; 0;if((file_descriptor &#61; creat("./hello.t",RWX)) <0){printf("creat fail\nprocess end");return 0;}else{printf("creat successful\n");}close(file_descriptor);return 0;
}
close函数
#include
int close(int filedes)
如果成功返回0&#xff0c;否则返回-1
每个文件都有一个相关的“当前文件偏置”(current file offset)&#xff0c;通常是一个非负整数。它测量表示的意义是从文件开头到结束的地方这段区域内&#xff0c;所含字节数。
read函数write函数的读写操作通常从这个offset开始
通常(default情况)&#xff0c;offset被初始化为0.
lseek函数
#include"unistd.h"//unistd.h - standard symbolic constants and types
off_t lseek(int files, off_t offset, int whence)
如果成功返回file offset&#xff0c;否则返回-1
whence宏&#xff1a;
SEEK_SET 将文件的offset设置为文件开头
SEEK_CUR将文件的offset设置为当前值加上lseek的第二参数offset的值(offset必须为正数)
SEEK_END将文件的offset设置为文件的大小加上lseek的第二个参数offset的值(offset可正可负)
/*
just a demo for lseek
*/
#include"apue.h"
#include"stdio.h"
#include"unistd.h"
#include"fcntl.h"int main()
{off_t file_off_set &#61; 0;int file_descriptor &#61; 0;if((file_descriptor &#61; open("./text.t",O_RDONLY)) <0){printf("open error\nProcess end\n");return 0;}if((file_off_set &#61; lseek(file_descriptor,file_off_set,SEEK_CUR)) <0){printf("lseek error\n");return 0;}else{printf("lseek execute successful\nCurent file off-set is %d\n",file_off_set);}return 0;
}
atomic operation微操作
#inlcude
ssize_t pread(int filedes, void * buf,size_t nbytes,off_t offset);
ssize_t pwrite(int filedes,const void*buf,size_t nbytes,off_t offset);
调用pread函数就相当于调用lseek函数之后紧接着调用read函数。这两者几乎是等价的&#xff0c;除了下面两点情况
1.调用pread的时候&#xff0c; 没有什么办法可以打断这两者(lseek和read)操作
2.文件指针没有更新
pwrite同理
简单的说&#xff0c;atomic operation就是指的一种操作。这种操作可能由其他多种操作组成(multiple step)。
这个atomic operation有个特点&#xff0c;就是这个atomic operation包含的操作步骤(step)要么都完成&#xff0c;要么都不
会开始进行。这个atomic operation中不会有其他的操作“夹杂着"发生。
下面是man pwrite 的结果&#xff1a;
pwrite() writes up to count bytes from the buffer
starting at buf to the file descriptor fd at offset
The file offset is not changed.
值得注意的是这里的offset 是个定值而不是动态获得的&#xff0c;也就是说可能覆盖之前的文本内容(亲测&#xff0c;有这个情况)
如果要动态更新offset达到&#xff0c;每次都在 “新的文本末尾" 写入数据的话&#xff0c;那么则需要lseek和SEEK_END来实现更新offset
动态更新的在文本末尾写入数据用pwrite是没有必要的&#xff0c;lseek&#43;write就可以了
my source code&#xff1a;
#include"unistd.h"
int dup(int fd);
int dup2(int fd,int fd2)
对于file descriptor的复制
These system calls create a copy of the file descriptor oldfd. dup() uses the lowest-numbered unused descriptor for the new descriptor. dup2() makes newfd be the copy of oldfd, closing newfd first if necessary, but note the following:
* If oldfd is not a valid file descriptor, then the call fails, and newfd is not closed.
* If oldfd is a valid file descriptor, and newfd has the same value as oldfd, then dup2() does nothing, and returns newfd.
#include"apue.h"
#include"unistd.h"
#include"fcntl.h"
int main()
{int file_descriptor &#61; 0;int duped_fd &#61; 0;if((file_descriptor &#61; open("./text.t",O_RDONLY)) <0){printf("open error\nprocess end\n");return 0;}else{duped_fd &#61; dup(file_descriptor);printf("The duped file descriptor is %d\n",duped_fd);printf("The file_descritor before dup:%d\n",file_descriptor);}return 0;
}
NAME
fsync, fdatasync - synchronize a file&#39;s in-core state with storage device
#include int fsync(int fd);#include
int fcntl(int filedes, int cmd,.../*int arg*/);
filedes文件标志符
cmd是参数宏&#xff0c;总共有十个&#xff0c;第三章只讨论前面七个&#xff0c;后面三个再第14章讨论
在秒速记录锁&#xff08;record locking&#xff09;的时候&#xff0c;第三个参数是一个指向结构体的指针
fcntl被用作五种不同的路径
第一&#xff0c;复制已经存在的文件标志符&#xff08;descriptor&#xff09;cmd &#61; F_DUP
第二&#xff0c;设置或者获得文件标识符cmd &#61; F_GETFD或者 cmd &#61; F_SETFD
第三&#xff0c;设置或者获得状态符&#xff08;status flag&#xff09; cmd &#61; F_GETFL或则F_SETFL
status flag:
O_RDWR
O_RDONLY
O_WRONLY
O_APPEND
O_NONBLOCK
O_SYNC
O_DSYNC
O_RSYNC
O_FSYNC O_ASYNC
第四&#xff0c;设置或则获得异步I/O权限(asynchronous I/O ownership)cmd &#61; F_GETOWN or cmd &#61; F_SETOWN
第五&#xff0c;设置或者获得记录锁(record lock)(cmd &#61; F_GETLK, or cmd &#61; F_SETLK)
#include
#include
#include
int main()
{int file_descriptor &#61; 0;int copy_file_descriptor &#61; 0;int file_flags &#61; 0;int ownership &#61; 0;int temp &#61; 0;if((file_descriptor &#61; open("./text.t",O_RDWR)) <0){printf("open error\nProcess end\n");return 0;}printf("file_descriptor is %d\n",file_descriptor);//cmd &#61; F_DUPFD ,dupliacte the file descriptorif((copy_file_descriptor &#61; fcntl(file_descriptor,F_DUPFD,0)) <0){printf("fcntl error\nProcess end");return 0;}else{printf("The return value is %d\n",copy_file_descriptor);}//cmd &#61; F_GETFD, return file descriptor flass for fiedes as the vale of the fucntionif(temp &#61; fcntl(file_descriptor,F_GETFD) <0){printf("fcntl error\nProcess end\n");return 0;}else{printf("file descriptor is %d\n",temp);}//cmd &#61; F_GETFL,return file status flags for filedes.if(file_flags &#61; fcntl(file_descriptor,F_GETFL) <0){printf("fcntl error\nProcess end\n");return 0;}else{switch(file_flags& O_ACCMODE) //& O_ACCMODE){case O_RDWR :printf("file flags is O_RDWR\n");break;case O_RDONLY:printf("file flags is O_RDONLY\n");break;case O_WRONLY:printf("file flags is O_WRONLY\n");break;}if(file_flags&O_APPEND){printf("file flags is O_APPEND\n");} if(file_flags&O_NONBLOCK){printf("file flags is O_NONBLOCK\n");}#if defined(O_SYNC)if(file_flags&O_SYNC){ printf("file flags is O_SYNC\n");}#endif#if defined(O_DSYNC)if(file_flags&O_DSYNC){printf("file flags is O_DSYNC\n");}#endif#if defined(O_FSYNC)if(file_descriptor&O_FSYNC) {printf("file flags is O_FSYNC\n");}#endif#if defined(O_ASYNC)if(file_descriptor& O_ASYNC){printf("file flags is O_ASYNC\n");} #endif#if defined (O_RSYNC)if(file_descriptor&O_RSYNC){printf("file flags is O_RSYNC\n");}#endif}//cmd &#61; F_GETOWNif(ownership &#61; fcntl(file_descriptor,F_GETOWN) <0){printf("fcntl error!\nProcess end\n");return 0;}else{printf("file ownership is %d",ownership);}return 0;
}
在 /dev/fd文件夹目录下的文件&#xff0c;如果被打开&#xff0c;相当于复制该文件标志符。