Linux下的系统编程——文件与目录操作(六)

简介: Linux下的系统编程——文件与目录操作(六)

一、文件系统

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;
  
}


目录
相关文章
|
5月前
|
存储 Linux
Linux 目录名称
Linux系统目录结构简介:根目录(/)下包含各类功能目录,如/bin存放用户命令,/etc存储配置文件,/home为用户主目录,/var记录日志等可变数据,/usr存放用户工具,/tmp用于临时文件。各目录分工明确,保障系统有序运行。(238字)
303 5
|
6月前
|
Ubuntu Linux Anolis
Linux系统禁用swap
本文介绍了在新版本Linux系统(如Ubuntu 20.04+、CentOS Stream、openEuler等)中禁用swap的两种方法。传统通过注释/etc/fstab中swap行的方式已失效,现需使用systemd管理swap.target服务或在/etc/fstab中添加noauto参数实现禁用。方法1通过屏蔽swap.target适用于新版系统,方法2通过修改fstab挂载选项更通用,兼容所有系统。
563 3
Linux系统禁用swap
|
6月前
|
Linux
Linux系统修改网卡名为eth0、eth1
在Linux系统中,可通过修改GRUB配置和创建Udev规则或使用systemd链接文件,将网卡名改为`eth0`、`eth1`等传统命名方式,适用于多种发行版并支持多网卡配置。
1072 3
|
Ubuntu Linux 网络安全
Linux系统初始化脚本
一款支持Rocky、CentOS、Ubuntu、Debian、openEuler等主流Linux发行版的系统初始化Shell脚本,涵盖网络配置、主机名设置、镜像源更换、安全加固等多项功能,适配单/双网卡环境,支持UEFI引导,提供多版本下载与持续更新。
663 3
Linux系统初始化脚本
|
7月前
|
运维 Linux 开发者
Linux系统中使用Python的ping3库进行网络连通性测试
以上步骤展示了如何利用 Python 的 `ping3` 库来检测网络连通性,并且提供了基本错误处理方法以确保程序能够优雅地处理各种意外情形。通过简洁明快、易读易懂、实操性强等特点使得该方法非常适合开发者或系统管理员快速集成至自动化工具链之内进行日常运维任务之需求满足。
481 18
|
6月前
|
安全 Linux Shell
Linux系统提权方式全面总结:从基础到高级攻防技术
本文全面总结Linux系统提权技术,涵盖权限体系、配置错误、漏洞利用、密码攻击等方法,帮助安全研究人员掌握攻防技术,提升系统防护能力。
721 1
|
6月前
|
监控 安全 Linux
Linux系统提权之计划任务(Cron Jobs)提权
在Linux系统中,计划任务(Cron Jobs)常用于定时执行脚本或命令。若配置不当,攻击者可利用其提权至root权限。常见漏洞包括可写的Cron脚本、目录、通配符注入及PATH变量劫持。攻击者通过修改脚本、创建恶意任务或注入命令实现提权。系统管理员应遵循最小权限原则、使用绝对路径、避免通配符、设置安全PATH并定期审计,以防范此类攻击。
1209 1
|
7月前
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
2045 10
|
7月前
|
安全 Linux 数据安全/隐私保护
为Linux系统的普通账户授予sudo访问权限的过程
完成上述步骤后,你提升的用户就能够使用 `sudo`命令来执行管理员级别的操作,而无需切换到root用户。这是一种更加安全和便捷的权限管理方式,因为它能够留下完整的权限使用记录,并以最小权限的方式工作。需要注意的是,随意授予sudo权限可能会使系统暴露在风险之中,尤其是在用户不了解其所执行命令可能带来的后果的情况下。所以在配置sudo权限时,必须谨慎行事。
1260 0
|
7月前
|
Ubuntu Linux 开发者
国产 Linux 发行版再添新成员,CutefishOS 系统简单体验
当然,系统生态构建过程并不简单,不过为了帮助国产操作系统优化生态圈,部分企业也开始用国产操作系统替代 Windows,我们相信肯定会有越来越多的精品软件登录 Linux 平台。
570 0