1.<unistd.h>中规定了文件标识符:
//头文件多在/usr/include/下
* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
2.open
#include
<fcntl>
int
open(
const
char* path,
int flags);
int
open(
const
char* path,
int flags,
mode_t mode);
int
openat(
int fd,
const
char* path,
int flags);
int
openat(
int fd,
const
char* path,
int flags,
mode_t mode);
flags:
a.O_RDONLY, O_WROLNY, O_RDWR,O_SEARCH,O_EXEC,五个中必须而且只能选择一个
b.下面是可选的:
O_APPEND:写追加,必须是O_WRONLY或者O_RDWR时使用
O_CREAT:若不存在则创建.必须使用mode,实际mode是8进制数与umask的与
O_EXCL:必须Q_CREAT | Q_EXCL使用,如果已存在会报错
O_DIRECTORY:目录
O_ NOFOLLOW:不是符号连接
O _NOBLOCK:若文件是FIFO,块,字,则非阻塞
O_TRUNC:文件写打开时,截断为0
O_SYNS:等待write等物理操作完成
O_DSYNC:同O_SYNC,但写不影响读时,无需等待
O_RSYNC read 等待所有写入同一区域的写操作完成后再进行
open()或openat()打开的是未用的最小fd,
例子:
#include
<fcntl.h>
#include
<stdio.h>
#include <unistd.h>
int
main(
int argc,
char*argv[])
{
//open
int fd;
const
char *fileName=
"tempfile";
int flags_open=O_WRONLY|O_CREAT|O_EXCL;
mode_t mode_open=
0644;
fd=
open(fileName,flags_open,mode_open);
if(-
1==fd)
{
perror(
"open error");
return -
1;
}
else
{
printf(
"fd: %d open
\n
",fd);
close(fd);
}
return
0;
}
sun@sun-PC:~/Downloads/linux/UNIX环境高级编程.tar/apue.3e/fileio$ gcc opentest.c
sun@sun-PC:~/Downloads/linux/UNIX环境高级编程.tar/apue.3e/fileio$ ./a.out
fd: 3 open
sun@sun-PC:~/Downloads/linux/UNIX环境高级编程.tar/apue.3e/fileio$ ./a.out
open error: File exists
3.creat()
#include
<fcntl.h>
int
creat(
const
char* name,
mode_t mode);
==>
int
open(name,O_WRONLY|O_CREAT|O_TRUNC,mode);
4.close()
#include
<unistd.h>
int
close(
int fd);
当一个进程结束,内核会自动close所有文件
5.lseek()
#include
<unistd.h>
#include
<fcntl.h>
int
lseek(
int fd,
off_t offset,
int whence);
whence offset
SEEK_SET 非负,开始处偏移
SEEK_CUR 正负零,当前位置偏移
SEEK_END 正负零,末尾偏移
例子:
#include
"apue.h"
#include
<fcntl.h>
char buf1[] =
"abcdefghij";
char buf2[] =
"ABCDEFGHIJ";
int
main(
void)
{
int fd;
if ((fd =
creat(
"file.hole", FILE_MODE)) <
0)
err_sys(
"creat error");
if (
write(fd, buf1,
10) !=
10)
err_sys(
"buf1 write error");
/* offset now = 10 */
if (
lseek(fd,
16384, SEEK_SET) == -
1)
err_sys(
"lseek error");
/* offset now = 16384 */
if (
write(fd, buf2,
10) !=
10)
err_sys(
"buf2 write error");
/* offset now = 16394 */
exit(
0);
}
6.read
/*
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
参数:从fd里最多读count个字节到buf
返回值:读到:返回实际读取字节
读到最后:返回0
错误:返回-1
*/
#include
<unistd.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<fcntl.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<strings.h>
int
main(
void)
{
int fd;
ssize_t size;
char buf[
1024];
fd=
open(
"readtest.c",O_RDONLY);
if(fd==-
1)
{
perror(
"open error");
exit(
1);
}
do{
bzero(buf,
1024);
size=
read(fd,buf,
1024);
if(size==-
1)
{
perror(
"read error");
exit(
1);
}
printf(
"%s",buf);
}
while(size>
0);
exit(
0);
}
7.write
/*
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
返回值与count相同成功,不然出错
*/
#include
<unistd.h>
#include
<fcntl.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<stdlib.h>
#include
<stdio.h>
int
main(
int argc,
char
const *argv[])
{
int fd;
ssize_t size;
char buf[]=
"Hello World!
\n
";
fd=
open(
"tmp.txt",O_WRONLY|O_CREAT|O_APPEND,
0666);
if(fd==-
1)
{
perror(
"open error");
exit(
1);
}
size=
write(fd,buf,
sizeof(buf));
if(size!=
sizeof(buf))
{
perror(
"write error");
exit(
1);
}
return
0;
}
8.IO效率
read(),write()的buf长度和磁盘块长度相同最佳,ext文件系统为4096
9.文件共享
不同进程操作同一个文件,文件描述符可能不同,分别有一个文件表项,文件表项由文件偏移量和v节点(i节点)组成,不同进程的文件偏移量不同,但是v节点相同,节点信息(包括所有者,打开方式,文件长度等)相同.
10.原子操作
1.追加到一个文件
原子操作是一个函数完成的,不能调用另外一个函数,因为随时可能挂起
open()时使用O_APPEND是原子操作,而lseek(fd,0,SEEK_END)后写不是原子操作
2.函数pread和pwrite
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
先lseek再读写,并且保证原子性
3.创建文件
open(fd,O_WRONLY|O_CREAT|O_EXCL)是原子的
11.dup和dup2
/*
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
#define _GNU_SOURCE
#include <fcntl.h>
#include <unistd.h>
int dup3(int oldfd, int newfd, int flags);
*/
#include
<unistd.h>
#include
<stdio.h>
#include
<fcntl.h>
#include
<sys/types.h>
#include
<sys/stat.h>
#include
<string.h>
int
main(
int argc,
char
const *argv[])
{
int fd,flags,ret;
if(argc!=
3)
{
printf(
"argc !=3
\n
");
_exit(
1);
}
if(
strcmp(argv[
1],
"y")!=
0 &&
strcmp(argv[
1],
"yy")!=
0)
{
printf(
"argv[1] != > or >>
\n
");
_exit(
1);
}
if(
strcmp(argv[
1],
"yy")!=
0)
{
flags=O_RDWR|O_CREAT|O_TRUNC;
}
else
{
flags=O_RDWR|O_CREAT|O_APPEND;
}
fd=
open(argv[
2],flags,S_IRUSR|S_IWUSR);
if(fd==-
1)
{
perror(
"open error");
_exit(
1);
}
ret=
dup2(fd,STDOUT_FILENO);
//argv[2]的文件描述符为1了
if(ret==-
1)
{
perror(
"dup2 error");
_exit(
1);
}
close(fd);
//这个文件描述符用不到了
printf(
"STDOUT
\n
");
fflush(stdout);
close(STDOUT_FILENO);
return
0;
}
12.sync,fsync.fdatasync
#include <unistd.h>
void sync(void);
int fsync(int fd);
int fdatasync(int fd);
sync:将缓冲区排入队列
fsync:等待向fd写操作完成才返回
fdatasync:只关注fd的数据部分更新完成
13.fcntl