什么是文件描述符
https://www.computerhope.com/jargon/f/file-descriptor.htm#:~:text=A%20file%20descriptor%20is%20a,Grants%20access.
https://zhuanlan.zhihu.com/p/143847169
A file descriptor is a number that uniquely identifies an open file in a computer's operating system. It describes a data resource, and how that resource may be accessed.
When a program asks to open a file — or another data resource, like a network socket — the kernel:
- Grants access.
- Creates an entry in the global file table.
- Provides the software with the location of that entry.
The descriptor is identified by a unique non-negative integer, such as 0, 12, or 567. At least one file descriptor exists for every open file on the system.
File descriptors were first used in Unix, and are used by modern operating systems including Linux, macOS, and BSD. In Microsoft Windows, file descriptors are known as file handles.
Overview
When a process makes a successful request to open a file, the kernel returns a file descriptor which points to an entry in the kernel's global file table. The file table entry contains information such as the inode of the file, byte offset, and the access restrictions for that data stream (read-only, write-only, etc.).
Question: What is indode?
https://www.bluematador.com/blog/what-is-an-inode-and-what-are-they-used-for
In a Unix-style file system, an index node, informally referred to as an inode, is a data structure used to represent a filesystem object, which can be one of various things including a file or a directory. Each inode stores the attributes and disk block location(s) of the filesystem object's data.[1] Filesystem object attributes may include manipulation metadata (e.g. change,[2] access, modify time), as well as owner and permission data (e.g. group-id, user-id, permissions).[3]
A Linux directory lists other filesystem objects by name, normally identifying the listed object by referring to its inode. The directory contains an entry for itself, its parent, and each of its children.
文件描述符里存放的内容就是一个指向文件表的指针。
Linux中文件描述符的定义
struct fd { struct file *file;//指向文件表的指针 unsigned int flags; }
它所指向的结构体file就是我们所说的文件表。下面我们来看一下file的源码
struct file { union { struct llist_node fu_llist; struct rcu_head fu_rcuhead; } f_u; struct path f_path;//文件的存放路径 struct inode *f_inode; /* cached value */ const struct file_operations *f_op;//指向结构体file_operations的指针 /* * Protects f_ep_links, f_flags. * Must not be taken from IRQ context. */ spinlock_t f_lock; atomic_long_t f_count;//文件引用计数 unsigned int f_flags;//文件状态标记符 fmode_t f_mode; struct mutex f_pos_lock; loff_t f_pos;//文件读写位置 struct fown_struct f_owner; const struct cred *f_cred; struct file_ra_state f_ra; u64 f_version; #ifdef CONFIG_SECURITY void *f_security; #endif /* needed for tty driver, and maybe others */ void *private_data; #ifdef CONFIG_EPOLL /* Used by fs/eventpoll.c to link all the hooks to this file */ struct list_head f_ep_links; struct list_head f_tfile_llink; #endif /* #ifdef CONFIG_EPOLL */ struct address_space *f_mapping; } __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */
这个结构中包含了文件的一些基本信息。
其中几个比较重要的有
struct path f_path:文件存放的路径,它通过目录表(dentry)找到inode的目录。
const struct file_operations *f_op:指向文件操作表的指针,这个表里面存放了对文件的操作函数例如:read,write…..
struct inode *f_inode:指向inode的指针,inode存放了从磁盘上读上来的信息。
atomic_long_t f_count:文件的引用计数,当引用计数为零的时候文件就关闭了。所以,同时也允许多个多个进程打开一个文件。
unsigned int f_flags:存放了文件的状态,例如只读,只写,或者可读可写。
loff_t f_pos:存放当前文件读写的位置。
Stdin, stdout, and stderr
On a Unix-like operating system, the first three file descriptors, by default, are STDIN (standard input), STDOUT (standard output), and STDERR (standard error).
Name | File descriptor | Description | Abbreviation |
---|---|---|---|
Standard input | 0 | The default data stream for input, for example in a command pipeline. In the terminal, this defaults to keyboard input from the user. | stdin |
Standard output | 1 | The default data stream for output, for example when a command prints text. In the terminal, this defaults to the user's screen. | stdout |
Standard error | 2 | The default data stream for output that relates to an error occurring. In the terminal, this defaults to the user's screen. | stderr |
Redirecting file descriptors
File descriptors may be directly accessed using bash, the default shell of Linux, macOS X, and Windows Subsystem for Linux.
For example, when you use the find command, successful output goes to stdout (file descriptor 1), and error messages go to stderr (file descriptor 2). Both streams display as terminal output:
find / -name '*something*'
/usr/share/doc/something /usr/share/doc/something/examples/something_random find: `/run/udisks2': Permission denied find: `/run/wpa_supplicant': Permission denied /usr/share/something /usr/games/something
We're getting errors because find is trying to search a few system directories that we don't have permission to read. All the lines that say "Permission denied" were written to stderr, and the other lines were written to stdout.
You can hide stderr by redirecting file descriptor 2 to /dev/null, the special device in Linux that "goes nowhere":
find / -name '*something*' 2>/dev/null
/usr/share/doc/something /usr/share/doc/something/examples/something_random /usr/share/something /usr/games/something
The errors sent to /dev/null, and are not displayed.
Understanding the difference between stdout and stderr is important when you want to work with a program's output. For example, if you try to grep the output of the find command, you'll notice the error messages are not filtered, because only the standard output is piped to grep.
find / -name '*something*' | grep 'something'
/usr/share/doc/something /usr/share/doc/something/examples/something_random find: `/run/udisks2': Permission denied find: `/run/wpa_supplicant': Permission denied /usr/share/something /usr/games/something
However, you can redirect standard error to standard output, and then grep will process the text of both:
find / -name '*something*' 2>&1 | grep 'something'
/usr/share/doc/something /usr/share/doc/something/examples/something_random /usr/share/something /usr/games/something
Notice that in the command above, the target file descriptor (1) is prefixed with an ampersand ("&"). For more information about data stream redirection, see pipelines in the bash shell.
For examples of creating and using file descriptors in bash, see our exec builtin command examples.