3 系统调用
3.1 文件描述符原理
- 文件描述符的概念
文件标识 inode(整型数, 数组下标)
open
file[inode] -> 文件结构体 -> pos 位置指针
count 打开计数器
文件流会存在一个进程空间的数组中 标准输入输出错误 会占用当前可使用地最小地三个文件描述符。
- 文件IO操作
open, close, read, write, lseek
-
文件IO与标准IO地区别
-
IO效率问题
3.2 open 和 close
- open
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);//变参函数
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);
int openat(int dirfd, const char *pathname, int flags);
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
DESCRIPTION
The argument flags must include one of the following access
modes: O_RDONLY, O_WRONLY, or O_RDWR. These request opening the file
read-only, write-only, or read/write, respectively.
In addition, zero or more file creation flags and file status flags
can be bitwise-or'd in flags. The file creation flags are O_CLOEXEC,
O_CREAT, O_DIRECTORY, O_EXCL, O_NOCTTY, O_NOFOLLOW, O_TMPFILE, and
O_TRUNC. The file status flags are all of the remaining flags listed
below. The distinction between these two groups of flags is that the
file creation flags affect the semantics of the open operation itself,
while the file status flags affect the semantics of subsequent I/O
operations. The file status flags can be retrieved and (in some cases)
modified; see fcntl(2) for details.
flags 参数的实质就是位表,对应到标准IO的打开模式下如下:
------------------------------------------------------------------
r -> O_RDONLY
r+ -> O_RDWR
w -> O_WRONLY|O_CREAT|O_TRUNC
w+ -> O_RDWR|O_TRUNC|O_CREEAT
- close
#include <unistd.h>
int close(int fd);
DESCRIPTION
close() closes a file descriptor, so that it no longer refers to any
file and may be reused. Any record locks (see fcntl(2)) held on the
file it was associated with, and owned by the process, are removed
(regardless of the file descriptor that was used to obtain the lock).
If fd is the last file descriptor referring to the underlying
open file description (see open(2)), the resources associated with the
open file description are freed; if the file descriptor was the last
reference to a file which has been removed using unlink(2), the file
is deleted.
3.3 read 、write 和 lseek
基本原理用法与标准IO相同,是标准IO的支撑。
- read
SYNOPSIS
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
DESCRIPTION
read() attempts to read up to count bytes from file descriptor fd into
the buffer starting at buf.
On files that support seeking, the read operation commences at the
file offset, and the file offset is incremented by the number of bytes
read. If the file offset is at or past the end of file, no bytes are
read, and read() returns zero.
If count is zero, read() may detect the errors described below. In
the absence of any errors, or if read() does not check for errors,
a read() with a count of 0 returns zero and has no other effects.
According to POSIX.1, if count is greater than SSIZE_MAX, the result
is implementation-defined; see NOTES for the upper limit on Linux.
- write
SYNOPSIS
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
DESCRIPTION
write() writes up to count bytes from the buffer starting at buf to
the file referred to by the file descriptor fd.
The number of bytes written may be less than count if, for example,
there is insufficient space on the underlying physical medium, or
the RLIMIT_FSIZE resource limit is encountered (see setrlimit(2)), or
the call was interrupted by a signal handler after having written less
than count bytes. (See also pipe(7).)
For a seekable file (i.e., one to which lseek(2) may be applied, for
example, a regular file) writing takes place at the file offset,
and the file offset is incremented by the number of bytes actually
written. If the file was open(2)ed with O_APPEND, the file offset is
first set to the end of the file before writing. The adjustment of
the file offset and the write operation are performed as an atomic
step.
POSIX requires that a read(2) that can be proved to occur after a
write() has returned will return the new data. Note that not all
filesystems are POSIX conforming.
According to POSIX.1, if count is greater than SSIZE_MAX, the result
is implementation-defined; see NOTES for the upper limit on Linux.
- lseek
SYNOPSIS
#include <sys/types.h>
#include <unistd.h>
off_t lseek(int fd, off_t offset, int whence);
DESCRIPTION
lseek() repositions the file offset of the open file description
associated with the file descriptor fd to the argument offset
according to the directive whence as follows:
SEEK_SET
The file offset is set to offset bytes.
SEEK_CUR
The file offset is set to its current location plus offset
bytes.
SEEK_END
The file offset is set to the size of the file plus offset
bytes.
lseek() allows the file offset to be set beyond the end of the file
(but this does not change the size of the file). If data is later
written at this point, subsequent reads of the data in the gap (a
"hole") return null bytes ('\0') until data is actually written into
the gap.
文件IO没有缓存区相应速度快,标准IO有缓冲区吞吐量大。
标准IO与文件IO不可混用。
time 命令
指令运行的时间。
4 文件共享
- 一个程序打开两次同一个文件。
- 两个进程打开同一个文件。
- 两个进程打开同一个文件。。
- truncate
SYNOPSIS
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
DESCRIPTION
The truncate() and ftruncate() functions cause the regular file named
by path or referenced by fd to be truncated to a size of precisely
length bytes.
If the file previously was larger than this size, the extra data is
lost. If the file previously was shorter, it is extended, and the
extended part reads as null bytes ('\0').
The file offset is not changed.
If the size changed, then the st_ctime and st_mtime fields
(respectively, time of last status change and time of last
modification; see inode(7)) for the file are updated, and the set-
user-ID and set-group-ID mode bits may be cleared.
With ftruncate(), the file must be open for writing; with truncate(),
the file must be writable.
例题:写程序删除文件的第10行。
4.1 原子操作
概念:不可分割的操作。
作用:解决竞争和冲突。
- dup 和 dup2
SYNOPSIS
#include <unistd.h>
int dup(int oldfd);//重定向 非原子
int dup2(int oldfd, int newfd);//重定向 原子
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
int dup3(int oldfd, int newfd, int flags);
DESCRIPTION
The dup() system call creates a copy of the file descriptor
oldfd, using the lowest-numbered unused file descriptor for the new
descriptor.
After a successful return, the old and new file descriptors may be
used interchangeably. They refer to the same open file description
(see open(2)) and thus share file offset and file status flags; for
example, if the file offset is modified by using lseek(2) on one of
the file descriptors, the offset is also changed for the other.
The two file descriptors do not share file descriptor flags (the
close-on-exec flag). The close-on-exec flag (FD_CLOEXEC; see
fcntl(2)) for the duplicate descriptor is off.
dup2()
The dup2() system call performs the same task as dup(), but instead
of using the lowest-numbered unused file descriptor, it uses the file
descriptor number specified in newfd. If the file descriptor newfd
was previously open, it is silently closed before being reused.
The steps of closing and reusing the file descriptor newfd are
performed atomically. This is important, because trying to
implement equivalent functionality using close(2) and dup() would be
subject to race conditions, whereby newfd might be reused between the
two steps. Such reuse could happen because the main program is
interrupted by a signal handler that allocates a file descriptor, or
because a parallel thread allocates a file descriptor.
Note the following points:
* If oldfd is not a valid file descriptor, then the call fails, and
newfd is not closed.
* If oldfd is a valid file descriptor, and newfd has the same value
as oldfd, then dup2() does nothing, and returns newfd.
文件重定向示例:
/**
* 文件重定向 dup dup2
*
* 将标准输出(控制台)重定向到 out 文件
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define FNAME "out"
int main(){
#if 0
int fd;
close(1);
fd = open(FNAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
if (fd < 0){
perror("open()");
exit(-1);
}
#endif
//----------------一下虚线内容同条件注释内容-----------------------
int fd;
fd = open(FNAME, O_WRONLY|O_CREAT|O_TRUNC, 0600);
if (fd < 0){
perror("open()");
exit(-1);
}
/* 以下注释内容非原子 可以被打断 */
//close(1);
//dup(fd);
//close(fd);
/* 原子操作 */
dup2(fd, 1);
if (fd != 1){
close(fd);
}
//---------------------------------------------------------------
/*******************************************************/
puts("hello!");
return 0;
}
4.2 同步 sync 和 syncfs
- sync syncfs
同步数据,刷内核buf,接触挂载
同步文件只刷数据不刷亚数据。
SYNOPSIS
#include <unistd.h>
void sync(void);
int syncfs(int fd);
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
sync():
_XOPEN_SOURCE >= 500
|| /* Since glibc 2.19: */ _DEFAULT_SOURCE
|| /* Glibc versions <= 2.19: */ _BSD_SOURCE
syncfs():
_GNU_SOURCE
DESCRIPTION
sync() causes all pending modifications to filesystem metadata and
cached file data to be written to the underlying filesystems.
syncfs() is like sync(), but synchronizes just the filesystem
containing file referred to by the open file descriptor fd.
RETURN VALUE
syncfs() returns 0 on success; on error, it returns -1 and sets errno
to indicate the error.
- fcntl
SYNOPSIS
#include <unistd.h>
#include <fcntl.h>
/* 文件描述符的基础函数 */
int fcntl(int fd, int cmd, ... /* arg */ );
- ioctl
//设备相关内容
SYNOPSIS
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
DESCRIPTION
The ioctl() system call manipulates the underlying device
parameters of special files. In particular, many operating
characteristics of character special files (e.g., terminals) may
be controlled with ioctl() requests. The argument fd must be an
open file descriptor.
The second argument is a device-dependent request code. The third
argument is an untyped pointer to memory.
It is traditionally char *argp (from the days before void * was valid
C), and will be so named for this discussion.
An ioctl() request has encoded in it whether the argument is an in
parameter or out parameter, and the size of the argument argp in
bytes. Macros and defines used in specifying an ioctl() request are
located in the file <sys/ioctl.h>.