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;
}
~                                                                                                  
~                                                                                                  
~                                                                                                  
~
相关文章
|
1天前
|
关系型数据库 MySQL Linux
Linux系统如何设置自启动服务在MySQL数据库启动后执行?
【10月更文挑战第25天】Linux系统如何设置自启动服务在MySQL数据库启动后执行?
22 3
|
1天前
|
Linux Shell
Linux系统
是对Linux系统进行管理的命令。对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的DOS命令类似。linux命令在系统中有两种类型:内置Shell命令和Linux命令。
|
3天前
|
Linux Shell
Linux系统
是对Linux系统进行管理的命令。对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的DOS命令类似。linux命令在系统中有两种类型:内置Shell命令和Linux命令。Linux系统
|
2天前
|
Linux Shell
Linux系统
是对Linux系统进行管理的命令。对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的DOS命令类似。linux命令在系统中有两种类型:内置Shell命令和Linux命令。
|
2天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
4天前
|
Linux Shell
Linux系统
是对Linux系统进行管理的命令。对于Linux系统来说,无论是中央处理器、内存、磁盘驱动器、键盘、鼠标,还是用户等都是文件,Linux系统管理的命令是它正常运行的核心,与之前的DOS命令类似。linux命令在系统中有两种类型:内置Shell命令和Linux命令。
|
4天前
|
存储 安全 关系型数据库
Linux系统在服务器领域的应用与优势###
本文深入探讨了Linux操作系统在服务器领域的广泛应用及其显著优势。通过分析其开源性、安全性、稳定性和高效性,揭示了为何Linux成为众多企业和开发者的首选服务器操作系统。文章还列举了Linux在服务器管理、性能优化和社区支持等方面的具体优势,为读者提供了全面而深入的理解。 ###
|
6月前
|
存储 监控 安全
《Linux 简易速速上手小册》第6章: 磁盘管理与文件系统(2024 最新版)
《Linux 简易速速上手小册》第6章: 磁盘管理与文件系统(2024 最新版)
63 1
|
3月前
|
存储 监控 Linux
|
6月前
|
Unix Linux
Linux 常用命令汇总(六):磁盘与文件系统命令
Linux 常用命令汇总(六):磁盘与文件系统命令