Linux下用C/C++访问目录下文件

前言:笔者没有抓住本科大把大把的时光认真学习编程,读研了只能遇到什么问题找什么解决方案。因此打算用博客的方式把遇到的问题和解决问题的方法记录下来,不仅有利于自己今后回顾,也算是以一种传递技术的方式感谢帮助过我的网友,以及看过的精品博文的博主。

问题背景

笔者最近在学习Caffe深度学习框架,在建立lmdb格式的数据集时,需要新建一个txt文件,在里面每行以“图片文件名 种类编号”的格式建立一个列表,用于接下来调用脚本建立lmdb数据集。而深度学习数据集往往都是成千上万量级的,笔者的数据集也是自己搜集、经人工分类的独一无二的数据集,原始数据根据类别存放在不同文件夹中。因此产生了读取文件夹中所有文件的需求。

问题描述

系统:Ubuntu 16.04
语言:C/C++
要求:读取指定文件夹下所有文件,并输出文件名。

解决方案

利用dirent库
dirent简介

dirent是Linux下的一个头文件,其位置在/usr/include/,为获取某文件夹内的目录内容提供接口
头文件引用:#include <dirent.h>

dirent结构体

该结构体用于表示文件夹下读取的文件。
dirent结构体定义如下:

struct dirent
{
	long d_ino; 			/* inode number 索引节点号 */
	off_t d_off; 			/* offset to this dirent 在目录文件中的偏移 */
	unsigned short d_reclen; 				/* length of this d_name 文件名长 */
	unsigned char d_type;					/* the type of d_name 文件类型 */
	char d_name [NAME_MAX+1]; 				/* file name (null-terminated) 文件名,最长256字符 */
}

其中重要的属性有:

  1. d_type属性
    它标示着dirent结构指向的文件的类型。
    类型有:
enum
{
	DT_UNKNOWN = 0,         //未知类型
  # define DT_UNKNOWN DT_UNKNOWN
    DT_FIFO = 1,            //管道
  # define DT_FIFO DT_FIFO
    DT_CHR = 2,             //字符设备
  # define DT_CHR DT_CHR
    DT_DIR = 4,             //目录
 # define DT_DIR DT_DIR
    DT_BLK = 6,             //块设备
 # define DT_BLK DT_BLK
    DT_REG = 8,             //常规文件
 # define DT_REG DT_REG
    DT_LNK = 10,            //符号链接
 # define DT_LNK DT_LNK
    DT_SOCK = 12,           //套接字
 # define DT_SOCK DT_SOCK
    DT_WHT = 14             //链接
 # define DT_WHT DT_WHT
 };

一般的文件即常规文件,因为直接将文件夹内所有文件都读取的话,也会将一些特殊的非常规文件读取,例如文件夹(包括正常文件夹,和 . 和 … 这两个特殊文件夹),所以常通过判断d_type属性的值来确认是否需要处理当前文件。

  1. d_name属性
    表示dirent结构体变量指向的文件的名称,是字符串。
DIR结构体

该结构体用于指示要操作的文件夹
DIR结构体定义如下:

struct __dirstream
{
	void *__fd; 		/* `struct hurd_fd' pointer for descriptor.   */
	char *__data; 		/* Directory block.   */
	int __entry_data; 	/* Entry number `__data' corresponds to.   */
	char *__ptr; 		/* Current pointer into the block.   */
	int __entry_ptr; 	/* Entry number `__ptr' corresponds to.   */
	size_t __allocation; 	/* Space allocated for the block.   */
	size_t __size; 		/* Total valid data in the block.   */
	__libc_lock_define (, __lock) 	/* Mutex lock for this structure.   */
};
typedef struct __dirstream DIR;

这个结构体没有什么太多好讲的,主要用于接受接下来要讲的函数的返回值,指示特定的文件夹。

opendir()函数

函数原型:DIR* opendir (const char * path );
参数:要指示的文件夹名

  • 在linux系统下,目录都用/符号隔开,举例:dir = opendir("/home/nvidia/Pictures/");
  • 在windows下,目录用\符号隔开,但由于\符号常用于转义,比如\n,\t等,因此目录需要用\隔开,举例:dir = open("F:\\Documents\\example\\");
    返回值:函数返回一个DIR类型的指针,指向参数中给出的具体文件夹地址。
closedir()函数

函数原型:int closedir(DIR *dir);
参数:指向已经打开的文件夹的DIR类型的指针
返回值:

  • 关闭成功返回0
  • 关闭失败返回1
使用举例
#include <dirent.h>
#include <iostream>
#include <fstream>			// 用于执行文件操作的库

using namespace std;
int main(int argc, char **argv)
{
    ofstream out("lists.txt");	// 在当前目录建立一个lists.txt的文本文件,如果已有则覆盖
    if(!out.is_open())
    {
        perror("failed to open the lists.txt");
        return -1;
    }
    
// 进入正题
    DIR *dir;	
    struct dirent *ent;
    
    dir = opendir(".");
    if(dir != NULL)
    {
        while((ent = readdir(dir)) != NULL)
        {
            if(ent->d_type == 8)		// 仅操作常规文件
            {
            	cout << ent->d_name << endl;				// 在屏幕上打印文件名
                out << ent->d_name << " "<<argv[1]<<endl;	// 这里解决了问题背景部分提出的问题,读者可以删去这行,自行编写处理程序。
            }
        }
        closedir(dir);
        out.close();		// 关闭刚才创建的文本文件
    }
    else
    {
        perror("fail to open the directory");
        return EXIT_FAILURE;
    }
    cout << "operate successfully!"<<endl;
    return 0;
}
利用c++17的特性

这里仅给出引文[3]中的一种方法,笔者未尝试过,给有兴趣的读者尝试

#include <string>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;

int main()
{
    std::string path = "/path/to/directory";
    for (const auto & entry : fs::directory_iterator(path))
        std::cout << entry.path() << std::endl;
}

引用

[1] 百度百科,dirent词条
[2] Linux下DIR,dirent,stat等结构体详解(转)
[3] How can I get the list of files in a directory using C or C++?

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值