-
函数open和openat
-
打开或新建一个文件
#include <fcntl.h>
int open(const char *path,int oflag...../*mode_t mode*/);
int openat(int fd,const char *path,int oflag.../*mode_t mode*/);
函数的返回值:若成功,返回文件描述符;若出错,返回-1;
我们将最后一个参数写为….,这种方法表明余下的参数的数量和类型是可变的。
path参数是要打开或创建文件的名字。oflag参数可用来说明此函数的多个选项(只读,只写,读写);
- 当path参数是绝对路径,两个函数一致
- 当path是相对路径,fd参数指出了相对路径名在文件系统的开始地址,
- path是相对参数,fd参数具有特殊值AT_FDCWD,这种情况下,路径名在当前工作目录获取,这个时候openat和open功能类似。
open和openat函数返回的文件描述符一定是最小的未用描述符值。
-
函数creat
-
创建一个新文件
#include<fcntl.h>
int creat(const char *path,mode_t mode);
返回值:若成功,返回为只写打开的文件描述符;若出错,返回-1;
等效open(path,O_WRONLY|O_CREAT|O_TRUNC,mode);
函数close
#include<unistd.h>
int close(int fd);
返回值:若成功,返回0;若出错,返回-1;
-
函数lseek
-
调用lseek 显式地为一个打开的文件设置偏移量
#include<unistd.h>
off_t lseek(int fd,off_t offset,int whence);
返回值:若成功,返回新的文件偏移量;若出错,返回-1;
参数offset与whence有关:
- 若whence 是SEEK_SET,偏移量为文件开始处offset
- 若whence是SEEK_CUR,偏移量为当前值加offset,offset可正可负;
- 若whence是SEEK_END,偏移量设置为文件长度加offset,可正可负
如下,当文件偏移量大于文件长度时,系统是如何保存文件的
#include<apue.h>
2 #include<fcntl.h>
3
4 char buf1[]="abcdefghij";
5 char buf2[]="ABCDEFGHIJ";
6
7 int main()
8 {
9 int fd;
10 if((fd=creat("file.hole",FILE_MODE))<0)
11 err_sys("create error");
12 if(write(fd,buf1,10)!=10)
13 err_sys("buf1 write error");
14 //offset now=10
15 if(lseek(fd,16384,SEEK_SET)==-1)
16 err_sys("lseek error");
17 //offset now=16384
18
19 if(write(fd,buf2,10)!=10)
20 err_sys("write buf2 error");
21 //offset now=16394
22 exit(0);
23 }
file_hole.c
-
函数read
-
从打开的文件中读数据
#include<unistd.h>
ssize_t read(int fd,void* buf,size_t nbytes);
返回值:读到的字节数,若已到文件尾,返回0;若出错:返回-1;
-
函数write
-
向打开文件写数据
#include<unistd.h>
ssize_t write(int fd,const void*buf,size_t nbytes);
返回值:若成功,返回已经写的字节数;若出错,返回-1;
其返回值通常与nbytes的值相同,否则出错;
1 #include<apue.h>
2
3 #define BUFFSIZE 4096
4
5 int main()
6 {
7 int n;
8 char buf[BUFFSIZE];
9 while((n=read(STDIN_FILENO,buf,BUFFSIZE))>0)
10 if(write(STDOUT_FILENO,buf,n)!=n)
11 err_sys("write error");
12 if(n<0)
13 err_sys("read error");
14 exit(0);
15 }
Read_Write.c
文件共享
-
文件的三种结构
-
1.记录项:包含一张打开文件描述符表
2.文件表
3.V节点:包含了文件类型和操作文件的各种函数的指针
原子操作
函数pread和pwrite
#include<unistd.h>
ssize_t pread(int fd,void *buf,size_t nbytes,off_t offset);
//返回值:读到的字节数,若已到文件尾,返回0,若出错,返回-1
ssize_t pwrite(int fd,const void *buf,size_t nbytes,off_t offset);
//返回值:若成功,返回已写的字节数;若出错,返回值-1
调用pread 相当于调用lseek后调用read,但是pread又与这种顺序调用有下列重要区别:
- 调用pread时,无法中断其定位和读操作
- 不更新当前文件偏移量
-
函数dup和dup2
- 两个函数都可以复制一个现有的文件描述符
#include<unistd.h>
int dup(int fd);
int dup2(int fd,int fd2);
//两函数的返回值:若成功,返回新的文件描述符;若出错,返回-1
-
由dup返回的文件描述符一定是当前可用描述符中最小的值。对dup2,可以用fd2参数指定新描述符的值。如果fd2已经打开,则先将其关闭,若fd等于fd2,则dup2返回fd2,而不关闭它。
函数sysnc、fsync和fdatasync
- 将缓冲区的数据写入磁盘
#include<unistd.h>
int fsync(int fd);
int fdatasync(int fd);
//返回值:若成功,返回0;若出错,返回-1;
void sync(void);
-
sync只是将所有修改过的块缓冲区排入写队列,不等其是否写完就返回。
fsync支队fd指定的文件起作用并且等待写完才返回结束。
fdatasync类似fsync,但fsync只影响文件的数据部分,而除数据外,fdatasync还会同步更新文件的属性
函数fcntl
- 可以改变已经打开的文件的属性
#include<fcntl.h>
int fcntl(int fd,int cmd,.../*int arg */);
//返回值:若成功,则依赖于cmd;若出错,返回-1;
fcntl函数有以下5中功能
(1) 复制一个已有的描述符(cmd=F_DUPFD或F_DUPFD_CLOEXEC)
(2)获取/设子文件的描述符标志(cmd=F_GETFP或F_SETFD)
(3)获取/设置文件状态标志(cmd=F_GETFL或F_SETFL)
(4)获取/设置异步I/O所有权(cmd=F_GETOWN或F+SETOWN)
(5)获取/设置记录锁(cmd=F_GETLK、F_SETLK或F_SETLKW)
程序的第一个参数指定文件描述符,并对还描述符打印其所选择的文件标志说明
#include<apue.h>
#include<fcntl.h>
int main(int argc,char* argv[])
{
int val;
if(argc!=2)
err_sys("usage:DupTest<descriptor#>");
if((val=fcntl(atoi(argv[1]),F_GETFL,0))<0)
err_sys("fcntl error for fd %d",atoi(argv[1]));
switch(val&O_ACCMODE){
case O_RDONLY:
printf("read only");
break;
case O_WRONLY:
printf("write only");
break;
case O_RDWR:
printf("read write");
break;
default:
printf("unkown access mode");
}
if(val&O_APPEND)
printf(", append");
if(val&O_NONBLOCK)
printf(", nonblock");
if(val&O_SYNC)
printf(", synchronous writes");
#if !defined(_POSIX_C_SOURCE)&&defined(O_FSYNC)&&(O_FSYNC!=O_SYNC)
if(val&O_FSYNC)
printf(", synchronous writes");
#endif
putchar('\n');
exit(0);
}
/dev/fd
较新的系统都提供名为/dev/fd/的目录,其目录项时名为0、1、2等的文件。打开文件/dev/fd/n等效于复制描述符n。某些系统提供路径名/dev/stdin,/dev/stdout和/dev/stderr,这些等效于/dev/fd/0,/dev/fd/1和/dev/fd/2