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;
}
~                                                                                                  
~                                                                                                  
~                                                                                                  
~
相关文章
|
7天前
|
存储 缓存 数据管理
深入理解 Linux 文件系统的层次结构
【4月更文挑战第30天】 本文旨在探讨和解析 Linux 操作系统中文件系统的结构与原理。不同于通常的摘要,我们将直接深入到文件系统的核心概念,包括其目录结构、关键组件以及它们如何相互作用以支持 Linux 操作系统的功能。通过剖析文件系统的层次性设计,我们能够更好地理解其在数据管理、用户权限控制和系统安全性方面的重要性。
|
23小时前
|
存储 Linux Shell
Linux文件系统
Linux文件系统
9 2
|
1天前
|
存储 移动开发 Linux
Linux系统之部署h5ai目录列表程序
【5月更文挑战第3天】Linux系统之部署h5ai目录列表程序
11 1
|
2天前
|
安全 Linux 数据安全/隐私保护
深入理解 Linux 文件系统的权限控制
【5月更文挑战第5天】本文旨在详细解析 Linux 操作系统中文件系统权限的核心机制。通过分析用户、组和其他人在文件及目录上拥有的读、写、执行权限,我们探讨了如何实现对系统资源的精确控制。文章还将介绍如何使用命令行工具来修改和管理这些权限,以及权限如何在安全策略和系统管理中扮演关键角色。
|
6天前
|
运维 监控 Linux
提升系统稳定性:Linux内核参数调优实战
【5月更文挑战第1天】 在运维领域,保障服务器的高效稳定运行是核心任务之一。Linux操作系统因其开源、可靠和灵活的特点被广泛应用于服务器中。本文将深入探讨通过调整Linux内核参数来优化系统性能,提升服务器的稳定性和响应能力。文章首先介绍了内核参数调优的必要性和基本原则,然后详细阐述了调优过程中的关键步骤,包括如何监控当前系统状态,确定性能瓶颈,选择合适的参数进行调优,以及调优后的测试与验证。最后,文中提供了一些常见问题的解决策略和调优的最佳实践。
28 5
|
6天前
|
Linux
Linux系统ps命令
这些是一些常见的 `ps`命令选项和用法,用于查看系统中运行的进程及其相关信息。您可以根据需要选择合适的选项以满足您的任务要求。
18 0
|
7天前
|
存储 负载均衡 网络协议
在Linux中优化系统性能的实用指南
【4月更文挑战第30天】本文是关于Linux系统性能优化的指南,涵盖硬件选择、系统及软件更新、调整Swap分区、内核参数优化、使用性能分析工具、文件系统优化、网络服务优化和定期维护等方面。通过这些方法,可提升系统响应速度,降低资源消耗,延长硬件寿命。注意,优化需根据具体系统和应用需求进行。
|
7天前
|
弹性计算 Shell Linux
|
7天前
|
存储 缓存 Linux
linux几种典型应用对系统资源使用的特点
【4月更文挑战第22天】几种典型应用对系统资源使用的特点
15 0
|
7天前
|
存储 关系型数据库 MySQL
linux安装MySQL8.0,密码修改权限配置等常规操作详解
linux安装MySQL8.0,密码修改权限配置等常规操作详解