首页 > 编程学习 > Linus 文件处理(三)

Linus 文件处理(三)

发布时间:2022/11/27 10:53:33

目录

一、前言

二、扫描目录

1、opendir

2、readdir

3、telldir

4、seekdir

5、 closedir

6、A Directory-Scanning Program

三、Errors

1、strerror

2、perror


一、前言

本文将简单介绍Linux文件和目录,以及如何操作它们(如何创建文件、打开、读、写和关闭,程序如何操作目录,如创建、扫描和删除目录等)。本文大部分内容将会介绍处理文件和目录的各种调用,涵盖了与文件相关的部分主题:(1)文件和设备;(2)系统调用;(3)库函数;(4)低级文件访问;(5)管理文件;(6)标准I/O库;(7)格式化的输入和输出;(8)文件和目录维护;(9)扫描目录;(10)错误;(11)/proc文件系统;(12)fcntl 和 mmap。这些内容本博客不会全部介绍,只是进行部分的基础介绍。

二、扫描目录

Linux 系统上的一个常见问题是扫描目录,也就是说,确定驻留在特定目录中的文件。

在 shell 程序中,这很简单——只要让 shell 展开通配符表达式即可。过去,不同的 UNIX 变体都允许对低级文件系统结构进行编程访问。我们仍然可以将目录作为常规文件打开并直接读取目录条目,但是不同的文件系统结构和实现使得这种方法不可移植。现在已经开发了一套标准的库函数,使目录扫描更加简单。

目录函数的头文件是 dirent.h,它们使用一个结构 DIR 作为目录操作的基础。指向这个结构的指针称为目录流 (DIR *),其作用与文件流 (file *) 用于常规文件操作的方式非常相似。目录条目本身以 dirent 结构返回,也在 dirent.h 中声明,因为不应该直接更改 DIR 结构中的字段。

我将复习以下函数:

❑ opendir, closedir

❑ readdir

❑ telldir

❑ seekdir

❑ closedir

1、opendir

opendir 函数的作用是:打开目录并建立目录流。如果成功,它将返回一个指向 DIR 结构的指针,用于读取目录条目。

opendir 失败时返回空指针。注意,目录流使用低级文件描述符来访问目录本身,因此如果打开的文件太多,opendir 可能会失败。

2、readdir

readdir 函数返回一个指向结构的指针,该结构详细描述了目录中的下一个目录条目流 dirp。连续调用 readdir 返回更多的目录条目。如果出现错误,并且在目录的末尾,readdir 返回 NULL。兼容 posix 的系统在目录末尾返回 NULL 时保留 errno 不变,并在发生错误时设置它。

注意,如果同时有其他进程在该目录中创建和删除文件,则 readdir 扫描不能保证列出该目录中的所有文件(和子目录)。包含目录条目详细信息的 direct 结构包括以下条目:

要确定目录中文件的进一步细节,需要调用 stat。

3、telldir

telldir 函数返回一个值,该值记录目录流中的当前位置。我们可以在后续调用 seekdir 时使用此命令将目录扫描重置到当前位置。

4、seekdir

seekdir 函数在 dirp 给出的目录流中设置目录入口指针。用于设置位置的 loc 值应该已经从之前对telldir 的调用中获得。

5、 closedir

closedir 函数关闭目录流并释放与之关联的资源。成功时返回 0,出错时返回 -1。

在下一个程序 printdir.c 中,我们将把许多文件操作函数组合在一起,以创建一个简单的目录列表。目录中的每个文件单独列在一行上。每个子目录的名称后面都有一个斜杠,其中列出的文件缩进 4 个空格。该程序将一个目录更改为子目录,以便它找到的文件具有可用的名称,也就是说,它们可以直接传递到 opendir。程序在嵌套很深的目录结构上会失败,因为打开的目录流的数量是有限制的。

当然,我们可以通过使用命令行参数来指定起点,从而使其更通用。查看诸如 ls 这样的实用程序的 Linux 源代码,并找到关于更通用实现的想法。

6、A Directory-Scanning Program

从适当的头文件开始,然后是 printdir 函数,它打印出当前目录。它将使用缩进的深度参数递归子目录。

#include<unistd.h>
#include<stdio.h>
#include<dirent.h>
#include<string.h>
#include<sys/stat.h>
#include<stdlib.h>

void printdir(char *dir,int depth)
{
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;

    if((dp=opendir(dir))==NULL){
        fprintf(stderr,"cannot open directory:%s \n",dir);
        return ;
    }
    chdir(dir);
    while((entry=readdir(dp))!=NULL){
        lstat(entry->d_name,&statbuf);
        if(S_ISDIR(statbuf.st_mode)){
            /* Found a directory, but ignore . and .. */
            if(strcmp(“.”,entry->d_name)==0||strcmp(“..”,entry->d_name) == 0)
                continue;
            printf("%*s%s/\n",depth,"",entry->d_name);
            /* Recurse at a new indent level */
            printdir(entry->d_name,depth+4);
        }
        else printf("%*s%s\n",depth,"",entry->d_name);
    }
    chdir("..");
    closedir(dp);
}

int main()
{
    printf("Directory scan of /home:\n");
    printdir("/home",0);
    printf("done.\n");

    exit(0);
}

该程序扫描主目录并产生如下的输出。要查看其他用户的目录,可能需要超级用户权限。

当然该代码还可以改进一些,但这里不再进行讨论。

三、Errors

许多系统调用和函数都可能由于许多原因而失败。当出现这种情况时,它们通过设置外部变量 errno 的值来指示失败的原因。许多不同的库使用此变量作为报告问题的标准方法。值得重复的是,程序必须在给出问题的函数之后立即检查 errno 变量,因为它可能被调用的下一个函数覆盖,即使该函数本身没有失败。

错误的值和含义列在头文件 errno.h 中。它们包括:

有两个有用的函数可以在发生错误时报告错误: strerror 和 perror。

1、strerror

strerror 函数将错误号映射为描述已发生错误类型的字符串。这对于记录错误条件很有用。

2、perror

perror 函数还将 errno 中报告的当前错误映射为字符串,并将其打印到标准错误流中。它的前面是字符串 s 中给出的消息(如果不是NULL),后面是冒号和空格。

以上,Linus 文件处理(三)

祝好


 

Copyright © 2010-2022 dgrt.cn 版权所有 |关于我们| 联系方式