windows 文件,文件夹操作
一. C标准的文件读写
- 操作方式:流式文件操作和I/O文件操作,这里只对流式文件操作进行说明,比较常用。
- 特点:可移植性强(跨平台),如果是偏低层开发,与二进制文件打交道,会经常使用到该类函数。
- 常用方法:
1. FILE:流式文件的操作指针,下面简单说明一下这个结构体。
1 typedef struct _iobuf 2 { 3 char *_ptr; //文件输入的下一个位置 4 int _cnt; //当前缓冲区的相对位置 5 char *_base; //指基础位置(应该是文件的其始位置) 6 int _flag; //文件标志 7 int _file; //文件的有效性验证 8 int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取 9 int _bufsiz; //文件的大小 10 char *_tmpfname; //临时文件名 11 }FILE;
2. fopen_s:打开一个流并与文件关联,如果打开失败则返回相应的错误码。注:第三个参数mode设置为“a”时,如果文件不存在,则创建新文件,其他参数详解。
3. fclose:关闭用fopen()打开的文件,如果打开成功返回0,失败则返回错误码。
4. fseek:一般用于二进制模式打开的文件中,功能是定位到流中指定的位置。第三个参数:SEEK_SET文件开头,SEEK_CUR文件当前读写位置,SEEK_END文件尾部。
5. ftell:返回当前的文件位置。
6. fwrite:往流中写入指定内容。文件操作是一个流程,将相关方法例子汇总到如下代码中。
1 FILE* pFile = nullptr; 2 const char* pcFilePath = ".//1.text"; 3 4 //文件写 5 errno_t err = fopen_s(&pFile, pcFilePath, "ab"); 6 if ((0 == err) && (nullptr != pFile)) 7 { 8 const char* pcData = "我们我们我们我们"; 9 UINT uiFileLen = strlen(pcData) + 1; 10 11 UINT uiWriteLen = fwrite(pcData, sizeof (char), uiFileLen, pFile); 12 if (uiFileLen == uiWriteLen) 13 { 14 printf("file write successfully\n"); 15 } 16 fclose(pFile); 17 }
7. fread:从流中读取指定个数的字符。
1 FILE* pFile = nullptr; 2 const char* pcFilePath = ".//1.text"; 3 4 errno_t err1 = fopen_s(&pFile, pcFilePath, "r"); 5 if ((0 == err1) && (nullptr != pFile)) 6 { 7 char acBuf[1024] = { 0 }; 8 9 fseek(pFile, 0, SEEK_END); 10 UINT uiFileLen = ftell(pFile); 11 fseek(pFile, 0, SEEK_SET); 12 13 UINT uiReadLen = fread(acBuf, sizeof (char), uiFileLen, pFile); 14 if (uiReadLen == uiFileLen) 15 { 16 printf("file read: %s \n", acBuf); 17 } 18 fclose(pFile); 19 }
二. MFC封装的文件读写
- 说明: c++也有流式文件操作,这里就不作说明了,只把自己常用的文件操作方式说明一下。
- 特点:简洁方便,缺点也明显,只限于MFC环境。
- 操作:
1. CFile类:MFC类库将文件的一些相关操作封装到一个类里供我们使用,可参照类详细信息。
2. 文件相关:GetLength获取文件大小,对比C方法更简洁。GetFileName获取文件名,GetFilePath获取文件路径,Remove删除指定文件等。
3. open:这里有nOpenFlgs的详细信息,其他与C的流式操作方法类似,下面就直接用例子说明。
1 CFile objFile; 2 3 //文件写 4 BOOL bOpen = objFile.Open(_T(".//2.text"), CFile::modeCreate | CFile::modeWrite); 5 if (TRUE == bOpen) 6 { 7 const PCHAR pcData = "我们会不会有明天"; 8 objFile.Write(pcData, (strlen(pcData) + 1) * sizeof (char)); 9 objFile.Close(); 10 } 11 12 //文件读 13 BOOL bOpen1 = objFile.Open(_T(".//2.text"), CFile::modeRead); 14 if (TRUE == bOpen1) 15 { 16 CHAR acBuf[1024] = { 0 }; 17 UINT uiFileLen = (UINT)objFile.GetLength(); 18 19 UINT uiReadLen = objFile.Read(acBuf, uiFileLen); 20 if (uiReadLen == uiFileLen) 21 { 22 printf("MFC: file read: %s \n", acBuf); 23 } 24 objFile.Close(); 25 }
三. MFC的文件对话框类CFileDialog
- 说明:用来筛选文件或"另存为"文件,构造函数的参数说明如下:
1 CFileDialog ObjFileDlg(TRUE, //指定要创建对话框的类型。若为"TRUE",则创建为"文件>打开"对话框;若为"FALSE",则创建为"文件>另存为"对话框。 2 nullptr, //默认的文件扩展名。 3 nullptr, //文件框显示的初始文件名。 4 OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,//具体参见MSDN 5 _T("图片文件(*.png; *.jpg; *.jpeg; *.bmp)|*.png; *.jpg; *.jpeg; *.bmp|所有文件(*.*)|*.*||"), //规则见文档说明 6 nullptr,//指向对话框的父窗口或所有者窗口 后面两个参数为缺省参数,可以不设置 7 0, //OPENFILENAME 结构的大小 8 TRUE); //指定文件对话框样式的参数
1. dwFlags参数:请参见dwFlags参数说明
2. lpszFilter:文件筛选器的过滤规则:eg .T("bmp文件(*.bmp)|*.bmp|JPEG文件(*.jpg)|*.jpg||")
- 打开文件夹:与CFileDialog类不同的是,打开"文件夹"对话框使用的win32 API。
1 void CFileDlgDlg::OnBnClickedBtnOpenfolder() 2 { 3 CString strDirPath; 4 BROWSEINFO stDirInfo; 5 ::ZeroMemory(&stDirInfo, sizeof(stDirInfo)); 6 7 stDirInfo.pidlRoot = 0; 8 stDirInfo.lpszTitle = _T("选择文件存储路径:"); 9 stDirInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_DONTGOBELOWDOMAIN; 10 stDirInfo.lpfn = nullptr; 11 12 LPITEMIDLIST lpidlBrowse = ::SHBrowseForFolder(&stDirInfo); 13 if (nullptr != lpidlBrowse) 14 { 15 if (::SHGetPathFromIDList(lpidlBrowse, strDirPath.GetBuffer(MAX_PATH))) 16 { 17 CEdit* pobjEditFolderPath = static_cast<CEdit*>(GetDlgItem(IDC_EDIT_FOLDERPATH)); 18 if (nullptr != pobjEditFolderPath) 19 { 20 pobjEditFolderPath->SetWindowTextW(strDirPath); 21 } 22 } 23 ::CoTaskMemFree(lpidlBrowse); 24 } 25 }
- 测试代码:见最后链接,展示图如下:
四. windows API 下的文件及文件夹操作
- 说明:CreateFile用来打开I/O设备。最常用的 I/O 设备如下:文件、文件流、目录、物理磁盘、卷、控制台缓冲区、磁带驱动器、通信资源、mailslot 和管道。比如,我们比较常用的对串口进行操作,就是使用此类函数,功能强大。
1. CFile类的核心代码:MFC封装的CFile类本质是对CreateFile,WriteFile,ReadFile,CloseHandle接口的封装;
2. CreateFile除了可以打开文件外,还可以打开磁盘,驱动等,所以封装时作了兼容性处理;
- wprintf汉字时出现"??",跟大小端的存储格式有关,加上setlocale()可解决;当使用unicode输入汉字到文本后,使用记事本打开呈乱码,原因是系统自动识别为ANSI,可以在写入汉字之前,先写入“FEFF”
- 打开文件后,直接进行读写操作时,一定要注意文件指针的位置,适当地使用SetFilePointer;
1 #ifndef _FILEUTIL_H__ 2 #define _FILEUTIL_H__ 3 4 class ICallBackFile 5 { 6 public: 7 virtual void CallBackEnumFiles(LPCTSTR lpFileName) = 0; 8 virtual void CallBackOpenDlgFile(LPCTSTR lpFileName) = 0; 9 virtual void CallBackOpenDlgDir(LPCTSTR lpDirName) = 0; 10 public: 11 ICallBackFile() = default; 12 virtual ~ICallBackFile() = default; 13 }; 14 15 class CFileUtil 16 { 17 public: 18 /*文件读写操作都是原子操作,使用单例来降低被重复并行操作的风险*/ 19 static CFileUtil& GetInstance(); 20 21 /*创建文件*/ 22 HANDLE CreateFile(LPCTSTR lpFileName, DWORD dwDesiredAccess, DWORD dwCreationDisposition, 23 DWORD dwShareMode = 0, LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr, 24 DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL, HANDLE hTemplateFile = nullptr); 25 26 /*写文件*/ 27 BOOL WriteFile(HANDLE hFile,LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, 28 LPOVERLAPPED lpOverlapped = nullptr); 29 30 /*读文件*/ 31 BOOL ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, 32 LPOVERLAPPED lpOverlapped = nullptr); 33 34 /*关闭文件句柄*/ 35 BOOL CloseHandle( HANDLE hObject ); 36 37 /*获取文件大小*/ 38 DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh = nullptr); 39 40 /*设置文件指针位置*/ 41 BOOL SetFilePointer(HANDLE hFile, LONGLONG llOffset, DWORD dwMoveMethod, PLARGE_INTEGER lpNewFilePointer = nullptr); 42 43 /*删除文件*/ 44 BOOL DeleteFile(LPCTSTR lpFileName); 45 46 /*文件遍历:遍历指定目录下所有指定类型的文件(包含子目录的遍历)*/ 47 void EnumFile(TCHAR* pcDirPath, TCHAR* pcFileExt); 48 49 /*获取文件名:从完整的文件名路径中分离出文件名*/ 50 PTSTR PathFindFileName(PTSTR ptFilePath); 51 52 /*获取文件后缀名:从完整的文件名路径中分离出后缀名*/ 53 BOOL PathFindFileExt(PTSTR ptFilePath, PTSTR ptExtBuf, UINT uiBufSize); 54 55 /*文件夹的创建*/ 56 BOOL CreateDirectory(LPCTSTR lpPathName, LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr); 57 58 /*文件夹的删除*/ 59 BOOL RemoveDirectory(LPCTSTR lpPathName); 60 61 /*选择文件:打开文件的对话框*/ 62 void OpenDlgFile(HWND hWnd = nullptr, DWORD dwFlags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST, LPCTSTR lpFileType = _T("*.*")); 63 64 /*选择文件夹:打开文件夹的对话框*/ 65 void OpenDlgDir(LPCTSTR lpTitle = _T("选择文件夹"), UINT uiFlags = BIF_RETURNONLYFSDIRS | BIF_DONTGOBELOWDOMAIN | BIF_USENEWUI); 66 67 public: 68 ICallBackFile* GetCallbackFile() const; 69 void SetCallbackFile(ICallBackFile* pCallbackFile); 70 71 public: 72 CFileUtil() : m_pCallBackFile(nullptr) {}; 73 CFileUtil(const CFileUtil&) = delete;//禁类赋值 74 CFileUtil& operator=(const CFileUtil&) = delete;//禁类拷贝 75 76 ~CFileUtil() = default; 77 78 private: 79 ICallBackFile* m_pCallBackFile; 80 }; 81 82 #endif /*_FILEUTIL_H__*/