知识点问答
1.什么是文件?文件位置?文件偏移量?目录?链接?硬链接?符号链接?fd?
2.符号链接的缺点与优点以及作用?
文件以及文件系统
Linux系统编程多半以fd来进行文件的打开、操作、关闭以及其他工作
1.regular file
常规文件内含数据的字节,通常会被组织成称为
byte stream
的
linear array
线性数组。文件的长度即为线性数组中字节的数目。
可以对一个文件内任何字节进行读写。始于一个特定的字节(
file position
文件位置 或者
file offset
偏移量)。可以将一个字节写入文件结尾后(中间补上0),但不可以写入文件开头前。文件位置最大值受限于存储其的C数据类型的大小,目前为64位。
可以通过
truncation
(截短)操作来变更一个文件的长度。
文件的引用是通过
inode
进行的,用来存储与文件有关的数据(但就是没有文件名!)inode会有一个独一无二的数值,
inode-
number
2.目录与链接
通过i-number来访问文件会很麻烦而且存在漏洞。将名称与i-node配对,就成为链接。目录只包含名称与inode之间的映射关系。
打开目录名称时,会经过路径中的每个目录项(
directory entry
,
dentry
)以便寻找下一项的inode。Linux内核还会使用一个缓冲区(
dentry cache
)用来存储目录解析的结果,以便能替
temporal locality
提供快速的解析。(特定资源被访问后某段时间内再次被访问的概率高)kernel不允许像对待regular file那样打开并操纵它们,以防止一个简单的错误就毁坏文件系统。
3.硬链接hard link
通过多个链接将不同名称与同一个inode形成映射关系。unlink操作:将一个inode与名称之间的映射关系从目录中移除。inode中存在link count,当值为0时,Linux kernel才会将inode与相关数据从文件系统中实际移除。
4.符号链接symbolic link
能跨越文件系统,会有更多的开销,缺乏透明度。行为类似于shortcut。symlink需要使用特殊的系统调用。
5.特殊文件
被表示成文件的内核对象。
1.character device 设备驱动程序会将字节一个个放入队列,用户空间程序会按顺序一个个读取,无可读取字符时会返回end of file。键盘就是其中的实例。
2.block device 可以自由访问有效的字节。通常作为存储设备,如:硬盘,软盘,光驱闪存等。
3.named pipe 命名管道(又称FIFO)是一种(interprocess communicationIPC)机制。通过文件描述符提供一个通信管道。regular pipe:将一个程序的输出pipe to 另一个程序的输入,其是由系统调用在内存建立的,不存在于文件系统中。named pipe与其类似,但是其访问通过特殊文件FIFO来进行的,无关的进程可以通过访问该文件与命名管道进行通信。
4.socket IPC高级形式,网络通信的基础。
进程
进程是一个执行中的目标码(还包括数据,资源,状态,一个虚拟的计算机),是一个虚拟的抽象对象。Linux内核通过virtual memory 和页面调度(paging)允许多个进程并存于系统中。
线程
一个进程由一个或多个执行的线程(threads of execution)构成。线程是进程内的最小单位。单线程(signal-threaded),多线程(multithreaded)。
进程标识符pid
第一个进程pid为1。一个进程终止不会立即移除,会保留一部分,来等待父进程的listen。一旦父进程打听到,则会完全移除。如果一个已经终止的进程没有父进程的打听,则为zombie进程。
r 4
w 2
x 1
信号signal单向异步通知机制
segmentation fault 分段错误
termi
nal hangup 终端机挂起
错误处理
errno errno.h
POSIX 表示可移植操作系统接口(Portable Operating System Interface ,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准
write
内核会先把数据写入缓冲区,再在合适的时候写入磁盘。
同步化I/0
<unistd.h>
int fsync(int fd);
保证fd所映射的文件数据写入磁盘。会等到数据写入磁盘后才返回(实际上在磁盘缓冲区)
int fdatasync(int fd);
和fsync行为一样,但只会刷新数据,不保证元数据和磁盘是同步的。
返回值:成功0 失败-1
int sync(cvid);
让所有缓冲区与磁盘同步化。LINUX内核会等到所有缓冲区交给磁盘为止。通常执行一次就够了。
O_SYNC 确保调用会执行I/O的同步化。成本太高较少使用
O_DSYNC 和
O_RSYNC
和SYNC类似
O_DIRECT
会绕过page cache直接启动用户空间缓冲区与设备之间的I/O
为了确保目录项的任何变动也能写回磁盘,要对目录项执行(打开目录,获得其fd)fsync。
int close(int fd);
返用于取消fd的映射关系。若文件已经被刷新到磁盘,关闭文件的动作将毫无作用。
返回值:成功0 失败-1
<unistd.h>
<sys/types.h>
off_t lseek(int fd, off_t pos, int origin);
会返回变更后文件的位置,错误:-1
pos = lseek(fd, 0 ,SEEK_CUR);可以得到文件的当前位置。
<unistd.h>
ssize_t pwrite(int fd, void *buf, size_t len, off_t pos);
ssize_t pread(int fd, void *buf, size_t len, off_t pos);
相当于先调用lseek+read、write。不会改变文件指针。也不会在多线程时出现竞争。
返回值:成功:字节数 失败:-1 0:pread表示EPF。pwrite表示写入0个字节
fopen();
r 读取。r+读取和写入
w写入 存在截短为0,不存在则创建。w+读取和写入
a追加 追加, 不存在则创建 。a+读取和追加
Linux中已相同方式处理文本文件和二进制文件,所以是否加b是一样的。
成功:有效FILE指针。失败:NULL。
fdopen(int fd, const char *mode);
将已经打开的fd转换为流。使用w,w+不会截短。若关闭流则会关闭文件描述符。
成功:有效FILE指针。失败:NULL。
int ffcloseall(void)
;会关闭关联到当前进程的所有流
读取一个
int fgetc(FILE *stream);
int ungetc(int c, FILE *stream);
成功:返回c。失败:EOF
读取一行
char *fgets(char *str, int size,FILE stream);
读取size-1个字符。读到一个EOF或者newline(加上\n)字符后就会停止。
成功:返回str。失败:NULL。
为了可移植性size最大为LINE_MAX(POSIX行最大尺寸)
读取二进制数据