[Win32] 文件系统操作
上一节讲了文件同步读写,这次就说说文件系统的操作。
文件系统,简单理解一下,因为磁盘上数据有他的存储方式,而应用程序如果对每种磁盘格式都有了解的话,无疑太难实现,而且兼容性也无法保证,因此,操作系统就将具体的磁盘格式虚拟成(抽象成)一个文件系统,应用程序只需对文件系统操作,磁盘设备驱动程序会把对文件系统的操作转化为对磁盘扇区的操作,这就是文件系统。
一。枚举子目录/枚举文件
依靠三个API实现: FindFirstFile、 FindNextFile、FindClose
MSDN:
FindFirstFile :https://msdn.microsoft.com/en-us/library/windows/desktop/aa364418(v=vs.85).aspx
HANDLE WINAPI FindFirstFile( _In_ LPCTSTR lpFileName, _Out_ LPWIN32_FIND_DATA lpFindFileData );
FindNextFile:https://msdn.microsoft.com/en-us/library/windows/desktop/aa364428(v=vs.85).aspx
<pre class="cpp" name="code">BOOL WINAPI FindNextFile( _In_ HANDLE hFindFile, _Out_ LPWIN32_FIND_DATA lpFindFileData );
FindFirstFile:
lpFileName:目录名称,可以包含*和?,表示任意字符比如,我要枚举D:a下面的所有文件和目录,就可以使用"D:\a\*.*"
lpFindFileData:指向一个WIN32_FIND_DATA结构的指针,用于接收文件/目录的信息
返回值:成功返回搜索句柄,失败返回INVALID_HANDLE_VALUE
FindNextFile:
hFindFile:以前调用 FindFirstFile 返回的搜索句柄
lpFindFileData:指向一个WIN32_FIND_DATA结构的指针,用于接收文件/目录的信息
返回值:成功返回非0,失败返回0。没有更多文件时 GetLastError 返回ERROR_NO_MORE_FILES
关于 WIN32_FIND_DATA结构:
typedef struct _WIN32_FIND_DATA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; TCHAR cFileName[MAX_PATH]; TCHAR cAlternateFileName[14]; } WIN32_FIND_DATA, *PWIN32_FIND_DATA, *LPWIN32_FIND_DATA;
dwFileAttributes:文件属性。下面有详细解释
ftCreationTime:文件创建时间
ftLastAccessTime:上次访问时间
ftLastWriteTime:上次写入时间
这三个时间都是 FILETIME 结构(以UTC计)
nFileSizeHigh:高位文件大小,以字节为单位。
文件的大小等于 (nFileSizeHigh * (MAXDWORD + 1)) + nFileSizeLow。
nFileSizeLow:低位文件大小,以字节为单位。
dwReserved0:如果 dwFileAttributes 成员包括 FILE_ATTRIBUTE_REPARSE_POINT 属性,该成员指定的重分析点标记。
否则为此值是未定义的并且不应使用。
dwReserved1:保留供将来使用。
cFileName:文件名称
cAlternateFileName:文件的替代名称。
此名称是经典 8.3 文件名格式。
例子:枚举D盘下的文件和目录
#include <stdio.h> #include <windows.h> int _tmain(int argc, _TCHAR* argv[]) { HANDLE find; WIN32_FIND_DATA data; find = FindFirstFile("D:\*.*", &data); if (find == INVALID_HANDLE_VALUE){ //出错 return 0; } do { //FILE_ATTRIBUTE_DIRECTORY会在下面说 if ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0){ //文件夹 printf(data.cFileName); printf(" <DIR> "); } else{ //不是文件夹,就是文件 puts(data.cFileName); } } while (FindNextFile(find, &data)); getchar(); return 0; }
二。删除文件
使用DeleteFile函数
MSDN:https://msdn.microsoft.com/en-us/library/windows/apps/aa363915(VS.85).aspx
函数原型:
<pre class="cpp" name="code">BOOL WINAPI DeleteFile( _In_ LPCTSTR lpFileName );
lpFileName:文件名称
返回值:成功返回非0,失败返回0
三。判断目录
头文件: Shlwapi.h库文件:Shlwapi.lib
判断文件或目录是否存在
PathFileExists(文件或目录名称)存在返回TRUE,不存在返回FALSE
判断目录是否存在PathIsDirectory(目录名称字符串)是目录返回TRUE,不是返回FALSE
判断目录是否为空目录PathIsDirectoryEmpty(目录名称字符串)是空目录返回TRUE,不是空返回FALSE
四。创建/删除目录
创建目录:CreateDirectory
MSDN:https://msdn.microsoft.com/en-us/library/windows/apps/aa363855(VS.85).aspx
函数原型:
BOOL WINAPI CreateDirectory( _In_ LPCTSTR lpPathName, _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes );
lpPathName:目录名称
lpSecurityAttributes:安全描述符,一般为NULL
注意不能一次创建多级目录
返回值:非0成功,0失败
删除空目录:RemoveDirectory
MSDN:https://msdn.microsoft.com/en-us/library/windows/apps/aa365488(VS.85).aspx
函数原型:
BOOL WINAPI RemoveDirectory( _In_ LPCTSTR lpPathName );
lpPathName:目录名称
返回值:非0成功,0失败
五。读取/设置文件属性
读取:GetFileAttributes
MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/aa364944(v=vs.85).aspx
函数原型:
DWORD WINAPI GetFileAttributes( _In_ LPCTSTR lpFileName );
lpFileName:文件名称
返回值:成功返回文件属性,失败返回INVALID_FILE_ATTRIBUTES
设置:SetFileAttributes
MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/aa365535(v=vs.85).aspx
函数原型:
lpFileName:文件名称
dwFileAttributes:要设置的文件属性
返回值:成功返回非0,失败返回0
文件属性:(红色为常用的)
FILE_ATTRIBUTE_ARCHIVE:文件或目录是一个存档文件或目录。应用程序通常使用此属性将文件标记为备份或移除。
FILE_ATTRIBUTE_COMPRESSED:文件或目录被压缩。对于文件,所有文件中的数据被压缩。目录,压缩是新创建的文件和子目录的默认值。
FILE_ATTRIBUTE_DEVICE:此值被保留供系统使用。
FILE_ATTRIBUTE_DIRECTORY:标识目录的句柄。
FILE_ATTRIBUTE_ENCRYPTED:文件或目录加密的。对于文件,文件中的所有数据流进行都加密。目录,加密是新创建的文件和子目录的默认值。
FILE_ATTRIBUTE_HIDDEN:隐藏的文件或目录。
FILE_ATTRIBUTE_INTEGRITY_STREAM:目录或用户数据流配置 (仅支持裁判的卷) 的完整性。它不是包括在普通目录列表。完整性设置与文件仍然存在,如果它被重命名。如果一个文件被复制目标文件将有完整性设置如果源的文件或目标目录设置的完整性。
Windows Server 2008 R2、 Windows 7、 Windows Server 2008,Windows Vista、 Windows Server 2003 和 Windows XP: 直到 Windows Server 2012 不支持此标志。
FILE_ATTRIBUTE_NORMAL:没有其他文件的属性设置。此属性是仅在单独使用时有效。
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED:文件或目录是不会通过内容索引服务索引。
FILE_ATTRIBUTE_NO_SCRUB_DATA:不能被理解的背景数据完整性扫描仪 (AKA 洗涤器) 用户数据流。当设置目录上它只提供继承。此标志仅支持在存储空间和裁判的卷上。它不是包括在普通目录列表。
Windows Server 2008 R2、 Windows 7、 Windows Server 2008,Windows Vista、 Windows Server 2003 和 Windows XP: 直到 Windows 8 和 Windows Server 2012 不支持此标志。
FILE_ATTRIBUTE_OFFLINE:文件的数据立即不是可用的。此属性指示文件数据被物理地移动到脱机存储区。此属性使用远程存储,是分层存储管理软件。应用程序不应随意更改此属性。
FILE_ATTRIBUTE_READONLY:是只读的文件。应用程序可以读取该文件,但不能写入或删除它。此属性不用在目录上。
FILE_ATTRIBUTE_REPARSE_POINT:文件或目录都有一个关联的重分析点,或者是一个符号链接文件。
FILE_ATTRIBUTE_SPARSE_FILE:是一个稀疏文件的文件。
FILE_ATTRIBUTE_SYSTEM:文件或目录的操作系统使用的一部分,或完全使用。
FILE_ATTRIBUTE_TEMPORARY:用于临时存储的文件。文件系统避免数据写回到大容量存储如果足够的缓存内存不可用,因为通常情况下,应用程序会删除临时文件之后关闭句柄。在这种情况下,该系统可以完全避免写入数据。否则,将数据写入后关闭句柄。
FILE_ATTRIBUTE_VIRTUAL:此值被保留供系统使用。
六。复制文件
1。CopyFile
MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/aa363851(v=vs.85).aspx
函数原型:
BOOL WINAPI CopyFile( _In_ LPCTSTR lpExistingFileName, _In_ LPCTSTR lpNewFileName, _In_ BOOL bFailIfExists );
lpExistingFileName:原文件名
lpNewFileName:目标文件名
bFailIfExists:如果此参数为 TRUE,指定的新文件 lpNewFileName 已经存在,函数将失败。如果此参数为 FALSE,并且新文件已经存在,函数将覆盖现有的文件并成功。
返回值:成功返回非0,失败返回0
2。CopyFileEx
MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/aa363852(v=vs.85).aspx
函数原型:
BOOL WINAPI CopyFileEx( _In_ LPCTSTR lpExistingFileName, _In_ LPCTSTR lpNewFileName, _In_opt_ LPPROGRESS_ROUTINE lpProgressRoutine, _In_opt_ LPVOID lpData, _In_opt_ LPBOOL pbCancel, _In_ DWORD dwCopyFlags );
lpExistingFileName:原文件名
lpNewFileName:目标文件名
lpProgressRoutine:指向一个回调函数的指针,回调函数用于接收复制进度等信息
lpData:要传给回调函数的数据指针
pbCancel:如果此标志设置为 TRUE 时复制操作,则取消此操作。否则,复制操作将继续完成。
dwCopyFlags:以下值:(红色为常用的)
COPY_FILE_ALLOW_DECRYPTED_DESTINATION:尝试将加密的文件复制将成功即使目标副本不能加密。
COPY_FILE_COPY_SYMLINK:如果源文件是一个符号链接,目标文件也是指向相同源符号链接指向的文件的符号链接。Windows Server 2003 和 Windows XP: 不支持此值。
COPY_FILE_FAIL_IF_EXISTS:如果目标文件已存在,复制操作失败。
COPY_FILE_NO_BUFFERING:使用无缓冲的 I/O,绕过系统 I/O 缓存资源执行复制操作。推荐用于非常大的文件传输。
Windows Server 2003 和 Windows XP: 不支持此值。
COPY_FILE_OPEN_SOURCE_FOR_WRITE:复制文件和原始文件是为写访问打开的。
COPY_FILE_RESTARTABLE:副本的追踪其进展情况在目标文件中复制发生故障的情况下。失败的复制可以在以后重新启动,通过指定相同的值为 lpExistingFileName 和 lpNewFileName 为那些失败的调用中使用。这明显可以减慢复制操作作为新的文件可能在复制操作期间刷新多次。
返回值:成功返回非0,失败返回0
关于回调函数:
DWORD CALLBACK CopyProgressRoutine( _In_ LARGE_INTEGER TotalFileSize, _In_ LARGE_INTEGER TotalBytesTransferred, _In_ LARGE_INTEGER StreamSize, _In_ LARGE_INTEGER StreamBytesTransferred, _In_ DWORD dwStreamNumber, _In_ DWORD dwCallbackReason, _In_ HANDLE hSourceFile, _In_ HANDLE hDestinationFile, _In_opt_ LPVOID lpData );
TotalFileSize:总文件的大小,以字节为单位。
TotalBytesTransferred:复制操作开始以来,从源文件转移到目标文件的字节总数。
StreamSize:以字节为单位,当前的文件流的总大小。
StreamBytesTransferred:当前流中的字节数,复制操作开始以来,已从源文件移交到目标文件的总数。
dwStreamNumber:当前流的句柄。第一次调用 CopyProgressRoutine 时,流编号是 1。
dwCallbackReason:以下值之一
CALLBACK_CHUNK_FINISHED:数据文件的另一部分被复制。
CALLBACK_STREAM_SWITCH:另一个流被创造并且将被复制。这是给出了第一次调用回调例程时的回调原因。
hSourceFile:源文件的句柄。
hDestinationFile:目标文件的句柄。
lpData:CopyFileEx等函数传递的参数
七。移动文件/文件更改名称
BOOL WINAPI MoveFile( _In_ LPCTSTR lpExistingFileName, _In_ LPCTSTR lpNewFileName );lpExistingFileName:原文件名
lpNewFileName:目的文件名 返回值:成功返回非0,失败返回0 注意:不支持跨卷移动文件,可以使用CopyFile,然后DeleteFile,或者使用SHFileOperation
2.MoveFileWithProgress MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/aa365242(v=vs.85).aspx 函数原型:
BOOL WINAPI MoveFileWithProgress( _In_ LPCTSTR lpExistingFileName, _In_opt_ LPCTSTR lpNewFileName, _In_opt_ LPPROGRESS_ROUTINE lpProgressRoutine, _In_opt_ LPVOID lpData, _In_ DWORD dwFlags );
lpExistingFileName:原文件名
lpNewFileName:目的文件名
lpProgressRoutine:指向一个回调函数的指针,回调函数用于接收移动进度等信息
lpData:要传给回调函数的数据指针
dwFlags:标志:(红色为常用的)
MOVEFILE_COPY_ALLOWED:如果文件移动到不同的卷,函数通过使用 CopyFile 和 DeleteFile 函数来模拟这一举动。如果该文件成功复制到一个不同的卷和原始文件是不能被删除,此函数成功留下的源文件的完整。使用此值不能同时用MOVEFILE_DELAY_UNTIL_REBOOT。
MOVEFILE_CREATE_HARDLINK:保留供将来使用。
MOVEFILE_DELAY_UNTIL_REBOOT:系统并不移动文件,直到重新启动操作系统。立即执行 AUTOCHK 后,但在创建任何分页文件之前,系统将该文件移动。因此,此参数启用的功能从先前启动删除分页文件。如果过程是在用户属于管理员组或本地系统帐户的上下文中,仅可以使用此值。此值不能用 MOVEFILE_COPY_ALLOWED。
MOVEFILE_FAIL_IF_NOT_TRACKABLE:如果源文件是链接的源,但该文件不能在移动后跟踪函数将失败。如果目标是用 FAT 文件系统格式化的卷,可以出现这种情况。
MOVEFILE_REPLACE_EXISTING:如果文件命名 lpNewFileName 存在,函数将其内容覆盖为lpExistingFileName 文件的内容。如果 lpNewFileName 或 lpExistingFileName 是目录,不能使用此值。
MOVEFILE_WRITE_THROUGH:函数不返回直到文件实际上已经在磁盘上。设置此值保证移动执行如拷贝和删除的操作刷新到磁盘之前,该函数返回。如果设置MOVEFILE_DELAY_UNTIL_REBOOT 此值没有任何作用。
- 上一篇: 统计数据库每天的数据增长量的脚本
- 下一篇: xhprof PHP的性能监控神器 mac 环境