函数系列
七种文件类型
普通文件类型
Linux中最多的一种文件类型, 包括 纯文本文件(ASCII);二进制文件(binary);数据格式的文件(data);各种压缩文件.第一个属性为 [-]
目录文件
就是目录, 能用 # cd 命令进入的。第一个属性为 [d],例如 [drwxrwxrwx]
块设备文件
块设备文件 : 就是存储数据以供系统存取的接口设备,简单而言就是硬盘。例如一号硬盘的代码是 /dev/hda1等文件。第一个属性为 [b]
字符设备
字符设备文件:即串行端口的接口设备,例如键盘、鼠标等等。第一个属性为 [c]
套接字文件
这类文件通常用在网络数据连接。可以启动一个程序来监听客户端的要求,客户端就可以通过套接字来进行数据通信。第一个属性为 [s],最常在 /var/run目录中看到这种文件类型
管道文件
FIFO也是一种特殊的文件类型,它主要的目的是,解决多个程序同时存取一个文件所造成的错误。FIFO是first-in-first-out(先进先出)的缩写。第一个属性为 [p]
链接文件
类似Windows下面的快捷方式。第一个属性为 [l],例如 [lrwxrwxrwx]
stat
函数原型:
int stat(const char *path, struct stat *buf);
int lstat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
函数说明:
通过文件名filename获取文件信息,并保存在buf所指的结构体stat中
lstat读取的链接文件本身的属性
stat读取的是连接文件指向的文件的属性,能追踪,穿透
fstat和第一个函数的区别是通过文件描述符获取文件属性
返回值:
成功返回0,失败返回-1;
文件属性结构体
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
blksize_t st_blksize; //块大小(文件系统的I/O 缓冲区大小)
blkcnt_t st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};
stat结构体中的st_mode 则定义了下列数种情况:
S_IFMT 0170000 文件类型的位遮罩
S_IFSOCK 0140000 套接字
S_IFLNK 0120000 符号连接
S_IFREG 0100000 一般文件
S_IFBLK 0060000 区块装置
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符装置
S_IFIFO 0010000 先进先出
S_ISUID 04000 文件的(set user-id on execution)位
S_ISGID 02000 文件的(set group-id on execution)位
S_ISVTX 01000 文件的sticky位
S_IRUSR(S_IREAD) 00400 文件所有者具可读取权限
S_IWUSR(S_IWRITE)00200 文件所有者具可写入权限
S_IXUSR(S_IEXEC) 00100 文件所有者具可执行权限
S_IRGRP 00040 用户组具可读取权限
S_IWGRP 00020 用户组具可写入权限
S_IXGRP 00010 用户组具可执行权限
S_IROTH 00004 其他用户具可读取权限
S_IWOTH 00002 其他用户具可写入权限
S_IXOTH 00001 其他用户具可执行权限
上述的文件类型在POSIX中定义了检查这些类型的宏定义:
S_ISLNK (st_mode) 判断是否为符号连接
S_ISREG (st_mode) 是否为一般文件
S_ISDIR (st_mode) 是否为目录
S_ISCHR (st_mode) 是否为字符装置文件
S_ISBLK (s3e) 是否为先进先出
S_ISSOCK (st_mode) 是否为socket
若一目录具有sticky位(S_ISVTX),则表示在此目录下的文件只能被该文件所有者、此目录所有者或root来删除或改名,在linux中,最典型的就是这个/tmp目录啦。
文件属性函数
1. access
函数说明:测试当前用户指定文件是否具有某种属性
函数原型:int access(const char *pathname, int mode);
参数:
pathname: 文件名
mode: 4种权限
R_OK -- 读
W_OK -- 写
X_OK -- 执行
F_OK -- 文件是否存在
返回值:
0 - 有某种权限, 或者文件存在
1 - 没有, 或文件不存在
2. chmod
函数说明:修改文件权限
函数原型:int chmod(const char *filename, int mode);
参数:
filename: 文件名
mode: 文件权限, 八进制数
3. chown
函数说明:修改文件所有者和所属组
函数原型:int chown(const char *path, uid_t owner, gid_t group);
函数参数:
path -- 文件路径
owner -- 整形值, 用户ID ,通过/etc/passwd查阅
group -- ....., 组ID,通过/etc/group查阅
4. truncate
函数说明:修改文件大小
函数原型:int truncate(const char *path, off_t length);
参数:
path -- 文件名
length -- 文件的最终大小
1. 比原来小, 删掉后边的部分
2. 比原来大, 向后拓展
5.unlink
函数说明:unlink()函数功能即为删除文件。执行unlink()函数会删除所给参数指定的文件
函数原型:int unlink(const char *pathname);
参数:所删除的指定文件
返回值:成功返回0,失败返回 -1
注意:
执行unlink()函数并不一定会真正的删除文件,它先会检查文件系统中此文件的连接数是否为1,如果不是1说明此文件还有其他链接对象,因此只对此文件的连接数进行减1操作。若连接数为1,并且在此时没有任何进程打开该文件,此内容才会真正地被删除掉。在有进程打开此文件的情况下,则暂时不会删除,直到所有打开该文件的进程都结束时文件就会被删除。
目录操作相关函数
1. 文件重命名
int rename(const char *oldpath, const char *newpath);
2. 修改当前进程(应用程序)的路径 cd
int chdir(const char *path);
参数: 切换的路径
3. 获取当前进程的工作目录 pwd
char *getcwd(char *buf, size_t size);
返回值:
成功: 当前的工作目录
失败: NULL
参数:
buf: 缓冲区, 存储当前的工作目录
size: 缓冲区大小
4. 创建目录 mkdir
int mkdir(const char *pathname, mode_t mode);
参数:
pathname: 创建的目录名
mode: 目录权限, 八进制的数, 实际权限:
mode & ~umask
5. 删除一个空目录
int rmdir(const char *pathname);
参数: 空目录的名字
目录遍历相关函数
1. 打开一个目录
DIR *opendir(const char *name);
参数: 目录名
返回值: 指向目录的指针
2. 读目录
struct dirent
{
ino_t d_ino; // 此目录进入点的inode
ff_t d_off; // 目录文件开头至此目录进入点的位移
signed short int d_reclen; // d_name 的长度, 不包含NULL 字符
unsigned char d_type; // d_name 所指的文件类型
har d_name[256]; // 文件名
};
d_type
DT_BLK - 块设备
DT_CHR - 字符设备
DT_DIR - 目录
DT_LNK - 软连接
DT_FIFO - 管道
DT_REG - 普通文件
DT_SOCK - 套接字
DT_UNKNOWN - 未知
函数原型:struct dirent *readdir(DIR *dirp);
参数: opendir的返回值
返回值: 目录项结构体
具体使用: while((denp=readdir(dp))!=NULL)
3. 关闭目录
int closedir(DIR *dirp);
代码
读取指定目录下普通文件的个数
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
//定义函数,读指定目录中文件的个数
int get_file_num(const char* root)
{
int total=0;
//读目录
DIR* dir=NULL;
dir=opendir(root);
if(dir==NULL)
{
perror("opendir error");
exit(1);
}
//循环读目录中的文件
struct dirent* ptr=NULL;
while((ptr=readdir(dir))!=NULL)
{
//不处理.和..目录
if(strcmp(".",ptr->d_name)==0|| strcmp("..",ptr->d_name)==0)
{
continue;
}
//判断是否是普通文件
if(ptr->d_type==DT_REG)
{
total++;
}
//如果是目录的话,进行递归处理
if(ptr->d_type==DT_DIR)
{
//求出子目录
char path[1024]={0};
sprintf(path,"%s/%s",root,ptr->d_name);
total+=get_file_num(path);
}
}
//关闭目录
close(dir);
return total;
}
int main(int argc,const char* argv[])
{
if(argc<2)
{
printf("./a.out path\n");
exit(1);
}
int total=get_file_num(argv[1]);
printf("%s 目录下普通文件共 %d 个\n",argv[1],total);
return 0;
}
dup/dup2函数
函数说明:复制文件描述符
dup()和dup2()函数都可以用来复制一个文件描述符
int dup(int oldfd);
参数:oldfd - 要复制的文件描述符
返回值: 新的文件描述符,取最小的且没被占用的文件描述符
dup调用成功后,有两个文件描述符指向同一个文件
int dup2(int oldfd, int newfd);
oldfd原来指向文件hello
newfd原来指向文件world
假设newfd已经指向了一个文件,首先断开close与那个文件的连接,newfd指向oldfd指向的文件,这就是文件描述符重定向
注意,如果oldfd和newfd指向同一个文件,那么就不会断开newfd与文件的连接
newfd没有被占用,newfd指向oldfd指向的文件
代码举例
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
int main(void)
{
int fd = open("temp", O_RDWR | O_CREAT | O_APPEND, 0664);
if(fd == -1)
{
perror("open");
exit(1);
}
int fd2 = open("temp1", O_RDWR | O_CREAT | O_APPEND, 0664);
if(fd2 == -1)
{
perror("open open");
exit(1);
}
// 复制文件描述符,fd2也指向temp文件
dup2(fd, fd2);
// 写文件
char* p = "hello,world";
write(fd2, p, strlen(p));
close(fd2);
char buf[1024];
lseek(fd, 0, SEEK_SET);
read(fd, buf, sizeof(buf));
printf(" buf = %s\n", buf);
close(fd);
return 0;
}
fcntl函数
函数说明:改变已经打开的文件的属性
这是一个变参函数,
复制一个已有的文件描述符
int ret = fcntl(fd, F_DUPFD);
获取/设置文件状态标志
获取文件状态标识
int flag = fcntl(fd, F_GETFL)
设置文件状态标识
flag = flag | O_APPEND;
fcntl(fd, F_SETFL, flag)
可以更改的几个标识: O_APPEND、O_NONBLOCK (常用)
命令系列
1.使用命令查看文件类型的三种方法
ls -l、file 文件名、stat
2.ls命令
ls -al
常用参数:
-a, –all 列出目录下的所有文件,包括以 . 开头的隐含文件
-i, –inode 印出每个文件的 inode 号
-l 除了文件名之外,还将文件的权限、所有者、文件大小等信息详细列出来
从左到右依次为:inode节点号,文件类型及权限、属主和所归属的组、最近修改时间、文件或目录名
3.stat命令
- File:显示文件名
- Size:显示文件大小
- Blocks:文件使用的数据块总数
- IO Block:IO块大小
- regular file:文件类型(常规文件)
- Device:设备编号
- Inode:Inode号
- Links:链接数
- Access:文件的权限
- Gid、Uid:文件所有权的Gid和Uid。Linux下的三个时间:
1. Access Time:简写为atime,表示文件的访问时间。当文件内容被访问时,更新这个时间。
2. Modify Time:简写为mtime,表示文件内容的修改时间,当文件的数据内容被修改时,更新这个时间。
3. Change Time:简写为ctime,表示文件的状态时间,当文件的状态被修改时,更新这个时间,例如文件的链接数,大小,权限,Blocks数。
我们都知道touch命令是用来创建文件的,其实它的用法还有一个,就是修改文件的时间戳。
用法:
-a 或–time=atime或–time=access或–time=use 只更改访问时间。 其实文件的状态时间也会改变。
-m 或–time=mtime或–time=modify 只更改修改时间。 其实文件的状态时间也会改变。
4.查找文件相关命令
(1)在某个目录下查找包含某个字符串的文件
grep -r "zh_CN" ./
(2)find [路径] <表达式>
-name <表达式> 根据文件名查找文件
-iname <表达式> 根据文件名查找文件,忽略大小写
-path <表达式> 根据路径查找文件
-ipath <表达式> 根据路径查找文件,忽略大小写
-amin <分钟> 过去N分钟内访问过的文件
-atime <天数> 过去N天内访问过的文件
-cmin <分钟> 过去N分钟内修改过的文件
-ctime <天数> 过去N天内修改过的文件
-anewer <参照文件> 比参照文件更晚被读取过的文件
-cnewer <参照文件> 比参照文件更晚被修改过的文件
-size <大小> 根据文件大小查找文件,单位b c w k M G
-type <文件类型> 根据文件类型查找文件。b 块设备 c 字符设备 d 目录 p 管道文件 f 普通文件 l 链接 s 端口文件
-user <用户名> 按归属用户查找文件
-uid <uid> 按UID查找文件
-group <群组名> 按归属群组查找文件
-gid <gid> 按GID查找文件
-empty 查找空文件
eg:
#find /usr/ -name '*mycat*' 查询文件名中包含mycat的文件所在路径
#find /usr/ -name 'mycat*' 查询文件名以mycat开头的文件所在路径
#find /usr/ -name '*mycat' 查询文件名以mycat结尾的文件所在路径