- 函數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