在 Windows 上用 C 搞一个打开/保存文件对话框做 Windows 桌面开发基本绕不开让用户选文件。不管是打开已有文件还是另存为新文件总得弹个系统对话框。网上搜一圈方法不少但很多要么是 MFC 的要么是纯 Win32 的混在一起讲容易乱。我这篇就只聊文件对话框文件夹的下一期再说把两种常用路子都过一遍顺带记几个我踩过的坑。先上 MFC 的CFileDialog如果你用 MFC 的话如果你的项目本身是 MFC 框架那直接用CFileDialog最省事不用自己折腾结构体。打开文件#includeafxdlgs.hvoidDoOpenFile(){CFileDialogdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,_T(文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*||),this);if(dlg.DoModal()IDOK){CString pathdlg.GetPathName();// 拿到路径该读就读AfxMessageBox(_T(选了: )path);}}那个过滤器字符串的格式是固定的描述|模式|描述|模式||最后一定要俩竖线少一个就弹不出来别问我怎么知道的。OFN_FILEMUSTEXIST保证用户不能瞎填一个不存在的文件省得你后面再校验。保存文件保存模式就是把第一个参数改成FALSE顺手加上覆盖提示。voidDoSaveFile(){CFileDialogdlg(FALSE,_T(txt),_T(默认名字),OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST,_T(文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*||),this);if(dlg.DoModal()IDOK){CString pathdlg.GetPathName();// 创建文件写入}}OFN_OVERWRITEPROMPT必须加不然用户选了个已存在的文件你的程序直接覆盖掉连个招呼都不打等着被骂吧。不用 MFC 的话Win32 老路子GetOpenFileName/GetSaveFileName很多朋友的项目是纯 Win32 或者 ATL 之类的没 MFC 那一套。那就用commdlg.h里的这两个 API它们从 Win95 就存在了兼容性无敌。打开文件#includecommdlg.hCStringOpenFileDialog(HWND hWnd){OPENFILENAME ofn{0};TCHAR szFile[MAX_PATH]{0};ofn.lStructSizesizeof(ofn);ofn.hwndOwnerhWnd;ofn.lpstrFileszFile;ofn.nMaxFileMAX_PATH;// 注意过滤器的写法用 \0 分隔最后两个 \0 结尾ofn.lpstrFilter_T(文本文件\0*.txt\0所有文件\0*.*\0);ofn.nFilterIndex1;ofn.FlagsOFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;if(GetOpenFileName(ofn))returnCString(szFile);return_T();// 取消或失败}这里最容易写错的就是lpstrFilter它用的是双空字符分隔不是|。如果你复制了 MFC 那种|分隔的字符串过来对话框直接罢工。另外szFile缓冲区要足够大MAX_PATH通常是 260 个字符一般够用但长路径的话可以考虑_MAX_PATH或动态分配不过一般不用太纠结。保存文件CStringSaveFileDialog(HWND hWnd){OPENFILENAME ofn{0};TCHAR szFile[MAX_PATH]_T(未命名.txt);// 预填默认名ofn.lStructSizesizeof(ofn);ofn.hwndOwnerhWnd;ofn.lpstrFileszFile;ofn.nMaxFileMAX_PATH;ofn.lpstrFilter_T(文本文件\0*.txt\0所有文件\0*.*\0);ofn.nFilterIndex1;ofn.FlagsOFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST;if(GetSaveFileName(ofn))returnCString(szFile);return_T();}跟打开的区别不大就是Flags换了OFN_OVERWRITEPROMPTszFile里给了个初始字符串用户可以在对话框里改。项目类型推荐接口说明基于 MFC 框架CFileDialog无需额外依赖接口与 MFC 风格一致纯 Win32 / ATL / 无 MFCGetOpenFileName/GetSaveFileName仅依赖commdlg.dll无框架开销需适配 Windows 10/11 界面两者均可底层均调用系统通用对话框外观一致需兼容 Windows XP两者均可GetOpenFileName原生支持 XPCFileDialog需使用 v141_xp 工具集编译 MFC几个容易忽略的细节用户点了取消两种方式都会返回FALSE或IDCANCEL一定要判断别拿着空路径去读写。默认扩展名CFileDialog的第二个参数可以指定默认后缀如果用户没输后缀系统会自动补上。Win32 版的话OPENFILENAME里也有lpstrDefExt可以设。多选文件这里没讲因为篇幅长而且多数场景只要单选。如果需要多选CFileDialog可以加OFN_ALLOWMULTISELECT但处理起来会复杂一些。Unicode 和 ANSI现在基本都用 Unicode 了代码里的_T宏和TCHAR能自动适应如果是 VS 的新项目默认就是 Unicode。版权声明本文为博主原创转载注明出处即可。
在 Windows 上用 C++ 搞一个打开/保存文件对话框
发布时间:2026/7/2 2:24:13
在 Windows 上用 C 搞一个打开/保存文件对话框做 Windows 桌面开发基本绕不开让用户选文件。不管是打开已有文件还是另存为新文件总得弹个系统对话框。网上搜一圈方法不少但很多要么是 MFC 的要么是纯 Win32 的混在一起讲容易乱。我这篇就只聊文件对话框文件夹的下一期再说把两种常用路子都过一遍顺带记几个我踩过的坑。先上 MFC 的CFileDialog如果你用 MFC 的话如果你的项目本身是 MFC 框架那直接用CFileDialog最省事不用自己折腾结构体。打开文件#includeafxdlgs.hvoidDoOpenFile(){CFileDialogdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_FILEMUSTEXIST,_T(文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*||),this);if(dlg.DoModal()IDOK){CString pathdlg.GetPathName();// 拿到路径该读就读AfxMessageBox(_T(选了: )path);}}那个过滤器字符串的格式是固定的描述|模式|描述|模式||最后一定要俩竖线少一个就弹不出来别问我怎么知道的。OFN_FILEMUSTEXIST保证用户不能瞎填一个不存在的文件省得你后面再校验。保存文件保存模式就是把第一个参数改成FALSE顺手加上覆盖提示。voidDoSaveFile(){CFileDialogdlg(FALSE,_T(txt),_T(默认名字),OFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST,_T(文本文件 (*.txt)|*.txt|所有文件 (*.*)|*.*||),this);if(dlg.DoModal()IDOK){CString pathdlg.GetPathName();// 创建文件写入}}OFN_OVERWRITEPROMPT必须加不然用户选了个已存在的文件你的程序直接覆盖掉连个招呼都不打等着被骂吧。不用 MFC 的话Win32 老路子GetOpenFileName/GetSaveFileName很多朋友的项目是纯 Win32 或者 ATL 之类的没 MFC 那一套。那就用commdlg.h里的这两个 API它们从 Win95 就存在了兼容性无敌。打开文件#includecommdlg.hCStringOpenFileDialog(HWND hWnd){OPENFILENAME ofn{0};TCHAR szFile[MAX_PATH]{0};ofn.lStructSizesizeof(ofn);ofn.hwndOwnerhWnd;ofn.lpstrFileszFile;ofn.nMaxFileMAX_PATH;// 注意过滤器的写法用 \0 分隔最后两个 \0 结尾ofn.lpstrFilter_T(文本文件\0*.txt\0所有文件\0*.*\0);ofn.nFilterIndex1;ofn.FlagsOFN_PATHMUSTEXIST|OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;if(GetOpenFileName(ofn))returnCString(szFile);return_T();// 取消或失败}这里最容易写错的就是lpstrFilter它用的是双空字符分隔不是|。如果你复制了 MFC 那种|分隔的字符串过来对话框直接罢工。另外szFile缓冲区要足够大MAX_PATH通常是 260 个字符一般够用但长路径的话可以考虑_MAX_PATH或动态分配不过一般不用太纠结。保存文件CStringSaveFileDialog(HWND hWnd){OPENFILENAME ofn{0};TCHAR szFile[MAX_PATH]_T(未命名.txt);// 预填默认名ofn.lStructSizesizeof(ofn);ofn.hwndOwnerhWnd;ofn.lpstrFileszFile;ofn.nMaxFileMAX_PATH;ofn.lpstrFilter_T(文本文件\0*.txt\0所有文件\0*.*\0);ofn.nFilterIndex1;ofn.FlagsOFN_OVERWRITEPROMPT|OFN_PATHMUSTEXIST;if(GetSaveFileName(ofn))returnCString(szFile);return_T();}跟打开的区别不大就是Flags换了OFN_OVERWRITEPROMPTszFile里给了个初始字符串用户可以在对话框里改。项目类型推荐接口说明基于 MFC 框架CFileDialog无需额外依赖接口与 MFC 风格一致纯 Win32 / ATL / 无 MFCGetOpenFileName/GetSaveFileName仅依赖commdlg.dll无框架开销需适配 Windows 10/11 界面两者均可底层均调用系统通用对话框外观一致需兼容 Windows XP两者均可GetOpenFileName原生支持 XPCFileDialog需使用 v141_xp 工具集编译 MFC几个容易忽略的细节用户点了取消两种方式都会返回FALSE或IDCANCEL一定要判断别拿着空路径去读写。默认扩展名CFileDialog的第二个参数可以指定默认后缀如果用户没输后缀系统会自动补上。Win32 版的话OPENFILENAME里也有lpstrDefExt可以设。多选文件这里没讲因为篇幅长而且多数场景只要单选。如果需要多选CFileDialog可以加OFN_ALLOWMULTISELECT但处理起来会复杂一些。Unicode 和 ANSI现在基本都用 Unicode 了代码里的_T宏和TCHAR能自动适应如果是 VS 的新项目默认就是 Unicode。版权声明本文为博主原创转载注明出处即可。