文件和目录

来源:互联网 发布:知乎 广场舞大妈 编辑:程序博客网 时间:2024/05/01 08:34
stat、fstat和lstat函数

#include <sys/stat.h>

int stat(const char *restrict pathname , struct stat *restrict buf);

int fstat(int filedes, struct stat *buf);

int lstat(const char *restrict pathname , struct stat *restrict buf);

stat函数返回指定文件有关的信息结构。

fstat函数获取已在描述符filedes上打开文件的有关信息。

lstat函数是当命名的文件是一个符号链接时,返回该符号链接的有关信息。


文件类型

(1)普通文件。

(2)目录文件。这种文件包含了其他文件的名字以及指向与这些文件有关信息的指针。

(3)块特殊文件。这种类型提供对设备带缓冲的访问,每次访问以固定长度为单位进行。

(4)字符特殊文件。这种文件类型提供对设备不带缓冲的访问,每次访问长度可变。

(5)FIFO。这种类型文件用于进程间通信,有时也将其称为命名管道。

(6)套接字。这种类型用于进程间的网络通信。套接字也可用于在一台宿主机上进程之间的非网络通信。

(7)符号链接。这种类型文件指向另一个文件。

POSIX.1允许实现将进程间通信对象(例如,消息队列和信号量等)表示为文件。


设置用户ID和设置组ID

与一个进程相关联的ID有6个或更多。

实际用户ID和实际组ID标识我们究竟是谁。

有效用户ID,有效组ID以及附加组ID决定了我们的文件访问权限。

保存的设置用户ID和保存的设置组ID在执行一个程序时包含了有效用户ID和有效组ID的副本。


文件访问权限

每个文件有9个访问权限位,可将它们分成三类:u表示用户(所有者),g表示组,o表示其他。

(1)当我们用名字打开任一类型的文件时,对该名字中包含的每一个目录,包括它可能隐含的当前工作目录都应具有执行权限。

(2)对于一个文件的读权限决定了我们是否能够打开该文件进行读操作。

(3)对于一个文件的写权限决定了我们是否能够打开该文件进行写操作。

(4)为了在open函数中对一个文件指定O_TRUNC标志,必须对该文件具有写权限。

(5)为了在一个目录中创建一个新文件,必须对该目录具有写权限和执行权限。

(6)为了删除一个现有的文件,必须对包含该文件的目录具有写权限和执行权限。

(7)如果用exec函数中的任何一个执行某个文件,都必须对该文件具有执行权限。


进程每次打开、创建或删除一个文件时,内核进行的测试是:

(1)若进程的有效用户ID是0,则允许访问。

(2)若进程的有效用户ID等于文件的所有者ID,那么:若所有者适当的访问权限位被设置,则允许访问,否则拒绝访问。

(3)若进程的有效组ID或进程的附加组ID之一等于文件的组ID,那么:若组适当的访问权限被设置,则允许访问,否则拒绝访问。

(4)若其他用户适当的访问权限位被设置,则允许访问,否则拒绝访问。


access函数

#include <unistd.h>

int access(const char *pathname, int mode);

mode常量可以取R_OK(读)、W_OK(写)、X_OK(执行)、F_OK(是否存在)


umask函数

为进程设置文件模式创建屏蔽字,并返回以前的值。

#include <sys/stat.h>

mode_t umask(mode_t cmask);


chmod和fchmod函数

更改现有文件的访问权限

#include <sys/stat.h>

int chmod(const char *pathname, mode_t mode);

int fchmod(int filedes, mode_t mode);

chmod函数在指定的文件上进行操作,而fchmod函数则对已打开的文件进行操作。

为了改变一个文件的权限位,进程的有效用户ID必须等于文件的所有者ID,或者该进程必须具有超级用户权限。


文件长度

stat结构成员st_size表示以字节为单位的文件长度。此字段只对普通文件、目录文件和符号链接有意义。

大多数unix系统提供字段st_blksize和st_blocks。其中,第一个是对文件I/O较适合的块长度,第二个是所分配的实际512(不同unix版本不同)字节块数量。


文件中的空洞

普通文件可以包含空洞。空洞是由所设置的偏移量超过文件尾端,并写了某些数据后造成的。

由于空洞的存在,文件的长度可能大于文件所使用的磁盘空间总量。

复制存在空洞的文件时,所有这些空洞都会被填满,其中所有实际数据字节皆填为0。

没空洞的文件所使用的磁盘空间总量大于文件的长度,因为文件系统使用了若干块以存放指向实际数据块的各个指针。


文件截短

#include <unistd.h>

int truncate(const char *pathname, off_t length);

int ftruncate(int filedes, off_t length);

当length大于文件实际长度时会造成文件空洞。


link、unlink、remove和rename函数

#include <unistd.h>

int link(const char *existingpath, const char *newpath);

创建一个指向现有文件的链接。如若newpath已经存在,则返回错误。只创建newpath中的最后一个分量,路径中的其他部分应当已经存在。


int unlink(const char *pathname);

删除目录项,并将由pathname所引用文件的链接计数减1。

只有当链接计数达到0时,该文件的内容才可被删除。如果有进程打开了该文件,其内容也不能被删除。关闭一个文件时,内核首先检查打开该文件的进程数。如果该数达到0,然后内核检查其链接数,如果也为0就删除该文件的内容。

unlink的这种性质经常被程序用来确保即使是在该进程崩溃时,它所创建的临时文件也不会遗留下来。


#include <stdio.h>

int remove(const char *pathname);

用来解除对一个文件或目录的链接。对于文件,其功能与unlink相同。对于目录,其功能与rmdir相同。


int rename(const char *oldname, const char *newname);

根据oldname是指文件还是目录,有几种情况要加以说明:

(1)如果oldname指的是一个文件,那么为该文件或符号链接更名。如果newname已经存在,且不是一个目录,则先将该目录项删除然后将oldname更名为newname。

(2)如果oldname指的是一个目录,那么为该目录更名。如果newname不存在,则它必须引用一个空目录。如果newname存在且为空目录,则先将其删除,然后将oldname更名为newname。

(3)如果oldname或newname引用符号链接,则处理的是符号链接本身,而不是它所引用的文件。

(4)如果oldnmae和newname引用同一文件,则函数不做任何更改而成功返回。


符号链接

符号链接是指向一个文件的间接指针,硬链接直接指向文件的i节点。引入符号链接的原因是为了避开硬链接的一些限制:

硬链接通常要求链接和文件位于同一文件系统中。

只有超级用户才能创建指向目录的硬链接。


symlink和readlink函数

symlink函数创建一个符号链接,成功返回0,失败返回-1。

#include <unistd.h>

symlink(const char *actualpath, const char *sympath);


readlink用于打开一个链接,并读符号链接的内容,成功返回读到的字节数,失败返回-1。

ssize_t readlink(cosnt char *restrict pathname, char *restrict buf, size_t bufsize);


文件的时间

对每个文件保持有三个时间字段,st_atime表示文件数据的最后访问时间,st_mtime表示文件数据的最后修改时间,st_ctime表示i节点状态的最后更改时间。


utime函数

用于更改一个文件的访问和修改时间。

#include <utime.h>

int utime(const char *pathname, const struct utimbuf *times);

struct utimbuf {

time_t actime;
time_t modtime;

}

如果times是一个空指针,则访问时间和修改时间两者都设置为当前时间。调用utime时,st_ctime被自动更新。


mkdir和rmdir函数

用mkdir函数创建目录,用rmdir函数删除空目录。

#include <sys/stat.h>

int mkdir(const char *pathname, mode_t mode);


#include <unistd.h>

int rmdir(const char *pathname);


读目录

#include <dirent.h>

DIR *opendir(const char *pathname);

struct dirent *readdir(DIR *dp);

int closedir(DIR *dp);


chdir、fchdir和getcwd函数

每个进程都有一个当前工作目录,此目录是搜索所有相对路径名的起点。

进程通过调用chdir或fchdir函数可以更改当前工作目录。

#include <unistd.h>

int chdir(const char *pathname);

int fchdir(int filedes);

char *getcwd(char *buf, size_t size);

getcwd函数可以得到当前工作目录完整的绝对路径名。

0 0