标准流描述符:
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
打开、创建、关闭文件:
#define O_ACCMODE 0003 /* O_ACCMODE = O_RDONLY | O_WRONLY | O_RDWR */
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_CREAT 0100 /* open() 第 3 个参数指定权限位 */
#define O_EXCL 0200
#define O_NOCTTY 0400
#define O_TRUNC 01000
#define O_APPEND 02000
#define O_NONBLOCK 04000 /* 非阻塞 */
#define O_SYNC 04010000
#define O_FSYNC O_SYNC
#define O_ASYNC 020000
#define O_DIRECTORY __O_DIRECTORY /* 打开非目录出错 */
#define O_NOFOLLOW __O_NOFOLLOW /* 打开符号链接出错 */
#define O_CLOEXEC __O_CLOEXEC /* exec() 时关闭 */
int open (const char *__file, int __oflag, ...);
int openat (int __fd, const char *__file, int __oflag, ...);
// open(__file, O_WRONLY | O_CREAT | O_TRUNC, __mode)
int creat (const char *__file, mode_t __mode);
int close (int __fd);
移动指针:
#define SEEK_SET 0 /* Seek from beginning of file. */
#define SEEK_CUR 1 /* Seek from current position. */
#define SEEK_END 2 /* Seek from end of file. */
__off_t lseek (int __fd, __off_t __offset, int __whence);
__off64_t lseek64 (int __fd, __off64_t __offset, int __whence);
读写(注意原子操作):
ssize_t read (int __fd, void *__buf, size_t __nbytes);
ssize_t pread (int __fd, void *__buf, size_t __nbytes, __off_t __offset);
ssize_t write (int __fd, const void *__buf, size_t __n);
ssize_t pwrite (int __fd, const void *__buf, size_t __n, __off_t __offset);
文件共享:
int dup (int __fd);
int dup2 (int __fd, int __fd2); // 先关闭 fd2, 再复制 fd -> fd2
刷新内部缓冲:
void sync (void); // 只写入队列,不等待磁盘 I/O
int fsync (int __fd); // 等待磁盘 I/O,更新数据和属性
int fdatasync (int __fildes); // 等待磁盘 I/O,只更新数据
fcntl()和ioctl():
#define F_DUPFD 0 /* Duplicate file descriptor. */
#define F_DUPFD_CLOEXEC 1030 /* Duplicate file descriptor with close-on-exit set. */
#define F_GETFD 1 /* Get file descriptor flags. */
#define F_SETFD 2 /* Set file descriptor flags. */
#define F_GETFL 3 /* Get file status flags. */
#define F_SETFL 4 /* Set file status flags. */
#define F_SETOWN __F_SETOWN /* Get owner (process receiving SIGIO). */
#define F_GETOWN __F_GETOWN /* Set owner (process receiving SIGIO). */
int fcntl (int __fd, int __cmd, ...);
int ioctl (int __fd, unsigned long int __request, ...);
/dev/fd:
每个进程看到的都不一样,例如:
# ls -l /dev/fd/ > a.txt # cat a.txt total 0 lrwx------. 1 root root 64 May 20 16:34 0 -> /dev/pts/0 l-wx------. 1 root root 64 May 20 16:34 1 -> /root/a.txt lrwx------. 1 root root 64 May 20 16:34 2 -> /dev/pts/0 lr-x------. 1 root root 64 May 20 16:34 3 -> /proc/6259/fd
习题3.2 自己实现一个dup2():
int mydup2 (int fd, int fd2) {
int fd_close[20] = { 0 };
int fd_temp;
if(fd == fd2) {
return fd2;
}
close(fd2);
while((fd_temp = dup(fd)) != fd2) {
fd_close[fd_temp] = 1;
}
for(int i = 0; i < (sizeof fd_close / sizeof fd_close[0]); i ++) {
if(fd_close[i]) {
close(i);
}
}
return fd2;
}
习题3.3 考虑下边代码,显然 fd1 和 fd2 指向同一个 vnode:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int fd11 = open("a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
int fd12 = dup(fd11);
int fd21 = open("a.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
// abcdefg
write(fd11, "abcdefg", 7);
lseek(fd11, 0, SEEK_SET);
// xxxxxxx
write(fd12, "xxxxxxx", 7);
// xxxxxxxyyyyyyy
lseek(fd21, 0, SEEK_END);
write(fd21, "yyyyyyy", 7);
// xxxxxxxaaaaaaa
write(fd11, "aaaaaaa", 7);
return 0;
}
习题3.6 以下代码说明可以任意位置读,写入总在尾部追加:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
char buffer[4] = { 0 };
int fd = open("a.txt", O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0644);
write(fd, "abcdefg", 7);
lseek(fd, 2, SEEK_SET);
printf("%d\n", read(fd, buffer, 3));
printf("%s\n", buffer);
printf("%d\n", write(fd, "xxx", 3));
return 0;
}