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;
}
~                                                                                                  
~                                                                                                  
~                                                                                                  
~
相关文章
|
6天前
|
Linux
Linux系统之whereis命令的基本使用
Linux系统之whereis命令的基本使用
50 23
Linux系统之whereis命令的基本使用
|
6天前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
38 17
|
15天前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
50 26
|
2月前
|
存储 缓存 监控
Linux缓存管理:如何安全地清理系统缓存
在Linux系统中,内存管理至关重要。本文详细介绍了如何安全地清理系统缓存,特别是通过使用`/proc/sys/vm/drop_caches`接口。内容包括清理缓存的原因、步骤、注意事项和最佳实践,帮助你在必要时优化系统性能。
230 78
|
1月前
|
缓存 安全 Linux
Linux系统查看操作系统版本信息、CPU信息、模块信息
在Linux系统中,常用命令可帮助用户查看操作系统版本、CPU信息和模块信息
109 23
|
1月前
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
95 15
|
2月前
|
Ubuntu Unix Linux
Linux网络文件系统NFS:配置与管理指南
NFS 是 Linux 系统中常用的网络文件系统协议,通过配置和管理 NFS,可以实现跨网络的文件共享。本文详细介绍了 NFS 的安装、配置、管理和常见问题的解决方法,希望对您的工作有所帮助。通过正确配置和优化 NFS,可以显著提高文件共享的效率和安全性。
233 7
|
2月前
|
存储 运维 监控
Linux--深入理与解linux文件系统与日志文件分析
深入理解 Linux 文件系统和日志文件分析,对于系统管理员和运维工程师来说至关重要。文件系统管理涉及到文件的组织、存储和检索,而日志文件则记录了系统和应用的运行状态,是排查故障和维护系统的重要依据。通过掌握文件系统和日志文件的管理和分析技能,可以有效提升系统的稳定性和安全性。
57 7
|
2月前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
120 13
|
9月前
|
缓存 Linux 测试技术
安装【银河麒麟V10】linux系统--并挂载镜像
安装【银河麒麟V10】linux系统--并挂载镜像
2615 0