Chinaunix首页 | 论坛 | 博客
  • 博客访问: 477999
  • 博文数量: 115
  • 博客积分: 5016
  • 博客等级: 大校
  • 技术积分: 1401
  • 用 户 组: 普通用户
  • 注册时间: 2008-09-21 16:03
文章分类

全部博文(115)

文章存档

2013年(1)

2010年(17)

2009年(76)

2008年(21)

我的朋友

分类: LINUX

2008-12-08 16:12:12

为了进一步敦促自己的学习,我决定把每天看过的内容写下来作为自己的读书笔记,同时也可以对重要的函数或者系统调用加以强化记忆!
1、open函数
#include
/*在《Beginning linux programming》中,这里还包含
*#include
*#include
*/
int open(const char *pathname,int oflag,.../*mode_t mode*/);
成功时返回文件描述符,失败时返回-1.
oflag参数用来说明文件的读写属性:O_RDONLY 0_WRONLY O_RDWR (只能指定一个)
可选参数:O_APPEND O_CREAT O_EXCL O_TRUNC O_NOCTTY O_NONBLOCK O_SYNC
mode:S_IS[UG]ID,S_ISVTX,S_IS[RWX](USR|GRP|OTH)
2、close函数
#include
int close(int fildes);  成功返回0,出错返回-1.
注意:关闭一个文件还会释放该进程施加在该文件上的所有记录锁。当一个进程终止时,内核自动关闭它所有打开的文件。
3、lseek函数
#include
off_t lseek(int fildes,off_t off,int whence);
成功返回新的文件偏移量,失败则返回-1.
whence选项:SEEK_SET SEEK_CUR SEEK_END
可以通过以下代码:
off_t offset;
offset = lseek(fd,0,SEEK_CUR);
来测试一个文件是否可以设置偏移量,如果文件描述符引用的是一个管道、FIFO或是网络套接字,则lseek返回-1,并将errno设置为ESPIPE。
4、read函数
#include
ssize_t read(int fildes,void *buf,size_t nbytes);
成功返回读取的字节数,若是到了文件结尾返回0,出错则返回-1.
其中ssize_t表示一个带符号整数 size_t表示一个不带符号整数  void *表示通用指针
5、write函数
#include
ssize_t write(int fildes,const void *buf,size_t nbytes);
成功返回已写的字节数,失败返回-1.其返回值通常与nbytes相同,否则表示出错。
6、pread函数和pwrite函数(原子性的执行定位搜索和I/O操作)
#include
ssize_t pread(int fildes,void *buf,size_t nbytes,off_t offset);
成功时返回已读的字节数,若到了文件结尾返回0,错误则返回-1
ssize_t pwrite(int fildes,const void *buf,size_t nbytes,off_t offset);
成功时返回已写的字节数,出错则返回-1
pread相当于顺序调用了lseek和read,但是无法中断其定位和读操作,不更新文件指针,这就避免了在早期通过lseek和read的顺序调用来实现添写文件不能满足多进程执行的问题。pwrite也是一样。
7、dup函数和dup2函数
#include
int dup(int fildes);
int dup2(int fildes1,int fildes2);
返回值:若成功返回新的文件描述符,失败则返回-1.
8、sync函数、fsync函数和fdatasync函数
传统unix系统中的延迟写机制-->减少了磁盘的读写次数,却降低了文件内容的更新速度。为了保证磁盘上实际文件系统与缓冲区高速缓冲中内容的一致性,unix系统提供了这三个函数。
#include
int fsync(int fildes);
int fdatasync(int fildes);
这两个函数若是成功则返回0,失败返回-1.
void sync(void);
sync函数只是将说有修改过的快缓冲区排入写队列,然后就返回,它不等待实际写操作完成。通常称为update的系统守护进程会周期性的调用sync函数,保证了定期冲洗内核的块缓冲区。命令sync也调用这个函数。fsync函数只对由文件描述符fildes指定的单一文件起作用,并且等待写磁盘操作结束然后返回。fdatasync与之类似但是它只影响文件的数据部分。
9、fcntl函数
#include
int fcntl(int fildes,int cmd, .../*int arg*/);
cmd选项:F_DUPFD  F_[SG]ET(FD|FL|OWN|LK) F_SETLKW  十种
F_DUPFD和dup*函数类似,F_GETFD返回对应于fildes的文件描述符标志,这个标志为0表示在exec时不关闭,为1时表示在exec时关闭。F_GETFL返回的文件状态标志与open函数的oflag字段相同。
10、ioctl函数
#include
int ioctl(int fildes,int request,...);
另外终端I/O的ioctl命令都需要头文件.
11、/dev/fd
较新的系统都提供名为/dev/fd的目录,其目录名为0、1、2等的文件,打开/dev/fd/n等效于复制描述符n.
12、I/O的效率
通过本节的学习,以及与第五章中标准IO的比较,感觉后者在基本的效率和可移植性上更好一些,当然用得熟练了选择合适的BUFFSIZE值运用系统调用的效率会更高。这部分内容还是在后续的学习中进一步去体会和研究。
学习这一部分内容时,我自己动手写了一些比较小的例子来实践,深化了对这些函数的调用但其中也遇到了一些问题,比如说我在通过open函数创建文件并且通过write函数写入后,在用read函数读取时总是返回0,令人费解,自己在linux下创建好的文件用read读取时就没有什么问题。比如下面的程序:
#include
#include
#include
#include
#include
#include
#define BUFSIZE 1024
int main()
{
 int file_des,file_src,file_new;
 int w,n;
 char buff[BUFSIZE];
 off_t off;
 off_t off1=100;
 umask(0);
 file_src = open("source",O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IXUSR);
 if(file_src)
 {
  printf("Source file create successfully!\n");
 }
 char buf[100] = "This part of my life,this little part of my life,I am happy!";
 w = write(file_src,buf,100);
 if(!w)
 {
  printf("Write error!");
 }
 else
 {
  printf("Write %d characters successfully!\n",w);
 }
 file_new = open("new.txt",O_RDWR);
 n = read(file_new,buff,BUFSIZE);
 printf("the value of n is %d\n",n);
 file_des = open("destination",O_RDWR|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR|S_IXUSR);
 if(file_des)
 {
  printf("Destination file create successfully!\n");
 }
 off = lseek(file_des,off1,SEEK_SET);
 if(off==-1)
 {
  printf("Can't lseek!\n");
 }
 printf("The offset is %d\n",off);
 n = read(file_src,buff,BUFSIZE);
 if(n>0)
 //while((n=read(STDIN_FILENO,buff,BUFSIZE))>0)
 {
  if(write(file_des,buff,n)!=n)
   printf("Write error!\n");
  else
   printf("Write successfully!\n");
 }
 else
 {
  printf("Read source error!");
 }
 buff[n-1]='\0';
 puts(buff);
 exit(0);
}
为了进一步验证这个问题,我又写了一个程序:
#include
#include
#include
#include
#include
int main(void)
{
 int file_d;
 int n;
 static char buf[100];
 char buff[] = "Just try!I will be successful!";
 file_d = open("source",O_RDWR|O_APPEND);
 if((n = write(file_d,buff,sizeof(buff)))==sizeof(buff))
 {
  printf("Write successfully!\n");
 }
 else
 {
  printf("Write failed!\n");
 }
 if(n = read(file_d,buf,100)>0)
 {
  //buf[n-1]='\0';
  printf("%c",buf[n-1]);
  puts(buf);
 }
 else
 {
  printf("Read error!\n");
 }
 printf("%d\n",n);
}
这个实验更是诡异,当我以open("source",O_RDWR)打开时,read返回1,当我改成追加方式file_d = open("source",O_RDWR|O_APPEND);时,read返回0,真的搞不懂是怎么回事?暂且留下这个问题吧,我再探索一下。
另外有个地方更深化了我对write的理解。上面绿色部分的目的是建立一个文件空洞,当文件的创建方式为open("destination",O_RDWR|O_CREATE|O_TRUNC);时(相当于用creat函数创建),可以实现空洞的建立,但是当使用open("destination",O_RDWR|O_CREATE|O_APPEND);时,空洞不能建立成功!
此处的原因是:
对于普通文件,写操作从文件的当前偏移量处开始。如果指定了O_APPEND选项,则在每次写操作之前文件的偏移量设置在文件的当前结尾处,在一次写之后,该文件偏移量增加实际写的字节数。
阅读(937) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~