转自http://blog.youkuaiyun.com/cinmyheart/article/details/18924241
File I/O
文件I/O
在Unix系统中,文件I/O大多数的使用五大函数来实现:open,read,write,lseek 和close.
术语unbuffered的意思是每个read或者write函数向内核请求一个系统调用
对于内核而言,每一个打开的文件都有相应的file descriptors(非负整数).
open 函数
#include<fcntl.h>
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所指的文件保持等待
- <span style="font-size:14px;">/***************
- just a demo
- ***************/
- #include"apue.h"
- #include"fcntl.h"
- #include"stdio.h"
- int main()
- {
- int file_descriptor = 0;
- if(file_descriptor = 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;
- }</span>
creat 函数
#include<fcntl.h>
int creat(const char* pathname,mode_t mode);
如果函数成功就返回打开的文件的file descriptor,否则返回-1
mode :
S_IRUSR 用户可读
S_IWUSR 用户可写
S_IXUSR 用户可执行
- #include<apue.h>
- #include<unistd.h>
- #include<fcntl.h>
- #define RWX (S_IRUSR | S_IWUSR | S_IXUSR)
- int main()
- {
- int file_descriptor = 0;
- if((file_descriptor = creat("./hello.t",RWX)) < 0)
- {
- printf("creat fail\nprocess end");
- return 0;
- }
- else
- {
- printf("creat successful\n");
- }
- close(file_descriptor);
- return 0;
- }
close函数
#include<unistd.h>
int close(int filedes)
如果成功返回0,否则返回-1
每个文件都有一个相关的“当前文件偏置”(current file offset),通常是一个非负整数。它测量表示的意义是从文件开头到结束的地方这段区域内,所含字节数。
read函数write函数的读写操作通常从这个offset开始
通常(default情况),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,否则返回-1
whence宏:
SEEK_SET 将文件的offset设置为文件开头
SEEK_CUR将文件的offset设置为当前值加上lseek的第二参数offset的值(offset必须为正数)
SEEK_END将文件的offset设置为文件的大小加上lseek的第二个参数offset的值(offset可正可负)
- <span style="font-size:14px;">/*
- just a demo for lseek
- */
- #include"apue.h"
- #include"stdio.h"
- #include"unistd.h"
- #include"fcntl.h"
- int main()
- {
- off_t file_off_set = 0;
- int file_descriptor = 0;
- if((file_descriptor = open("./text.t",O_RDONLY)) < 0)
- {
- printf("open error\nProcess end\n");
- return 0;
- }
- if((file_off_set = 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;
- }</span>
atomic operation微操作
- <span style="font-size:14px;">#inlcude<unistd.h>
- ssize_t pread(int filedes, void * buf,size_t nbytes,off_t offset);</span>
- <span style="font-size:14px;">ssize_t pwrite(int filedes,const void*buf,size_t nbytes,off_t offset);</span>
调用pread函数就相当于调用lseek函数之后紧接着调用read函数。这两者几乎是等价的,除了下面两点情况
1.调用pread的时候, 没有什么办法可以打断这两者(lseek和read)操作
2.文件指针没有更新
pwrite同理
简单的说,atomic operation就是指的一种操作。这种操作可能由其他多种操作组成(multiple step)。
这个atomic operation有个特点,就是这个atomic operation包含的操作步骤(step)要么都完成,要么都不
会开始进行。这个atomic operation中不会有其他的操作“夹杂着"发生。
下面是man pwrite 的结果:
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 是个定值而不是动态获得的,也就是说可能覆盖之前的文本内容(亲测,有这个情况)
如果要动态更新offset达到,每次都在 “新的文本末尾" 写入数据的话,那么则需要lseek和SEEK_END来实现更新offset
动态更新的在文本末尾写入数据用pwrite是没有必要的,lseek+write就可以了
my source code:
- #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 = 0;
- int duped_fd = 0;
- if((file_descriptor = open("./text.t",O_RDONLY)) < 0)
- {
- printf("open error\nprocess end\n");
- return 0;
- }
- else
- {
- duped_fd = 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's in-core state with storage device
- #include <unistd.h>
- int fsync(int fd);
- #include<fcntl.h>
- int fcntl(int filedes, int cmd,.../*int arg*/);
filedes文件标志符
cmd是参数宏,总共有十个,第三章只讨论前面七个,后面三个再第14章讨论
在秒速记录锁(record locking)的时候,第三个参数是一个指向结构体的指针
fcntl被用作五种不同的路径
第一,复制已经存在的文件标志符(descriptor)cmd = F_DUP
第二,设置或者获得文件标识符cmd = F_GETFD或者 cmd = F_SETFD
第三,设置或者获得状态符(status flag) cmd = F_GETFL或则F_SETFL
status flag:
O_RDWR
O_RDONLY
O_WRONLY
O_APPEND
O_NONBLOCK
O_SYNC
O_DSYNC
O_RSYNC
O_FSYNCO_ASYNC
第四,设置或则获得异步I/O权限(asynchronous I/O ownership)cmd = F_GETOWN or cmd = F_SETOWN
第五,设置或者获得记录锁(record lock)(cmd = F_GETLK, or cmd = F_SETLK)
- #include<apue.h>
- #include<fcntl.h>
- #include<stdio.h>
- int main()
- {
- int file_descriptor = 0;
- int copy_file_descriptor = 0;
- int file_flags = 0;
- int ownership = 0;
- int temp = 0;
- if((file_descriptor = open("./text.t",O_RDWR)) < 0)
- {
- printf("open error\nProcess end\n");
- return 0;
- }
- printf("file_descriptor is %d\n",file_descriptor);
- //cmd = F_DUPFD ,dupliacte the file descriptor
- if((copy_file_descriptor = 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 = F_GETFD, return file descriptor flass for fiedes as the vale of the fucntion
- if(temp = fcntl(file_descriptor,F_GETFD) < 0)
- {
- printf("fcntl error\nProcess end\n");
- return 0;
- }
- else
- {
- printf("file descriptor is %d\n",temp);
- }
- //cmd = F_GETFL,return file status flags for filedes.
- if(file_flags = 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 = F_GETOWN
- if(ownership = 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文件夹目录下的文件,如果被打开,相当于复制该文件标志符。
- <pre code_snippet_id="177568" snippet_file_name="blog_20140205_8_7827139" name="code" class="csharp"><pre code_snippet_id="177568" snippet_file_name="blog_20140205_8_7827139"></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- </pre>