一种批量读取文件的方法——SHBrowseForFolder

数字图像处理群qq:51701853

在编程过程中,经常涉及到对某一个文件夹下的文件进行批量操作,尤其是在图像处理过程中,需要通过大量样本来进行分类器的训练,因此涉及到图片文件批量读取的问题。在之前的博客中介绍过一种基于csv文件的批量读取方法,在此介绍另外一种方法即SHBrowseForFolder方法,它是MFC框架编程中常用的一种批量文件读取方法,下面结合实例在具体介绍下这个函数的用法。

批量读取文件换句话说就是读取某一个目录下的所有文件,因此需要先创建一个对象来保存用户所选定的目录,具体代码如下:

CString str;//存储图像路径
BROWSEINFO bi;//用来存储用户选中的目录信息
TCHAR name[MAX_PATH];//存储路径

在VC++中BROWSEINFO结构中包含了用户选定目录的重要信息,具体结构参见MSDN。在创建完BROWSEINFO 之后,显示文件夹选择对话框之前,需要对对象bi的一些参数进行设置,以便设计弹出对话框的形式以及变量存储方式,常用的赋值方法如下:

ZeroMemory(&bi,sizeof(BROWSEINFO));//清空目录对应的内存
bi.hwndOwner=GetSafeHwnd();//得到窗口句柄
bi.pszDisplayName=name;//存储目录字符串路径

BIF_BROWSEINCLUDEFILES;
bi.lpszTitle=_T("Select folder");//对话框标题
bi.ulFlags=0x80;//设置对话框形式

对对话框属性设置完成后,就可以弹出对话框让用户选择文件夹了,具体代码如下:

LPITEMIDLIST idl=SHBrowseForFolder(&bi);//返回所选中文件夹的ID

其中LPITEMIDLIST这个结构体涉及到windows文件管理的一些内容,在此可以简单理解为对象idl存储了用户所选中文件夹的全路径,之后我们只需要将其中存储的路径提取出来并保存到字符串对象中即可,具体代码如下:

CString str;//存储图像路径

CStringm_Path;//存储图像路径

SHGetPathFromIDList(idl,str.GetBuffer(MAX_PATH));//将文件信息格式化存储到对应缓冲区中
str.ReleaseBuffer();//与GerBuffer配合使用,清空内存
m_Path=str;//将路径存储在m_path中

if(str.GetAt(str.GetLength()-1)!='\\')
m_Path+="\\";
UpdateData(FALSE);

SHGetPathFromIDList函数可以将idl变量中关于文件夹的路径信息转换成String类型存储到相应变量中,通过简单处理即得到文件夹的全路径信息m_Path,接下来开始读取该路径下的所有文件。

在读取文件之前需要先单开所在目录,即调用opendir()函数,该函数入口参数要求为char*类型,因此在调用之前需要先进行类型转换,代码如下:

char* m_ImageDir;//存放文件夹文件结构

m_ImageDir=(LPSTR)(LPCTSTR)m_Path;

DIR *m_pDir;//DIR结构体

m_pDir = opendir(m_ImageDir);

需要强调的一点是:关于dir的操作要想顺利执行,必须包含头文件dirent.h,该头文件是Linux的移植版,网上可以找到。

在打开对应的目录结构之后,在该目录下的前两个路径分别是../以及./,是无效的,需要通过readdir()函数把这两个无效目录过滤掉,readdir()函数返回一个dirent类型的指针,即:

struct dirent *m_pEnt;//目录结构体

for (int i = 0; i < 2; i ++) //过滤目录 ..   和  .
{
m_pEnt = readdir(m_pDir);
}

目录过滤完成后就可以正式的逐条的读取文件名等信息了,下面给出一段循环读取文件夹下所有图像类文件的代码:

while (m_pDir && (m_pEnt = readdir(m_pDir)) != NULL) 
{
//判断名字中有没有 .jpg  .bmp .png
char* pJpg = strstr(m_pEnt->d_name,".jpg");
char* pBmp = strstr(m_pEnt->d_name,".bmp");
char* pPng = strstr(m_pEnt->d_name,".png");
char* pJPG = strstr(m_pEnt->d_name,".JPG");

if(pJpg==NULL && pBmp==NULL && pPng==NULL && pJPG==NULL)
{
break;
}

//拼出文件的全路径
sprintf(imageFullName,"%s%s",m_ImageDir,m_pEnt->d_name);

//读入文件并按规则改写文件名
Mat image = imread(imageFullName,1);
}

由以上代码可见,m_pEnt->d_name指明了文件夹下具体文件的文件名(m_pEnt是struct dirent *类型的变量),然后通过字符串比较函数 strstr()来判断当前文件名中是否包含图像类型的扩展名,然后通过sprintf()函数将当前文件夹路径和文件名合并起来,构成文件的全路径,之后就可以通过得到的全路径来读取文件了,此处已opencv中图像读取为例,最后通过while()语句来判断每次 readdir()函数的返回值是否为空来判断当前文件是否是最后一个,注意readdir()的读取顺序是自动后移的。

最后说明一点,这篇博客主要是介绍这个方法怎么用,对其中涉及的一些函数并没有做深入分析,大家有什么问题欢迎进行讨论,水平有限,欢迎指正,有感兴趣的欢迎大家加群51701853一起讨论。




你可能感兴趣的:(文件批量读取)