在应用程序当中打开文件夹选择一个或多个文件进行操作非常普遍;打开文件夹选择一个文件夹存放内容也很多。但是相关函数又很复杂,需要给复杂的结构体赋值。为此,我封装了一个类,方便以后的调用。
废话少说,上代码:
定义类的头文件:OpenFileClass.h
#pragma once
#include"stdafx.h"
#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容
#include <windows.h>//打开对话框要用到
//打开保存文件对话框
#include<Commdlg.h>
//选择文件夹对话框
#include<Shlobj.h>
#include <stdlib.h>
#include<iostream>
#include <malloc.h>
#include <string> // string
#include <atlstr.h> //CString的头文件:
#include<vector>
//没有照样运行:#pragma comment(lib,"Shell32.lib")
class OpenFileClass
{
public:
OpenFileClass()
{
}
~OpenFileClass()
{
}
private:
/*
从选定的文件夹里面读取所有的文件,宽字符版本
WCHAR* szBuffer类型的参数可以实现输入输出
*/
void GetDirectoryW(WCHAR* szBuffer)
{
BROWSEINFOW bi = { 0 };
bi.hwndOwner = NULL;//拥有着窗口句柄,为NULL表示对话框是非模态的,实际应用中一般都要有这个句柄
bi.pszDisplayName = szBuffer;//接收文件夹的缓冲区
bi.lpszTitle = TEXT("选择一个文件夹");//标题
bi.ulFlags = BIF_NEWDIALOGSTYLE;
//为显示允许用户选择一个目录而不是一个文件的对话框,要调用SHBrowseForFolder函数。
LPITEMIDLIST idl = SHBrowseForFolderW(&bi);
if (!SHGetPathFromIDListW(idl, szBuffer))
{
MessageBox(NULL, TEXT("请选择一个文件夹"), NULL, MB_ICONERROR);
}
else
{
//如果在这里使用函数GetCurrentDirectory(),是不是就可以打开文件夹所属的所有文件呢
//MessageBoxW(NULL, szBuffer, TEXT("GetDirectory_1函数内部,你选择的文件夹"), 0);
}
}
/*
从选定的文件夹里面读取所有的文件,窄字符版本
char* szBuffer类型的参数可以实现输入输出
*/
void GetDirectoryA(char* szBuffer)
{
BROWSEINFOA bi = { 0 };
bi.hwndOwner = NULL;//拥有着窗口句柄,为NULL表示对话框是非模态的,实际应用中一般都要有这个句柄
bi.pszDisplayName = szBuffer;//接收文件夹的缓冲区
bi.lpszTitle = "选择一个文件夹";//标题
bi.ulFlags = BIF_NEWDIALOGSTYLE;
//为显示允许用户选择一个目录而不是一个文件的对话框,要调用SHBrowseForFolder函数。
LPITEMIDLIST idl = SHBrowseForFolderA(&bi);
if (!SHGetPathFromIDListA(idl, szBuffer))
{
MessageBoxA(NULL, "请选择一个文件夹", "发生了错误!", MB_ICONERROR);
}
}
//打开文件夹,获取文件夹内文件
//注意了,注意了,我只读取json文档
std::vector<std::string> GetFilesFromDirectoryA(char* DirectoryPath)
{
//char DirectoryPath[126];
GetCurrentDirectoryA(sizeof(DirectoryPath), DirectoryPath);//指定文件夹
lstrcatA(DirectoryPath, "\\*.json");//给获取到的文件路径添加文件后缀,便于搜索
WIN32_FIND_DATAA winFndData;//这个结构体是用来保存信息的,而不是为了入参(凡是以结构体指针入参的,都是输入输出)
//lstrcpyA(winFndData.cAlternateFileName,"*/" );
//第一个参数决定了我们在tmp这个文件夹路径下能获得什么,文件类型(后缀决定)、文件夹
HANDLE FileHandle = FindFirstFileA(DirectoryPath, &winFndData);
//FileNames.push_back(myFilePath);
//FileNames.push_back(winFndData.cFileName);//找到的第一个文件
std::vector<std::string>FileNames;
if (FileHandle == INVALID_HANDLE_VALUE)
{
MessageBoxA(NULL, "文件夹内没有相对应的文件类型", "发生错误", MB_OK);
}
else
{
while (FindNextFileA(FileHandle, &winFndData))
{
//如果是文件,我才输入
if (winFndData.dwFileAttributes & FILE_SHARE_READ || FILE_SHARE_WRITE)//文件属性决定了是隐藏文件还是加密文件、文件夹
{
FileNames.push_back(winFndData.cFileName);//这里得到的时全路径文件名
}
}
}
return FileNames;
}
//打开文件夹,获取文件夹内文件
//注意了,注意了,我只读取json文档
std::vector<CString> GetFilesFromDirectoryW(wchar_t* DirectoryPath)
{
//char DirectoryPath[126];
GetCurrentDirectoryW(sizeof(DirectoryPath), DirectoryPath);//指定文件夹
lstrcatW(DirectoryPath, L"\\*.json");//给获取到的文件路径添加文件后缀,便于搜索
WIN32_FIND_DATAW winFndData;//这个结构体是用来保存信息的,而不是为了入参(凡是以结构体指针入参的,都是输入输出)
//lstrcpyA(winFndData.cAlternateFileName,"*/" );
//第一个参数决定了我们在tmp这个文件夹路径下能获得什么,文件类型(后缀决定)、文件夹
HANDLE FileHandle = FindFirstFileW(DirectoryPath, &winFndData);
//FileNames.push_back(myFilePath);
//FileNames.push_back(winFndData.cFileName);//找到的第一个文件
std::vector<CString>FileNames;//可以放入宽字符么???
if (FileHandle == INVALID_HANDLE_VALUE)
{
MessageBoxW(NULL, L"文件夹内没有相对应的文件类型", L"发生错误", MB_OK);
}
else
{
while (FindNextFileW(FileHandle, &winFndData))
{
//如果是文件,我才输入
if (winFndData.dwFileAttributes & FILE_SHARE_READ || FILE_SHARE_WRITE)//文件属性决定了是隐藏文件还是加密文件、文件夹
{
//不可以把宽字符的字符串输入到string里面。现在FileNames定义的是cstring类型
//这里得到的时全路径文件名
FileNames.push_back(winFndData.cFileName);
}
}
}
return FileNames;
}
public:
//获得文件路径及文件名,
//char*strFilename类型的参数可以实现输入输出
void GetFilePathA(char*strFilenameBuffer)
{
OPENFILENAMEA open; // 公共对话框结构。
ZeroMemory(&open, sizeof(OPENFILENAME)); // 初始化选择文件对话框
open.lStructSize = sizeof(OPENFILENAME); //指定这个结构的大小,以字节为单位。
open.lpstrFile = strFilenameBuffer; //打开的文件的全路径
open.lpstrFilter = "json文件(*.json)\0*.json\0表格文件(*.csv)\0*.csv\0表格文件(.xls)\0*.xls\0\0"; //打开文件类型
open.nFilterIndex = 1; //指定在文件类型控件中当前选择的过滤器的索引
open.lpstrFile[0] = '\0'; //第一个字符串是过滤器描述的显示字符串
open.nMaxFile = MAX_PATH; //指定lpstrFile缓冲的大小,以TCHARs为单位
open.lpstrTitle = "选择一个文件"; // 对话框的窗口标题
open.lpstrFileTitle = NULL; // 指向接收选择的文件的文件名和扩展名的缓冲(不带路径信息)。这个成员可以是NULL。
open.nMaxFileTitle = 0; //指定lpstrFileTitle缓冲的大小,以TCHARs为单位
open.lpstrInitialDir = NULL; //指向以空字符结束的字符串,可以在这个字符串中指定初始目录。
open.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;//位标记的设置,你可以使用来初始化对话框
//函数功能:该函数创建一个Open公共对话框,使用户指定驱动器、目录和文件名、或使用户打开文件。
//Ipofn:指向包含初始化对话框的信息的一个OPENFILENAME结构。当OpenfileName函数返回时,此结构包含有关用户文件选择的信息。
//返回值:如果用户指定了一个文件名,点击OK按钮,返回值为非零。
//由OPENFILENAME结构的IPstrFile成员指向的缓冲区含有全路径和用户指定的文件名。
//如果用户取消或关闭Open对话框或错误出现,返回值为零。若想获得更多的错误信息,请调用CommDlgExtendedError函数。
//GetOpenFileName (&open) ;//打开文件对话框
//GetSaveFileName(&open);//保存文件对话框
if (!GetOpenFileNameA(&open)) // 显示打开选择文件对话框。
{
printf_s("没有选择文件:%s\n", strFilenameBuffer);
MessageBoxA(NULL, strFilenameBuffer, "发生了错误", MB_ICONERROR);//错误的
}
else//正确的情况
{
//CString path = strFilename;
//wprintf_s(path + "\n");
//printf_s("%s\n",file);
//strFilename仅仅是一个文件的全路径名称,需要去掉文件名才能成为路径,以参数的形式入参下面的函数里面
//myFiles = GetFilesFromDirectory(strFilename);
//MessageBoxA(NULL, strFilename, "选择的文件", 0);//正确的
}
}
//获得文件的全路径名称
//WCHAR* strFilename类型的参数可以实现输入输出
void GetFilePathW(WCHAR* strFilenameBuffer)
{
OPENFILENAMEW open; // 公共对话框结构。
ZeroMemory(&open, sizeof(OPENFILENAME)); // 初始化选择文件对话框
open.lStructSize = sizeof(OPENFILENAME); //指定这个结构的大小,以字节为单位。
open.lpstrFile = strFilenameBuffer; //打开的文件的全路径
open.lpstrFilter = L"json文件(*.json)\0*.json\0表格文件(*.csv)\0*.csv\0表格文件(.xls)\0*.xls\0\0"; //打开文件类型
open.nFilterIndex = 1; //指定在文件类型控件中当前选择的过滤器的索引
open.lpstrFile[0] = L'\0'; //第一个字符串是过滤器描述的显示字符串
open.nMaxFile = MAX_PATH; //指定lpstrFile缓冲的大小,以TCHARs为单位
open.lpstrTitle = L"选择一个文件"; // 对话框的窗口标题
open.lpstrFileTitle = NULL; // 指向接收选择的文件的文件名和扩展名的缓冲(不带路径信息)。这个成员可以是NULL。
open.nMaxFileTitle = 0; //指定lpstrFileTitle缓冲的大小,以TCHARs为单位
open.lpstrInitialDir = NULL; //指向以空字符结束的字符串,可以在这个字符串中指定初始目录。
open.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;//位标记的设置,你可以使用来初始化对话框
//函数功能:该函数创建一个Open公共对话框,使用户指定驱动器、目录和文件名、或使用户打开文件。
//Ipofn:指向包含初始化对话框的信息的一个OPENFILENAME结构。当OpenfileName函数返回时,此结构包含有关用户文件选择的信息。
//返回值:如果用户指定了一个文件名,点击OK按钮,返回值为非零。
//由OPENFILENAME结构的IPstrFile成员指向的缓冲区含有全路径和用户指定的文件名。
//如果用户取消或关闭Open对话框或错误出现,返回值为零。若想获得更多的错误信息,请调用CommDlgExtendedError函数。
//GetOpenFileName (&open) ;//打开文件对话框
//GetSaveFileName(&open);//保存文件对话框
if (!GetOpenFileNameW(&open))
{
MessageBoxW(NULL, L"请选择一个文件", NULL, MB_ICONERROR);
}
else//正确的情况,因为我们有了输入输出的机制
{
//MessageBoxW(NULL, strFilename, L"选择的文件", 0);
}
}
//从选定的文件夹里面读取特定的一系列文件
std::vector<CString> GetDirectoryFilesW()
{
wchar_t szBuffer[MAX_PATH] = { 0 };//今日进一步理解了输入输出参数的机制
GetDirectoryW(szBuffer);//这是一个弹出对话框的阻塞式函数
//MessageBoxW(NULL, szBuffer, L"你选择的文件夹", 0);
return GetFilesFromDirectoryW(szBuffer);
}
//从选定的文件夹里面读取特定的一系列文件
std::vector<std::string> GetDirectoryFilesA()
{
char szBuffer[MAX_PATH] = { 0 };//今日进一步理解了输入输出参数的机制
GetDirectoryA(szBuffer);//这是一个弹出对话框的阻塞式函数
//MessageBoxA(NULL, szBuffer, "你选择的文件夹", 0);
return GetFilesFromDirectoryA(szBuffer);//从文件夹里面获取我们需要的文件
}
};
调用OpenFileClass类的cpp文件:
#include"OpenFileClass.h"
OpenFileClass OFC;
int main()
{
//测试1、
//wchar_t wFileName[256];
//OFC.GetFilePathW(wFileName); //没有问题
//MessageBoxW(NULL, wFileName, L"宽字符,类外的结果", MB_OK);//成功了
//测试2、
//char cFileName[256];
//OFC.GetFilePathA(cFileName); //没有问题
//MessageBoxA(NULL, cFileName, "窄字符,类外的结果", MB_OK);//成功了
//测试3、
//注意了,注意了,我只读取json文档
//std::vector<std::string> myFiles = OFC.GetDirectoryFilesA(); //没有问题
//for (auto itr = myFiles.begin(); itr != myFiles.end(); ++itr)
//{
// printf_s("文件:%s\n", itr->c_str());
//}
//myFiles.clear();
//测试4、
//注意了,注意了,我只读取json文档
std::vector<CString> myFiles = OFC.GetDirectoryFilesW(); //没有问题
for (auto itr = myFiles.begin(); itr != myFiles.end(); ++itr)
{
//printf_s("文件:%s\n", itr->c_str());//CString类型的数据更方便使用c_str()得到多字节字符串,无须转换
//wprintf_s(L"文件:%s\n", itr->GetString());//无法输出uincode字符串,uincode字符串只在win32窗口界面下使用,不能在控制台输出
//std::cout << itr->GetBuffer() << std::endl;//无法输出uincode字符串,uincode字符串只在win32窗口界面下使用,不能在控制台输出
//std::cout << itr->GetString() << std::endl;//无法输出uincode字符串,uincode字符串只在win32窗口界面下使用,不能在控制台输出
}
MessageBoxW(NULL, myFiles.at(1), L"看看第一个文件名", MB_OK);//uincode字符串只在win32窗口界面下使用,不能在控制台输出
myFiles.clear();
getchar();
return 0;
}