文件同步:
1、在写入数据时内存与磁盘之间也有一个缓冲区,这种机制降低了磁盘的读写次数,提高了读写的效率
2、这种机制带来的后果就是磁盘中的数据与实际写入的数据不匹配,系统提供了三个函数可以让缓冲区中的数据立即写入到磁盘上
#include <unistd.h>
void sync(void)
功能: 把缓冲区中的数据立即同步到磁盘上
注意: 并不会等待数据全部同步,而是把缓冲区的数据加入写入队列后,立即返回
int fsync(int fd);
功能: 把指定文件的内容从缓冲区同步到磁盘上
注意: 会等到全部写入到磁盘后才返回
返回值: 成功返回0,失败返回-1
int fdatasync(int fd);
功能: 把指定文件的内容从缓冲区同步到磁盘上,只同步文件的内容不同步文件的属性
注意: 会等到全部写入到磁盘后才返回
文件属性
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char* path,struct stat* buf);
功能: 根据文件的路径获取文件的属性
int fstat(int fd,struct stat* buf);
功能: 根据文件描述符获取文件的属性
int lstat(const char* path,struct stat* buf);
功能: 获取软链接文件的文件属性
buf: 存储文件属性的结构体指针,是一个输出型参数
struct stat{
dev_t st_dev; 设备ID
//ID of device containing file
ino_t st_ino; inode 编号
//inode number
(·)mode_t st_mode; 文件的类型和权限
//protection
nlink_t st_nlink; 硬链接数
//number of hard links
uid_t st_uid; 用户ID
//user ID of owner
gid_t st_gid; 组ID
//group ID of owner
dev_t st_rdev; 特殊设备ID号
//device ID (if special file)
(·)off_t st_size; 总字节数
//total size,in bytes
blksize_t st_blksize; IO块字节数
//blocksize for filesystem I/O
blkcnt_t st_blocks; 占用512字节块数
//number of 512B blocks allocated
(·)time_t st_atime; 最后访问时间
//time of last access
time_t st_mtime; 最后内容修改时间
//time of last modification
time_t st_ctime; 最后状态修改时间
//time of last status change
}; 带(·)的常用
在POSIX中,有对于st_mode有以下宏可以判断文件属于哪个类型
S_ISREG(m) 检查是否是普通文件
//is it a regular file?
S_ISDIR(m) 检查是否是目录文件
//directory
S_ISCHR(m) 检查是否是字符设备文件
//character device
S_ISBLK(m) 检查是否是块设备文件
//block device
S_ISFIFO(m) 检查是否是管道文件
//FIFO (named pipe)
S_ISLNK(m) 检查是否是软链接文件
//symbolic link? (Not in POSIX.1-1996.
S_ISSOCK(m) 检查是否是Socket文件
//socket? (Not in POSIX.1-1996.)
S_IFMT 0170000 获取文件类型的掩码
//bit mask for the file type bit fields
S_IFSOCK 0140000 socket文件
//socket
S_IFLNK 0120000 软链接文件
//symbolic link
S_IFREG 0100000 普通文件
//regular file
S_IFBLK 0060000 块设备文件
//block device
S_IFDIR 0040000 目录文件
//directory
S_IFCHR 0020000 字符设备文件
//character device
S_IFIFO 0010000 管道文件
//FIFO
S_ISUID 0004000 设置用户ID
//set-user-ID bit
S_ISGID 0002000 设置组ID
//set-group-ID bit (see below)
S_ISVTX 0001000
//sticky bit (see below)
S_IRWXU 00700 用户权限掩码
//mask for file owner permissions
S_IRUSR 00400 用户读权限掩码
//owner has read permission
S_IWUSR 00200 用户写权限掩码
//owner has write permission
S_IXUSR 00100 用户执行权限掩码
//owner has execute permission
S_IRWXG 00070 用户组权限掩码
//mask for group permissions
S_IRGRP 00040 用户组读权限掩码
//group has read permissio
S_IWGRP 00020 用户组写权限掩码
//group has write permission
S_IXGRP 00010 用户组执行权限掩码
//group has execute permission
S_IRWXO 00007 其他用户权限掩码
//mask for permissions for others (not in group)
S_IROTH 00004 其他用户读权限掩码
//others have read permission
S_IWOTH 00002 其他用户写权限掩码
//others have write permission
S_IXOTH 00001 其他用户执行权限掩码
//others have execute permission
文件权限
#include <unistd.h>
int access(const char* pathname,int mode);
功能: 测试当前用户对文件有哪些权限
pathname: 文件路径
mode: 想要测试的权限
F_OK 文件是否存在
R_OK 是否有写权限
W_OK 是否有读权限
X_OK 是否有执行权限
返回值: 存在则返回0,不存在返回-1
注意: 如果文件不存在,测试RWX权限也会返回-1
#include <sys/stat.h>
int chmod(const char* path,mode_t mode);
功能: 根据文件路径修改文件权限
path: 文件路径
mode: 由三位的八进制数组成的权限码
0644 普通文件
0755 执行文件
int fchmod(int fd,mode_t mode);
功能: 根据文件描述符修改文件权限
path: 文件路径
mode: 由三位的八进制数组成的权限码
0644 普通文件
0755 执行文件
权限屏蔽码:
如果我们不让新创建的文件具有某些权限,可以通过设置权限屏蔽码进行过滤
通过命令 umask 可以查看当前终端的权限屏蔽码
通过命令 umask 0xxx 可以修改当前终端的权限屏蔽码
注意: 权限屏蔽码对于chmod/fchmod函数和命令无效
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
功能: 设置当前进程的权限屏蔽码
mask 想要设置的权限屏蔽码
返回值: 返回旧的权限屏蔽码
注意: 该函数的设置只对当前进程有效,进程结束后就失效
修改文件大小
#include <unistd.h>
#include <sys/types.h>
int truncate(const char* path,off_t length);
功能: 根据文件的路径截取文件的大小
length: 想要截取成的字节数大小
int ftruncate(int fd,off_t length);
功能: 根据文件描述符截取文件的大小
length: 想要截取成的字节数大小
练习1: 实现一个函数,可以删除文件的第[n,m)个字节
int del_file(const char* path,size_t n,size_t m)
删除和重命名
#include <stdio.h>
int remove(const char* pathname);
功能: 标准库中的删除文件函数,底层调用unlink
#include <unistd.h>
int unlink(const char* pathname);
功能: 删除文件
#include <stdio.h>
int rename(const char* oldpath, const char* newpath);
功能: 重命名文件
链接文件
Linux的文件系统会把分区主要分为两大部分:
inode信息块: (默认128b)记录了文件的权限、大小、所有者、最后修改时间等信息、以及对应的block块的位置信息
block块: (默认4k)记录了文件名和真正的数据信息
每个文件必须拥有唯一 一个inode以及若干个block,读取文件时,需要借助目录的block中记录的文件名找到该文件的inode号,通过inode读取到该文件的block
什么是软硬链接文件
硬链接: 硬链接文件没有自己的inode和block,只是在不同目录下复制了一份源文件的inode信息,可以通过inode访问到源文件的同一份block
软链接: 软链接文件会建立自己的新的inode和block,而软链接文件的block中存储的是源文件的文件名和inode号
区别:
1、当修改硬链接文件内容时,源文件以及其他的硬链接文件也会被修改,而软链接不会
2、当删除源文件,只是删除了源文件的inode,硬链接文件不受影响,但软链接文件无法访问源文件
3、当硬链接数被删除被0时,文件才算是被真正的删除了
4、软链接可以链接目录,硬链接不可以
5、软链接可以跨文件系统,硬链接不行
#include <unistd.h>
int link(const char* oldpath,
const char* newpath);
功能: 创建硬链接文件
int symlink(const char* oldpath,
const char* newpath);
功能: 创建软链接文件
ssize_t readlink(const char* path,
char* buf,size_t bufsiz); (symlink.c)
功能: 读取软链接文件数据,而非链接目标数据,读取的其实是链接的路径
buf: 是一个输出型参数,获取链接路径
bufsize: 获取的字节数
目录操作
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char* pathname,mode_t mode);
功能: 创建目录
mode: 目录的权限 注意: 必须要有执行权限,否则无法进入
#include <unistd.h>
int rmdir(const char* pathname);
功能: 删除空目录
int chdir(const char* path);
功能: 进入某个目录,相当于cd命令
char* getcwd(char* buf,size_t size);
功能: 获取当前工作目录,相当于pwd命令
#include <sys/types.h>
#include <dirent.h>
DIR* opendir(const char* name);
功能: 打开目录文件,返回一个目录流
DIR* fdopendir(int fd);
#include <dirent.h>
struct dirent* readdir(DIR* dirp);
功能: 从目录流中读取一条记录
struct dirent{
ino_t d_ino; //i节点号
off_t d_off; //下一条条目的偏移量
unsigned short d_reclen; //当前条目的长度
unsigned char d_type; //文件类型
DT_BLK 块设备文件
DT_CHR 字符设备文件
DT_DIR 目录文件
DT_FIFO 管道文件
DT_LNK 链接文件
DT_REG 普通文件
DT_SOCK socket文件
DT_UNKNOWN 未知类型
char d_name[256]; //文件名
}
练习1: 实现 ls -l 功能
#include <dirent.h>
void seekdir(DIR* dirp,long loc);
功能: 设置目录流的位置指针,用于随机读取
#include <sys/types.h>
#include <dirent.h>
void rewinddir(DIR* dirp);
功能: 设置目录流的位置指针到开头
#include <dirent.h>
long telldir(DIR* dirp);
功能: 获取当前目录流的位置指针位置
作业: 实现 rm -rf 功能(建议备份一下虚拟机文件,重点关注. ..两个目录的删除)
day06 task.c