前言:
在Linux系统中,文件和目录的操作非常灵活。用户可以通过命令行或者图形界面来进行操作。下面是Linux文件和目录操作的一些常见操作:
目录
一、文件系统
1.inode
2.dentry
二、文件操作
1.stat/lstat:
2.link/unlink:
3.隐式回收。
4.readlink
5.rename
三、目录操作
1.文件目录权限
2.目录操作函数:
(1)opendir:
(2)closedir:
(3)readdir:
(4)rewinddir
(5)telldir/seekdir
3.递归遍历目录
四、重定向:
(1)dup :
(2)dup2:
五、fcntl实现dup描述符
一、文件系统
1.inode
其本质为结构体,存储文件的属性信息。如:权限、类型、大小、时间、用户、盘块位置……也叫作文件属性管理结构,大多数的inode,都存储在磁盘上。
少量常用、近期使用的inode会被缓存到内存中。,
2.dentry
目录项,其本质依然是结构体,重要成员变量有两个{文件名,inode,...},而文件内容(data)保存在磁盘盘块中。
二、文件操作
1.stat/lstat:
stat/lstat 函数:
int stat(const char *path, struct stat *buf);
参数:
path: 文件路径
buf:(传出参数) 存放文件属性。
返回值:
成功: 0
失败: -1 errno
获取文件大小: buf.st_size
#include<stdio.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
struct stat sbuf;
int ret = stat(argv[1],&sbuf);
if(ret == -1){
perror("stat error");
exit(1);
}
printf("file size:%ld\n",sbuf.st_size);
return 0;
}
获取文件类型: buf.st_mode
#include<stdio.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
struct stat sb;
int ret = stat(argv[1],&sb);
if(ret == -1){
perror("stat error");
exit(1);
}
//printf("file size:%ld\n",sbuf.st_size);
if(S_ISREG(sb.st_mode)){
printf("It is a regular\n");
}else if(S_ISDIR(sb.st_mode)){
printf("It is a dir\n");
}else if(S_ISFIFO(sb.st_mode)){
printf("It is a pipe\n");
}else if(S_ISLNK(sb.st_mode)){
printf("It is a sym link\n");
}
return 0;
}
获取文件权限: buf.st_mode
符号穿透:stat会。lstat不会。
#include<stdio.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
struct stat sb;
int ret = lstat(argv[1],&sb);
if(ret == -1){
perror("stat error");
exit(1);
}
//printf("file size:%ld\n",sbuf.st_size);
if(S_ISREG(sb.st_mode)){
printf("It is a regular\n");
}else if(S_ISDIR(sb.st_mode)){
printf("It is a dir\n");
}else if(S_ISFIFO(sb.st_mode)){
printf("It is a pipe\n");
}else if(S_ISLNK(sb.st_mode)){
printf("It is a sym link\n");
}
return 0;
}
文件权限位图:
2.link/unlink:
link 函数,可以为已经存在的文件创建目录项(硬链接)
mv命令既是修改了目录项,而并不修改文件本身。↓
unlink:删除一个目录的文件项
#include<stdio.h>
#include <unistd.h>
int main(int argc,char *argv[])
{
link(argv[1],argv[2]);
unlink(argv[1]);
return 0;
}
3.隐式回收。
当进程结束运行时,所有该进程打开的文件会被关闭,申请的内存空间会被释放。系统的这一特性称之为隐式回收系统资源。
4.readlink
读取符号链接文件本身内容,得到链接所指向的文件名。
ssiz...t readlink(const char*path, char*buf, size_t bufsiz);
成功:返回实际读到的字节数;
失败:-1设置errno为相应值。
5.rename
重命名一个文件。
int rename(const char*oldpath, const char*newpath);
成功: 0;
失败: -1设置errno.为相应值。
和实现前面的myMv效果相同
三、目录操作
1.文件目录权限
注意:
目录文件也是“文件”。其文件内容是该目录下所有子文件的目录项dentry。可以尝试用vim打开一个目录。
目录设置黏住位:
若有w权限,创建不变,删除、修改只能由root、目录所有者、文件所有者操作。
用vi查看目录: vi 目录 查看到的是:目录项
*2.目录操作函数:
(1)opendir:
根据传入的目录名打开一个目录(库函数)
语法:DIR *opendir(const char *name);
成功返回指向该目录结构体指针
失败返回NULL
(2)closedir:
关闭打开目录
语法:int closedir(DIR*dirp);
成功:0;
失败: -1设置errno为相应值。
(3)readdir:
读取目录(库函数)
语法:struct dirent*readdir(DIR*dirp);
成功返回目录项结构体指针;
失败返回NULL设置errno为相应值
需注意返回值,读取数据结束时也返回NULL值,所以应借助errno.进
步加以区分
struct dirent *readdir(DIR * dp);
struct dirent {
inode
char dname[256];
};
(4)rewinddir
回卷目录读写位置至起始。,
语法:void rewinddir(DIR*dirp);返回值:无。
(5)telldir/seekdir
获取目录读写位置,
语法:long telldir(DlR *dirp);
成功:与dirn.相关的目录当前读写位置。
失败-1,设置errno.
修改目录读写位置
void seekdir(DIR*dirp, long loc);
返回值:无,
参数loc一般由telldir函数的返回值来决定。
#include<stdio.h>
#include<dirent.h>
#include<stdlib.h>
int main(int argc,char *argv[])
{
DIR * dp;
struct dirent *sdp;
dp = opendir(argv[1]);
if(dp == NULL){
perror("opendir error");
exit(1);
}
while((sdp = readdir(dp)) != NULL){
printf("%s\n",sdp->d_name);
}
printf("\n");
closedir(dp);
return 0;
}
*3.递归遍历目录
查询指定目录,递归列出目录中文件,同时显示文件大小
递归遍历目录:ls-R.c
1. 判断命令行参数,获取用户要查询的目录名。 int argc, char *argv[1]
argc == 1 --> ./
2. 判断用户指定的是否是目录。 stat S_ISDIR(); --> 封装函数 isFile() { }
3. 读目录:
read_dir() {
opendir(dir)
while (readdir()){
普通文件,直接打印
目录:
拼接目录访问绝对路径。sprintf(path, "%s/%s", dir, d_name)
递归调用自己。--》 opendir(path) readdir closedir
}
closedir()
}
read_dir() --> isFile() ---> read_dir()
代码预览:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <pthread.h>
void isFile(char *name);
// 打开目录读取,处理目录
void read_dir(char *dir, void (*func)(char *))
{
char path[259];
DIR *dp;
struct dirent *sdp;
dp = opendir(dir);
if (dp == NULL) {
perror("opendir error");
return;
}
// 读取目录项
while((sdp = readdir(dp)) != NULL) {
if (strcmp(sdp->d_name, ".") == 0 || strcmp(sdp->d_name, "..") == 0) {
continue;
}
//fprintf();
// 目录项本身不可访问, 拼接. 目录/目录项
sprintf(path, "%s/%s", dir, sdp->d_name);
// 判断文件类型,目录递归进入,文件显示名字/大小
//isFile(path);
(*func)(path);
}
closedir(dp);
return ;
}
void isFile(char *name)
int ret = 0;
struct stat sb;
// 获取文件属性, 判断文件类型
ret = stat(name, &sb);
if (ret == -1) {
perror("stat error");
return ;
}
// 是目录文件
if (S_ISDIR(sb.st_mode)) {
read_dir(name, isFile);
}
// 是普通文件, 显示名字/大小
printf("%10s\t\t%ld\n", name, sb.st_size);
return;
}
int main(int argc, char *argv[])
{
// 判断命令行参数
if (argc == 1) {
isFile(".");
} else {
isFile(argv[1]);
}
return 0;
}
四、重定向:
(1)dup :
int dup(int oldfd); 文件描述符复制。
oldfd: 已有文件描述符
返回:新文件描述符。
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
int fd = open(argv[1],O_RDONLY);012 ----3
int newfd = dup(fd); //4
printf("newfd = %d\n",newfd);
return 0;
}
*(2)dup2:
int dup2(int oldfd, int newfd); 文件描述符复制。重定向。
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
int fd1 = open(argv[1],O_RDWR);
int fd2 = open(argv[2],O_RDWR);
int fdret = dup2(fd1,fd2);
printf("fdret = %d\n",fdret);
int ret = write(fd2,"-----1234567-----",7);
printf("ret = %d\n",ret);
dup2(fd1,STDOUT_FILENO);
printf("********--------------------********\n");
return 0;
}
五、fcntl实现dup描述符
fcntl 函数实现 dup:
int fcntl(int fd, int cmd, ....)
cmd: F_DUPFD
参3: 被占用的,返回最小可用的。
未被占用的, 返回=该值的文件描述符。
#include<stdio.h>
#include<fcntl.h>
int main(int argc,char *argv[])
{
int fd1 = open(argv[1],O_RDWR);
printf("fd1 = %d\n",fd1);
int newfd = fcntl(fd1,F_DUPFD,0);//0被占用,fcntl使用文件描述符表中的最小文件描述符返回(4)
printf("newfd = %d\n",newfd);
int newfd2 = fcntl(fd1,F_DUPFD,7);//7 未被占用,返回>=7的文件描述符
printf("newfd2 = %d\n",newfd2);
return 0;
}