目录
1.函数stat、lstat和fstat
调用 stat 函数将通过参数 pstat 返回 pcName 文件的状态信息。
调用 fstat 函数将获得已 在描述符 iFd 上打开文件的有关信息。
lstat 函数类似 stat 函数,但是当传入的文件名是符号 链接名字时,将获得符号链接的相关信息。
#include <sys/stat.h>
int stat(const char *pcName, struct stat *pstat);
int lstat(const char *pcName, struct stat *pstat);
int fstat(int iFd, struct stat *pstat);
函数 stat 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcName 是文件名;
- 输出参数 pstat 返回文件状态信息。
函数 lstat 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcName 是文件名;
- 输出参数 pstat 返回文件状态信息。
函数 fstat 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 iFd 是文件描述符;
- 输出参数 pstat 返回文件状态信息。
调用 stat 函数将通过参数 pstat 返回 pcName 文件的状态信息,调用 fstat 函数将获得已在描述符 iFd 上打开文件的有关信息,lstat 函数类似 stat 函数,但是当传入的文件名是符号 链接名字时,lstat 函数将获得符号链接的相关信息,而不是符号链接所指实际文件的信息(之后的小节将详细说明符号链接)。
参数 pstat 是需要用户提供的一个状态缓冲区,该指针指向 stat 结构体类型缓冲区,这个结构体如下图所示:
接下来,我们重点介绍一下文件模式(st_mode 信息),下图显示了这些类型在 st_mode 中对应的位信息。
所有的文件类型都有访问权限,每个文件有 9 个访问权限位,可将这些访问权限位分成 3 类,如下图所示。
2.函数access
调用该函数可以按文件所有者,测试文件的访问权限。
#include <unistd.h>
int access(const char *pcName, int iMode);
函数 access 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcName 是文件名;
- 参数 iMode 是访问模式。
3.函数umask
调用该函数可以为当前进程设置创建文件时的屏蔽字。
#include <sys/stat.h>
mode_t umask(mode_t modeMask);
函数 umask 原型分析:
- 此函数返回之前的屏蔽字;
- 参数 modeMask 是新的屏蔽字。
umask 函数为当前进程设置文件创建屏蔽字,并返回之前的值,这是一个没有错误值返回的函数。
其中,参数 modeMask 是由下表中列出的常量中的若干个按位“或”构成的。
在进程创建一个新文件或新目录时,就一定会使用文件模式创建屏蔽字(在介绍 open函数、creat 函数时,这两个函数都有一个模式参数,它指定了新文件的访问权限),在文件屏蔽字中为 1 的位,文件中相应的访问权限位一定被关闭,需要注意的是,SylixOS 内核在创建新文件时所有者的读权限不会被屏蔽(这样保证了文件的所有者能够正常读文件)。
下面部分代码展示了 umask 函数的使用方法,创建第一个文件时,umask值为 0,也即不会屏蔽任何权限位,将按内核默认的权限模式创建文件,创建第二个文件时,umask值禁止了组和其他的读、写权限。
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
umask(0);
if (creat("./a.c", FILE_MODE) < 0) {
fprintf(stderr, "create file failed.\n");
return -1;
}
umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
if (creat("./b.c", FILE_MODE) < 0) {
fprintf(stderr, "create file failed.\n");
return -1;
}
4.函数fchmod、chmod
调用 chmod 函数和 fchmod 函数可以改变文件的访问权限。
#include <sys/stat.h>
int fchmod(int iFd, int iMode);
int chmod(const char *pcName, int iMode);
函数 fchmod 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 iFd 是文件描述符;
- 参数 iMode 是要设置的模式。
函数 chmod 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcName 是文件名;
- 参数 iMode 是要设置的模式。
调用 chmod 函数和 fchmod 函数可以改变现有文件的访问权限。chmod 函数在指定的文件上进行操作,fchmod 函数对已打开的文件进行操作。
函数实际使用时可以在文件原来的访问权限基础上添加或删除某个权限,也可以直接设定某些访问权限位。
5.函数unlink、remove
调用 unlink和remove函数可以删除一个文件。
#include <unistd.h>
int unlink(const char *pcName);
函数 unlink 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcName 是要删除的文件名。
调用 unlink 函数可以删除一个文件。删除一个文件需要满足一定的条件,当文件引用计数达到 0 时,文件才可以被删除,当有进程打开了该文件,其不能被删除。删除一个文件时,内核首先检查打开该文件的进程个数,如果个数达到了 0,内核再去检查其引用计数,如果也是 0,那么就删除该文件。
如果参数 pcName 是一个符号链接的名字,此符号链接将被删除,而不是删除该符号链接所引用的文件。
函数 remove 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 file 是要删除的文件名。
6.函数rename
调用该函数可以对文件或者目录进行重命名。
#include <stdio.h>
int rename(const char *pcOldName, const char *pcNewName);
函数 rename 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcOldName 是旧文件名;
- 参数 pcNewName 是改后的文件名。
文件或者目录可以用 rename 函数进行重命名。根据参数 pcOldName 的不同,有下列几种情况需要说明:如果 pcOldName 指向一个非目录文件,则有以下两种情况:
- 如果 pcNewName 已存在,则 pcNewName 不能是一个目录文件;
- 如果 pcNewName 已存在,且不是目录文件,则先将其删除,然后重命名pcOldName。
如果 pcOldName 指向一个目录文件,则有以下两种情况:
- 如果 pcNewName 已存在,则 pcNewName 必须是一个空目录;
- 如果 pcNewName 已存在,则先将其删除,然后重命名 pcOldName。
如果 pcOldName 、 pcNewName 是同一个文件,则函数安静的返回不做任何修改。
7.函数opendir、closedir
调用opendir 函数将以只读的方式打开一个已经存在的目录。
调用 closedir 函数将关闭 dir 指向的目录。
#include <dirent.h>
DIR *opendir(const char *pathname);
int closedir(DIR *dir);
函数 opendir 原型分析:
- 此函数成功返回目录指针,失败返回 NULL 并设置错误号;
- 参数 pathname 是目录名。
函数 closedir 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 dir 是目录指针。
调用 opendir 函数将打开 pathname 指向的目录并返回 DIR 类型的目录指针,这个目录指针指向目录的开始位置。需要注意的是,opendir 函数将以只读的方式打开目录,这意味着,打开的目录必须是存在的,否则将返回 NULL 并设置 errno 为 ENOENT。如果 pathname不是一个有效目录文件,则返回 NULL 并设置 errno 为 ENOTDIR。
调用 closedir 函数将关闭 dir 指向的目录(dir 由 opendir 函数返回)。
8.函数readdir、readdir_r
调用 readdir 函数将返回指定目录的目录信息。
readdir_r 函数是 readdir 函数的可重入实现。
#include <dirent.h>
struct dirent *readdir(DIR *dir);
int readdir_r(DIR *pdir, struct dirent *pdirentEntry, struct dirent **ppdirentResult);
函数 readdir 原型分析:
- 此函数成功返回目录信息指针,失败返回 NULL 并设置错误号;
- 参数 dir 是已打开的目录指针。
函数 readdir_r 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pdir 是已打开的目录指针。
- 输出参数 pdirentEntry 返回目录信息;
- 输出参数 ppdirentResult 指向 pdirentEntry 地址或 NULL。
读取的目录信息都存放在了 dirent 结构体中,结构体信息如下所示:
struct dirent {
char d_name[NAME_MAX + 1]; /* 文件名 */
unsigned char d_type; /* 文件类型 (可能为 DT_UNKNOWN) */
char d_shortname[13]; /* fat 短文件名 (可能不存在) */
……
};
d_name 成员保存了目录中文件的名字,d_type 指示了该文件的类型如下左图所示,文件类型模式位如下右图所示。
通过下面的宏可实现文件类型和文件类型模式位的互转。
IFTODT 宏将类型模式转换成文件类型,DTTOIF 宏将文件类型转换成类型模式。
#include <dirent.h>
unsigned char IFTODT①(mode_t mode);
mode_t DTTOIF(unsigned char dtype);
9.函数mkdir和rmdir
调用 mkdir 函数可以创建一个空目录,调用函数 rmdir 可以删除一个空目录。
#include <sys/stat.h>
int mkdir(const char *dirname, mode_t mode);
int rmdir(const char *pathname);
函数 mkdir 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 dirname 是创建的目录名;
- 参数 mode 是创建模式。
函数 rmdir 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pathname 是目录名。
调用 mkdir 函数可以创建一个空目录,所指定的目录访问权限由 mode 指定,mode 会根据进程的文件模式屏蔽字修改。
调用函数 rmdir 可以删除一个空目录,底层通过调用 unlink 函数实现。
10.函数chdir、fchdir和getcwd
进程调用 chdir 函数或 fchdir 函数可以更改当前工作目录。
调用 getcwd 函数可以获得当前默认的工作路径
每个进程都有一个当前工作目录,此目录是搜索所有相对路径名的起点(不以斜线开始的路径名为相对路径)。
#include <unistd.h>
int chdir(const char *pcName);
int fchdir(int iFd);
char *getcwd(char *pcBuffer, size_t stByteSize);
函数 chdir 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcName 是新的默认目录。
函数 fchdir 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 iFd 是文件描述符。
函数 getcwd 原型分析:
- 此函数成功返回默认目录缓冲区首地址,失败返回 NULL;
- 输出参数 pcBuffer 是默认目录缓冲区;
- 参数 stByteSize 是缓冲区大小。
进程调用 chdir 函数或 fchdir 函数可以更改当前工作目录,chdir 函数用参数 pcName 指定当前的工作目录,fchdir 函数用文件描述符 iFd 来指定当前的工作目录。
因为当前工作目录是进程的一个属性,所以,修改本进程的工作目录并不会影响其他进程的工作目录,这一点值得注意。
调用 getcwd 函数可以获得当前默认的工作路径,此函数必须要有一个足够大的缓冲区来存放返回的绝对路径名再加上一个终止 null 字符,否则返回出错。
当一个应用程序需要在文件系统中返回到它工作的出发点时,getcwd 函数是很有用的。
在更改工作目录前,先调用 getcwd 函数保存当前工作目录,在完成处理后,就可以将之前保存的工作目录作为参数传递给 chdir 函数,返回到文件系统的出发点处。
fchdir 函数提供了一个更为便捷的方法,在更换文件系统中的不同位置前,先调用 open函数打开当前工作目录,然后保存返回的文件描述符,当希望返回原工作目录时,只需要将保存的文件描述符作为参数传递给 fchdir 函数即可。
11.符号链接
open 函数只能打开符号链接指向的文件,所以需要有一种方法打开该符号链接本身,并读取其中的内容,readlink 提供了这种功能。
符号链接是对一个文件的间接指针,任何用户都可以创建指向目录的符号链接。符号链接一般用于将一个文件或整个目录结构定向到系统中另一个位置。
#include <unistd.h>
int symlink(const char * pcActualPath, const char *pcSymPath);
ssize_t readlink(const char *pcSymPath, char *pcBuffer, size_t iSize);
函数 symlink 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcActualPath 是实际链接的目标文件;
- 参数 pcSymPath 是新创建的符号链接文件。
函数 readlink 原型分析:
- 此函数成功返回读取的符号链接内容长度,失败返回-1 并设置错误号;
- 参数 pcSymPath 是要读取的符号链接名;
- 输出参数 pcBuffer 是内容缓冲区;
- 参数 iSize 是缓冲区长度。
SylixOS 可以调用 symlink 函数来创建符号链接,symlink 函数将创建一个指向pcActualPath 的符号链接 pcSymPath,并且 pcActualPath 和 pcSymPath 可以不在同一个文件系统中。
用 open 函数打开文件时,如果传递给 open 函数的文件名参数是一个符号链接,那么open 将跟随符号链接打开指定的文件,如果此文件不存在 open 函数将返回出错,表示文件不存在。
12.文件截断
调用 truncate 函数和 ftruncate 函数可以缩减或者扩展文件长度。
有时我们需要在文件尾端截去一些数据以缩短文件,将一个文件的长度截断为 0 是一个特例,在打开文件时使用 O_TRUNC 标志可以做到这一点。
#include <unistd.h>
int ftruncate(int iFd, off_t oftLength);
int truncate(const char *pcName, off_t oftLength);
函数 ftruncate 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 iFd 是文件描述符;
- 参数 oftLength 是文件长度。
函数 truncate 原型分析:
- 此函数成功返回 0,失败返回-1 并设置错误号;
- 参数 pcName 是文件名;
- 参数 oftLength 是文件长度。
调用 truncate 函数和 ftruncate 函数可以缩减或者扩展文件长度,如果之前的文件长度比oftLength 长,额外的数据会丢失,如果之前的文件长度比指定的长度小,文件长度将扩展,也就是产生文件空洞。ftruncate 函数对用户已经打开的文件进行操作,传入的是文件描述符。