open/close/perror函数
perror返回错误码errno转译的错误信息, 和输入信息同时输出.
umask为权限掩码, 可以重置. 如umask为002, 取反后为775, 与上777结果为775, 主要起到不同类型用户(user, group, others)权限过滤的作用.
// 打开已存在文件
fd = open("hello.c", O_RDWR);
// 新建文件, (0777)&(umask取反)为真实八进制权限
fd = open("myhello", O_RDWR | O_CREAT, 0777);
// 将文件截断为0
fd = open("myhello", O_RDWR | O_TRUNC);
// 创建文件, 如果已存在则截断为0
fd = open("myhello", O_RDWR | O_CREAT | O_TRUNC, 0644);
// 判断文件是否存在, 必须O_CREAT和O_EXCL同时写才能判断
fd = open("myhello", O_RDWR | O_CREAT | O_EXCL, 0777);
if(fd == -1)
{
perror("file open");
exit(1);
}
int ret = close(fd);
if(ret == -1) // 关闭也要测试返回码
{
perror("file close");
exit(1);
}
read/write/lseek函数
另有read,write,lseek函数, 缓冲区通过malloc或者数组提供. ssize_t是一个有符号数, -1失败/0已读完/>0字节数(每次读buf大小). write时加const的是要写的东西.
lseek的whence参数有3个宏, SEEK_SET, SEEK_CUR, SEEK_END, 代表文件指针起始的位置, 在这个基础上增加偏移量offset. lseek可以改变文件指针位置, 获取文件长度和向后拓展文件大小.
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
off_t lseek(int fd, off_t offset, int whence);
read() write()示例
![](https://img.haomeiwen.com/i15969950/d34d9c030bdb845f.png)
lseek()示例, 从末尾向后拓展2000个字节,最后必须要执行一次写操作. 如原文件含Hello, Linux!
占14个字节, 拓展后为2014个字节, 又执行了一次写"a", 共2015个字节. 最后得到的是一个空洞文件, 无法打印, 占位用(如迅雷下载).
truncate()函数不用执行写操作.
![](https://img.haomeiwen.com/i15969950/6c05a24b21fe08e0.png)
stat函数
stat 文件名
输出文件各种元数据, 其中inode号是文件唯一编号.
inode: Linux系统通过inode号(唯一)访问文件, 索引节点inode保存了文件的元数据, 一般是128或256字节, 每2KB就设置一个inode. Linux通过inode信息得到文件数据所在的block.
ls -l, rm都是不追踪软链接的, vi是追踪软链接的.
// 对于软链接, stat(穿透函数)读到的是真实文件大小, lstat读到的只是软链接大小(路径字节数)
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
stat函数传出一个结构体, 里面包含各个信息对应的变量.
其中st_mode共16位, 为4+3+3+3+3, 分别为文件类型+特殊权限位+user权限+group权限+others权限. 通过与上0170000掩码(八进制)可以得到文件类型, 或者类似的与上0000700得到user权限. 文件类型包括套接字, 软连接, 目录, 管道等.
其他函数
access(path, W_OK)
, 返回0代表有写权限
chmod(path, 0755)
, 改变文件权限.
strtol("0755", NULL, 8)
将字符串表示的数字转为八进制, 第二个参数无用
chown(path, uid, gid)
改变文件权限, uid和gid可以在/etc/passwd中查看
truncate(path, length)
若length小于文件实际长度截断, 大于则拓展.
rename(old_path, new_path)
重命名文件
link相关函数
link(old_path, new_path)
创建硬链接, symlink(old_path, new_path)
创建软链接. 硬链接就是普通文件, 指同一个文件不同的文件名, 其inode结点值完全相同, 当rm A, rm B...把一个文件所有的文件名都删光, inode结点对应的链接数为0时, 其数据块才会被回收.
readlink(path, buf, buf_size)
读取软链接的内容
unlink(path)
指定文件成为临时文件, 当进程释放该文件后就删除, 示例如下
![](https://img.haomeiwen.com/i15969950/b536445f505d75ab.png)
dir相关函数
chdir(path)
改变路径
getcwd(buf, sizeof(buf))
输出当前路径
mkdir(pathname, mode)
创建目录, 需要提供权限
rmdir(pathname)
删除空目录
DIR* opendir(const char* name)
打开目录, 成功返回DIR结构指针, 失败返回NULL.
struct dirent* readdir(DIR* dirp)
传入DIR指针, 返回dirent结构体指针. 结构体的d_type成员包含文件类型, 用宏表示(DT_DIR目录, DE_REG普通文件).
使用strcmp(ptr->d_name, ".")==0
来排除根目录, 使用char buf[1024]={0}; sprintf(buf, "%s/%s", root, ptr->d_name)
来拼接字符串.
// 使用如下方式来遍历目录文件数量
DIR* dir = opendir(root);
struct dirent* ptr = NULL;
while((ptr = readdir(dir)) !=NULL) {
排除"."和"..";
目录则递归;
文件则加1;
}
closedir(dir) // 最后一定要关闭目录, 否则无法返回结果
dup/dup2/fcntl
dup(old_fd)
返回文件描述表中没有被占用的最小的文件描述符, 将其指向传入old_fd指向的文件, 返回新分配的fd的编号.
dup2(old_fd, new_fd)
1. 如果new_fd是一个已被打开的fd, 在拷贝前先关闭new_fd, 然后把new_fd指向old_fd指向的文件, 返回new_fd的编号. 2. 如果old_fd和new_fd是同一个fd, 则直接返回old_fd的编号. 本质上是把old_fd处的指针复制给new_fd, 使得二者都指向old_td指向的文件.
int fcntl(int fd, int cmd, long arg)
fcntl可以获取/改变已打开文件的属性, 如读写权限. O_WRONLY文件指针在头部, 会覆盖部分原内容. O_APPEND文件指针在尾部, 会追加在最后.
int flag = fcntl(fd, F_GETFL, 0) //获取文件状态标记.
//使用按位或对权限(整型数)进行操作,
//如设置O_APPEND/O_NONBLOCK(追加写和非阻塞)
flag |= O_APPEND
fcntl(fd, F_SETFL, flag) //将修改后的权限设置进去.
网友评论