linux系统编程(六) linux文件系统的操作(下)

简介: linux系统编程(六) linux文件系统的操作

2.6 truncate函数


截断文件长度成指定长度。常用来拓展文件大小,代替lseek。
int truncate(const char *path, off_t length); 
       成功:0;
       失败:-1 设置errno为相应值
       int ftruncate(int fd, off_t length);


2.7 link函数

思考,为什么目录项要游离于inode之外,画蛇添足般的将文件名单独存储呢??这样的存储方式有什么样的好处呢?
  其目的是为了实现文件共享。Linux允许多个目录项共享一个inode,即共享盘块(data)。不同文件名,在人类眼中将它理解成两个文件,但是在内核眼里是同一个文件。
link函数,可以为已经存在的文件创建目录项(硬链接)。
int link(const char *oldpath,  const char *newpath);    成功:0;失败:-1设置errno为相应值
  注意:由于两个参数可以使用“相对/绝对路径+文件名”的方式来指定,所以易出错。
  如:link("../abc/a.c", "../ioc/b.c")若a.c,b.c都对, 但abc,ioc目录不存在也会失败。
  mv命令既是修改了目录项,而并不修改文件本身。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
int main(int argc,char *argv[])
{
        link(argv[1],argv[2]);
        unlink(argv[1]);
        return 0;
}


2.8 unlink函数


删除一个文件的目录项;
int unlink(const char *pathname);   成功:0;失败:-1设置errno为相应值
练习:编程实现mv命令的改名操作            【imp_mv.c】
  注意Linux下删除文件的机制:不断将st_nlink -1,直至减到0为止。无目录项对应的文件,将会被操作系统择机释放。(具体时间由系统内部调度算法决定)
  因此,我们删除文件,从某种意义上说,只是让文件具备了被释放的条件。
unlink函数的特征:清除文件时,如果文件的硬链接数到0了,没有dentry对应,但该文件仍不会马上被释放。要等到所有打开该文件的进程关闭该文件,系统才会挑时间将该文件释放掉。    【unlink_exe.c】
/*
 * unlink函数是删除一个dentry
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
int main(void)
{
        int fd,ret;
        char *p = "test of unlink\n";
        char *p2 = "after write something.\n";
        fd = open("temp.txt",O_RDWR|O_CREAT|O_TRUNC,0644);
        if(fd<0){
                perror("open temp error");
                exit(1);
        }
        ret = unlink("temp.txt");
        if(ret<0){
                perror("unlink error");
                exit(1);
        }
        ret = write(fd,p,strlen(p));
        if(ret == -1){
                perror("----write error");
        }
        printf("hi!I'm printf\n");
        ret = write(fd,p2,strlen(p2));
        if (ret == -1){
                perror("----write error");
        }
        printf("Enter anykey continue\n");
        getchar();
        close(fd);
        return 0;
}
~                                                                                                  
~


2.9 隐式回收


当进程结束运行时,所有该进程打开的文件会被关闭,申请的内存空间会被释放。系统的这一特性称之为隐式回收系统资源。


2.10 symlink函数


创建一个符号链接
int symlink(const char *oldpath, const char *newpath);  成功:0;失败:-1设置errno为相应值


2.11 readlink函数


读取符号链接文件本身内容,得到链接所指向的文件名。
ssize_t readlink(const char *path, char *buf, size_t bufsiz);   成功:返回实际读到的字节数;
失败:-1
设置errno为相应值。


2.12 rename函数


重命名一个文件。
int rename(const char *oldpath, const char *newpath); 成功:0;失败:-1设置errno为相应值


3.目录操作


工作目录:“./”代表当前目录,指的是进程当前的工作目录,默认是进程所执行的程序所在的目录位置。


3.1 getcwd函数


获取进程当前工作目录  (卷3,标库函数)
    char *getcwd(char *buf, size_t size); 
    成功:buf中保存当前进程工作目录位置。
    失败返回NULL。


3.2 chdir函数

改变当前进程的工作目录
  int chdir(const char *path);  成功:0;失败:-1设置errno为相应值
  练习:获取及修改当前进程的工作目录,并打印至屏幕。         【imp_cd.c】


3.3 文件、目录权限


注意:目录文件也是“文件”。其文件内容是该目录下所有子文件的目录项dentry。 可以尝试用vim打开一个目录。

1670994608313.jpg

目录设置黏住位:若有w权限,创建不变,删除、修改只能由root、目录所有者、文件所有者操作。


3.4 opendir函数


根据传入的目录名打开一个目录 (库函数)    DIR * 类似于 FILE *
  DIR *opendir(const char *name);   成功返回指向该目录结构体指针,失败返回NULL 
    参数支持相对路径、绝对路径两种方式:
    例如:打开当前目录:
    ① getcwd() , opendir() 
    ② opendir(".");


3.5 closedir函数


关闭打开的目录
int closedir(DIR *dirp);  成功:0;失败:-1设置errno为相应值


3.6 readdir函数


读取目录  (库函数)
  struct dirent *readdir(DIR *dirp);  成功返回目录项结构体指针;失败返回NULL设置errno为相应值
  需注意返回值,读取数据结束时也返回NULL值,所以应借助errno进一步加以区分。
  struct 结构体:
           struct dirent {
               ino_t          d_ino;      inode编号
               off_t          d_off;       
               unsigned short  d_reclen;    文件名有效长度
               unsigned char   d_type;     类型(vim打开看到的类似@*/等)
               char          d_name[256];文件名
           };
  其成员变量重点记忆两个:d_ino、d_name。实际应用中只使用到d_name。
  练习1:实现简单的ls功能。            
  练习2:实现ls不打印隐藏文件。每5个文件换一个行显示。        
  拓展1:实现ls -a -l 功能。
拓展2:统计目录及其子目录中的普通文件的个数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <dirent.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){
                if((strcmp(sdp->d_name,".")==0))
                        continue;
                printf("%s\t",sdp->d_name);
        }
        printf("\n");
        closedir(dp);
        return 0;
}
~                                                                                                  
~                                                                                                  
~                                                                                                  
~                                                                                                  
~                                                                                                  
~


3.7 rewinddir函数


回卷目录读写位置至起始。
void rewinddir(DIR *dirp);  返回值:无。


3.8 telldir/seekdir函数


获取目录读写位置
  long telldir(DIR *dirp); 成功:与dirp相关的目录当前读写位置。失败-1,设置errno
  修改目录读写位置
  void seekdir(DIR *dirp, long loc); 返回值:无
  参数loc一般由telldir函数的返回值来决定。


4.递归遍历目录


查询指定目录,递归列出目录中文件,同时显示文件大小。        【ls_R.c】
#include <dirent.h>
void isfile(char *name);
void read_dir(char *dir,void (*func)(char *))
{
        char path[256];
        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;
                }
                sprintf(path,"%s/%s",dir,sdp->d_name);
                (*func)(path);  
        }
        closedir(dp);
        return ;
}
void isfile(char *name)
{
        int ret ;
        struct stat sb;
        ret = stat(name,&sb);
        if(ret == -1){
                perror("stat error");
                return;
        }
        if(S_ISDIR(sb.st_mode)){
                read_dir(name,isfile);
        }
        else{
        printf("%20s\t%ld\n",name,sb.st_size);
        }
        return;


5.重定向


dup 和 dup2函数
  int dup(int oldfd); 
  成功:返回一个新文件描述符;
  失败:-1设置errno为相应值
        int dup2(int oldfd, int newfd);

1670994703084.jpg

1670994711550.jpg

重定向示
记忆方法两种:
1. 文件描述符的本质角度理解记忆。
2. 从函数原型及使用角度,反向记忆。
练习:借助dup函数编写mycat程序,实现cat file1 > file2 命令相似功能。

 

【mycat.c】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
        int fd = open(argv[1],O_RDONLY);
        int newfd = dup(fd);
        printf("newfd = %d\n",newfd);
        return 0;
}
~                                                                                                  
~
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.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("-------------------------886");
        return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.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);
        printf("newfd = %d\n",newfd);
        int newfd2 = fcntl(fd1,F_DUPFD,7);
        printf("newfd2 = %d\n",newfd2);
        int ret = write(newfd2,"YYYYYY",7);
        printf("ret = %d\n",ret);
        return 0;
}
~                                                                                                  
~                                                                                                  
~                                                                                                  
~
相关文章
|
2天前
|
存储 运维 监控
深入Linux基础:文件系统与进程管理详解
深入Linux基础:文件系统与进程管理详解
33 8
|
1天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
10 3
|
1天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
8 3
|
4天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
15 6
|
1天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
9 2
|
4天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
21 5
|
5天前
|
监控 网络协议 算法
Linux内核优化:提升系统性能与稳定性的策略####
本文深入探讨了Linux操作系统内核的优化策略,旨在通过一系列技术手段和最佳实践,显著提升系统的性能、响应速度及稳定性。文章首先概述了Linux内核的核心组件及其在系统中的作用,随后详细阐述了内存管理、进程调度、文件系统优化、网络栈调整及并发控制等关键领域的优化方法。通过实际案例分析,展示了这些优化措施如何有效减少延迟、提高吞吐量,并增强系统的整体健壮性。最终,文章强调了持续监控、定期更新及合理配置对于维持Linux系统长期高效运行的重要性。 ####
|
6月前
|
NoSQL Unix Linux
Linux下的系统编程——守护进程、线程(十二)
Linux下的系统编程——守护进程、线程(十二)
71 0
Linux下的系统编程——守护进程、线程(十二)
|
6月前
|
存储 Linux Shell
Linux系统编程(守护进程)
Linux系统编程(守护进程)
74 0
|
NoSQL Ubuntu Unix
linux系统编程(十)守护进程、线程(上)
linux系统编程(十)守护进程、线程
272 0
linux系统编程(十)守护进程、线程(上)