一、基本概念
1、磁盘分区(Partitions)
磁盘是装到计算机上的存储设备,比如常见的硬盘。磁盘分区是为了便于管理和使用物理硬盘,而在一个物理硬盘上划分可以各自独立工作的一些逻辑磁盘。比如一块80GB的硬盘可以划分为4个20GB的分区来使用,对操作系统来说这4个20GB的分区是4块独立的逻辑磁盘。
2、卷(Volumes)
卷,也称为逻辑驱动器,是NTFS、FAT32等文件系统组织结构的最高层。卷是存储设备(如硬盘)上由文件系统管理的一块区域,是在逻辑上相互隔离的存储单元。一个磁盘分区至少含有一个卷,卷也可以存在于多个磁盘分区上,仅存在于一个磁盘分区上的卷称为“简单卷”,仅存在于多个磁盘分区上的卷称为“多分区卷”或“跨区卷”。在最常见的情况下,一个分区只包含一个卷,一个卷也只存在于一个分区上,所以两者容易混淆。卷存在卷标,程序可以通过卷标访问卷。
在Windows系统中,文件路径的长度被限制260个字符,这260个字符包括卷标、路径、主文件名和扩展名以及分隔符,因此,文件名的长度为260减去文件所在目标的路径长度。在Windows NT系统中,字符使用的是Unicode宽字符。英文和中文都占用两个字节。
特殊字符则不能在文件名的任何位置出现。特殊字符一共有9个,分别为:“/”、“∣”“\”、“*”、“?”、"<"、“>”、“””、“:”。特殊字符在系统或者命令行下代表一些特殊意义。
二、文件系统API
三、注意点
1、文件名,可以是绝对路径或相对路径。
2、重命名也是用移动文件MoveFile。
3、可以看到:
◇在进程中使用相对路径,则相对路径的起始点是程序的当前路径而不是可执行文件所在的路径。
◇进程的当前路径在默认情况下是应用程序可执行文件所在的路径。
◇模块路径与程序的当前路径是两个概念,进程的主程序和进程中所加载的所有DLL都是进程的模块。
四、示例程序
1、示例遍历指定目录
*《精通Windows API》
* 示例代码
* sub_dir.c
* 4.3.5 遍历目录下的文件和子目录
************************************* */
/* 头文件 */
#include < windows.h >
#include < stdio.h >
/* ************************************
* DWORD EnumerateFileInDrectory(LPSTR szPath)
* 功能 遍历目录下的文件和子目录,将显示文件的
* 文件和文件夹隐藏、加密的属性
* 参数 LPTSTR szPath,为需遍历的路径
* 返回值 0代表执行完成,1代码发生错误
************************************* */
DWORD EnumerateFileInDrectory(LPSTR szPath)
{
WIN32_FIND_DATA FindFileData;
HANDLE hListFile;
CHAR szFilePath[MAX_PATH];
// 构造代表子目录和文件夹路径的字符串,使用通配符“*”
lstrcpy(szFilePath, szPath);
// 注释的代码可以用于查找所有以“.txt结尾”的文件。
// lstrcat(szFilePath, "\\*.txt");
lstrcat(szFilePath, " \\* " );
// 查找第一个文件/目录,获得查找句柄
hListFile = FindFirstFile(szFilePath, & FindFileData);
// 判断句柄
if (hListFile == INVALID_HANDLE_VALUE)
{
printf( " 错误:%d " ,GetLastError());
return 1 ;
}
else
{
do
{
/* 如果不想显示代表本级目录和上级目录的“.”和“..”,
可以使用注释部分的代码过滤。
if(lstrcmp(FindFileData.cFileName,TEXT("."))==0||
lstrcmp(FindFileData.cFileName,TEXT(".."))==0)
{
continue;
}
*/
// 打印文件名、目录名
printf( " %s\t\t " ,FindFileData.cFileName);
// 判断文件属性,加密文件或文件夹
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)
{
printf( " <加密> " );
}
// 判断文件属性,隐藏文件或文件夹
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
{
printf( " <隐藏> " );
}
// 判断文件属性,目录
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
printf( " <DIR> " );
}
// 读者可根据文件属性表中的内容自行添加判断文件属性。
printf( " \n " );
}
while (FindNextFile(hListFile, & FindFileData));
}
return 0 ;
}
/* ************************************
* int main(int argc, PCHAR argv[])
* 功能 调用ListFileInDrectory
* 遍历目录下的文件和子目录
* 参数 argv[1]为需遍历的路径,如果为空则获取
* 当前路径
************************************* */
int main( int argc, PCHAR argv[])
{
if (argc == 2 )
{
EnumerateFileInDrectory(argv[ 1 ]);
}
else
{
CHAR szCurrentPath[MAX_PATH];
GetCurrentDirectory(MAX_PATH,szCurrentPath);
EnumerateFileInDrectory(szCurrentPath);
}
return 0 ;
}
2、示例遍历目录树
*《精通Windows API》
* 示例代码
* tree.c
* 4.3.6 递归遍历目录树
* 2007年10月
************************************* */
/* 头文件 */
#include < windows.h >
#include < stdio.h >
/* 预处理申明 */
#pragma comment (lib, "User32.lib")
/* 函数申明 */
DWORD ListAllFileInDrectory(LPSTR szPath);
/* 全局变量 */
// 记录所有的文件和目录数
DWORD dwTotalFileNum = 0 ;
/* ************************************
* DWORD ListAllFileInDrectory(LPSTR szPath)
* 功能 遍历目录及所有子目录,打印路径
*
* 参数 LPTSTR szPath,为需遍历的目录
*
* 返回值 0代表执行完成,1代码发生错误
************************************* */
DWORD ListAllFileInDrectory(LPSTR szPath)
{
CHAR szFilePath[MAX_PATH];
WIN32_FIND_DATA FindFileData;
HANDLE hListFile;
CHAR szFullPath[MAX_PATH];
// 构造代表子目录和文件夹路径的字符串,使用通配符“*”
lstrcpy(szFilePath, szPath);
lstrcat(szFilePath, " \\* " );
// 查找第一个文件/目录,获得查找句柄
hListFile = FindFirstFile(szFilePath, & FindFileData);
if (hListFile == INVALID_HANDLE_VALUE)
{
printf( " 错误:%d " ,GetLastError());
return 1 ;
}
else
{
do
{
// 过滤“.”和“..”,不需要遍历
if (lstrcmp(FindFileData.cFileName,TEXT( " . " )) == 0 ||
lstrcmp(FindFileData.cFileName,TEXT( " .. " )) == 0 )
{
continue ;
}
// 构造成全路径
wsprintf(szFullPath, " %s\\%s " ,
szPath,FindFileData.cFileName);
dwTotalFileNum ++ ;
// 打印
printf( " \n%d\t%s\t " ,dwTotalFileNum,szFullPath);
// 如果是目录,则递归调用,列举下级目录
if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
printf( " <DIR> " );
ListAllFileInDrectory(szFullPath);
}
}
while (FindNextFile(hListFile, & FindFileData));
}
return 0 ;
}
/* ************************************
* int main(int argc, PCHAR argv[])
* 功能 调用ListAllFileInDrectory
* 遍历目录下的文件和子目录
*
* 参数 argv[1]为需遍历的路径,如果为空则获取
* 当前路径
*
* 2007年10月
*
************************************* */
int main( int argc, PCHAR argv[])
{
if (argc == 2 )
{
ListAllFileInDrectory(argv[ 1 ]);
}
else
{
CHAR szCurrentPath[MAX_PATH];
GetCurrentDirectory(MAX_PATH,szCurrentPath);
ListAllFileInDrectory(szCurrentPath);
}
return 0 ;
}
3、示例获取当前时间
*《精通Windows API》
* 示例代码
* attr.c
* 4.3.7 获取、设置文件属性和时间
************************************* */
/* 头文件 */
#include < windows.h >
#include < stdio.h >
/* 函数申明 */
DWORD ShowFileTime(PFILETIME lptime);
DWORD ShowFileSize(DWORD dwFileSizeHigh,DWORD dwFileSizeLow);
DWORD ShowFileAttrInfo(DWORD dwAttribute);
DWORD SetFileHiddenAndReadonly(LPSTR szFileName);
/* ************************************
* DWORD ShowFileAttributes(LPSTR szPath)
* 功能 获取并显示文件属性,
* 调用ShowFileTime、ShowFileSize和
* ShowFileAttrInfo函数
*
* 参数 LPTSTR szPath,获取并显示此文件的属性
*
* 返回值 0代表执行完成,1代码发生错误
************************************* */
DWORD ShowFileAttributes(LPSTR szPath)
{
// 文件属性结构
WIN32_FILE_ATTRIBUTE_DATA wfad;
printf( " 文件:%s\n " ,szPath);
// 获取文件属性
if ( ! GetFileAttributesEx(szPath,
GetFileExInfoStandard,
& wfad))
{
printf( " 获取文件属性错误:%d\n " ,GetLastError());
return 1 ;
}
// 显示相关时间
printf( " 创建时间:\t " );
ShowFileTime( & (wfad.ftCreationTime));
printf( " 最后访问时间:\t " );
ShowFileTime( & (wfad.ftLastAccessTime));
printf( " 最后修改时间:\t " );
ShowFileTime( & (wfad.ftLastWriteTime));
// 显示文件大小
ShowFileSize(wfad.nFileSizeHigh,wfad.nFileSizeLow);
// 显示文件属性
ShowFileAttrInfo(wfad.dwFileAttributes);
return 0 ;
}
/* ************************************
* DWORD ShowFileAttrInfo(DWORD dwAttribute)
* 功能 打印将文件属性
*
* 参数 DWORD dwAttribute,文件属性
*
* 返回值 0
************************************* */
DWORD ShowFileAttrInfo(DWORD dwAttribute)
{
// 依次判断属性,并显示。
printf( " 文件属性:\t " );
if (dwAttribute & FILE_ATTRIBUTE_ARCHIVE)
printf( " <ARCHIVE> " );
if (dwAttribute & FILE_ATTRIBUTE_COMPRESSED)
printf( " <压缩> " );
if (dwAttribute & FILE_ATTRIBUTE_DIRECTORY)
printf( " <目录> " );
if (dwAttribute & FILE_ATTRIBUTE_ENCRYPTED)
printf( " <加密> " );
if (dwAttribute & FILE_ATTRIBUTE_HIDDEN)
printf( " <隐藏> " );
if (dwAttribute & FILE_ATTRIBUTE_NORMAL)
printf( " <NORMAL> " );
if (dwAttribute & FILE_ATTRIBUTE_OFFLINE)
printf( " <OFFLINE> " );
if (dwAttribute & FILE_ATTRIBUTE_READONLY)
printf( " <只读> " );
if (dwAttribute & FILE_ATTRIBUTE_SPARSE_FILE)
printf( " <SPARSE> " );
if (dwAttribute & FILE_ATTRIBUTE_SYSTEM)
printf( " <系统文件> " );
if (dwAttribute & FILE_ATTRIBUTE_TEMPORARY)
printf( " <临时文件> " );
printf( " \n " );
return 0 ;
}
/* ************************************
* DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow)
* 功能 打印文件大小信息
*
* 参数 DWORD dwFileSizeHigh,文件大小高32位
* DWORD dwFileSizeLow,文件大小低32位
*
* 返回值 0
************************************* */
DWORD ShowFileSize(DWORD dwFileSizeHigh, DWORD dwFileSizeLow)
{
ULONGLONG liFileSize;
liFileSize = dwFileSizeHigh;
// 高们移动32位
liFileSize <<= sizeof (DWORD) * 8 ;
liFileSize += dwFileSizeLow;
printf( " 文件大小:\t%I64u 字节\n " ,liFileSize);
return 0 ;
}
/* ************************************
*DWORD ShowFileTime(PFILETIME lptime)
* 功能 轮换文件时间,将打印
*
* 参数 PFILETIME lptime,指向文件时间的指针
*
* 返回值 0
************************************* */
DWORD ShowFileTime(PFILETIME lptime)
{
// 文件时间结构
FILETIME ftLocal;
// 系统时间结构
SYSTEMTIME st;
// 调整为系统所在时区的时间
FileTimeToLocalFileTime(
lptime,
& ftLocal
);
// 将文件时间转换为SYSTEMTIME格式,便于显示。
FileTimeToSystemTime(
& ftLocal,
& st
);
// 显示时间信息字符串
printf( " %4d年%.2d月%#02d日,%.2d:%.2d:%.2d\n " ,
st.wYear,st.wMonth,st.wDay,st.wHour,st.wMinute,st.wSecond);
return 0 ;
}
/* ************************************
* DWORD SetFileHiddenAndReadonly(LPSTR szFileName)
* 功能 将指定的文件设置为隐藏和只读
*
* 参数 LPSTR szFileName,文件路径
*
* 返回值 0
************************************* */
DWORD SetFileHiddenAndReadonly(LPSTR szFileName)
{
// 获取原来的文件属性
DWORD dwFileAttributes = GetFileAttributes(szFileName);
// 将只读和隐藏属性附加到原来的文件属性上
dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
// 设置文件属性,并判断是否成功。
if (SetFileAttributes(szFileName, dwFileAttributes))
{
printf( " 文件%s的隐藏和属性设置成功\n " ,szFileName);
}
else
{
printf( " 属性设置; %d\n " ,GetLastError());
}
return 0 ;
}
/* ************************************
* int main(int argc, PCHAR argv[])
* 功能 设置和获取文件属性等
*
* 参数 显示第一个参数指定文件的属性、时间、大小
* 将第二个参数的属性设置为隐藏、只读。
*
* 返回值 0代表执行完成,1代码发生错误
************************************* */
int main( int argc, PCHAR argv[])
{
if (argc != 3 )
{
printf( " 请输入参数\n " );
printf( " 显示第一个参数指定文件的属性、时间、大小;\n " );
printf( " 将第二个参数的属性设置为隐藏、只读。 " );
return 1 ;
}
ShowFileAttributes(argv[ 1 ]);
SetFileHiddenAndReadonly(argv[ 2 ]);
return 0 ;
}
五、内存映射文件
◇使用Mapping File提高文件读写的效率。
◇通过Mapping File在进程间共享内存。
◇通过文件句柄获得文件路径。
文件映射( mapping)是一种在将文件内容映射到进程的虚拟地址空间的技术。视图(View)是一段虚拟地址空间,进程可以通过View来存取文件的内容,视图是一段内存,可以使用指针来操作视图。使用的文件映射之后,读写文件就如同对读写内存一样简单。在使用文件映射时需要创建映射对象,映射对象分为命名的和未命名的。映射对象还存取权限。
使用文件映射至少有3个好处,一是因为文件是存储于硬盘上的,而文件视图是一段内存,使用文件映射操作时更方便;二是效率更高;三是可以在不同的进程间共享数据。
文件映射依赖于系统虚拟内存管理的分页机制。
1、如何使用文件映射
*《精通Windows API》
* 示例代码
* file_map.c
* 4.4.1 使用Mapping File提高文件读写的效率
************************************* */
/* 头文件 */
#include < windows.h >
#include < stdio.h >
/* 预处理申明 */
#define BUFFSIZE 1024 // 内存大小
#define FILE_MAP_START 0x28804 // 文件映射的起始的位置
/* 全局变量 */
LPTSTR lpcTheFile = TEXT( " test.dat " ); // 文件名
/* ************************************
* int main(void)
* 功能 演示使用文件mapping
*
* 参数 无
*
* 返回值 0代表执行完成,1代表发生错误
************************************* */
int main( void )
{
HANDLE hMapFile; // 文件内存映射区域的句柄
HANDLE hFile; // 文件的句柄
DWORD dBytesWritten; // 写入的字节数
DWORD dwFileSize; // 文件大小
DWORD dwFileMapSize; // 文件映射的大小
DWORD dwMapViewSize; // 视图(View)的大小
DWORD dwFileMapStart; // 文件映射视图的起始位置
DWORD dwSysGran; // 系统内存分配的粒度
SYSTEM_INFO SysInfo; // 系统信息
LPVOID lpMapAddress; // 内在映射区域的起始位置
PCHAR pData; // 数据
INT i; // 循环变量
INT iData;
INT iViewDelta;
BYTE cMapBuffer[ 32 ]; // 存储从mapping中计出的数据
// 创建一个文件
hFile = CreateFile(lpcTheFile,
GENERIC_READ | GENERIC_WRITE,
0 ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
// 判断文件是否创建成功
if (hFile == INVALID_HANDLE_VALUE)
{
printf( " CreateFile error\n " ,GetLastError);
return 1 ;
}
// 依次写入整数,一共写入65535个整数
// 在32位平台下,大小为65535*32
for (i = 0 ; i < 65535 ; i ++ )
{
WriteFile (hFile, & i, sizeof (i), & dBytesWritten, NULL);
}
// 查看写入完成后的文件大小
dwFileSize = GetFileSize(hFile, NULL);
printf( " 文件大小: %d\n " , dwFileSize);
// 获取系统信息,内存分配粒度
// 获取分配粒度,进行下面的几个计算,
// 目的是为了映射的数据与系统内存分配粒度对齐,提高内存访问效率
GetSystemInfo( & SysInfo);
dwSysGran = SysInfo.dwAllocationGranularity;
// 计算mapping的起始位置
dwFileMapStart = (FILE_MAP_START / dwSysGran) * dwSysGran;
// 计算mapping view的大小
dwMapViewSize = (FILE_MAP_START % dwSysGran) + BUFFSIZE;
// 计算mapping的大小
dwFileMapSize = FILE_MAP_START + BUFFSIZE;
// 计算需要读取的数据的偏移
iViewDelta = FILE_MAP_START - dwFileMapStart;
// 创建File mapping
hMapFile = CreateFileMapping( hFile, // 需要映射的文件的句柄
NULL, // 安全选项:默认
PAGE_READWRITE, // 可读,可写
0 , // mapping对象的大小,高位
dwFileMapSize, // mapping对象的大小,低位
NULL); // mapping对象的名字
if (hMapFile == NULL)
{
printf( " CreateFileMapping error: %d\n " , GetLastError() );
return 1 ;
}
// 映射view
lpMapAddress = MapViewOfFile(hMapFile, // mapping对象的句柄
FILE_MAP_ALL_ACCESS, // 可读,可写
0 , // 映射的文件偏移,高32位
dwFileMapStart, // 映射的文件偏移,低32位
dwMapViewSize); // 映射到View的数据大小
if (lpMapAddress == NULL)
{
printf( " MapViewOfFile error: %d\n " , GetLastError());
return 1 ;
}
printf ( " 文件map view相对于文件的起始位置: 0x%x\n " ,
dwFileMapStart);
printf ( " 文件map view的大小:0x%x\n " , dwMapViewSize);
printf ( " 文件mapping对象的大小:0x%x\n " , dwFileMapSize);
printf ( " 从相对于map view 0x%x 字节的位置读取数据, " , iViewDelta);
// 将指向数据的指针偏移,到达我们关心的地方
pData = (PCHAR) lpMapAddress + iViewDelta;
// 读取数据,赋值给变量
iData = * (PINT)pData;
// 显示读取的数据
printf ( " 为:0x%.8x\n " , iData);
// 从mapping中复制数据,32个字节,并打印
CopyMemory(cMapBuffer,lpMapAddress, 32 );
printf( " lpMapAddress起始的32字节是: " );
for (i = 0 ; i < 32 ; i ++ )
{
printf( " 0x%.2x " ,cMapBuffer[i]);
}
// 将mapping的前32个字节用0xff填充
FillMemory(lpMapAddress, 32 ,(BYTE) 0xff );
// 将映射的数据写回到硬盘上
FlushViewOfFile(lpMapAddress,dwMapViewSize);
printf( " \n已经将lpMapAddress开始的32字节使用0xff填充。\n " );
// 关闭mapping对象
if ( ! CloseHandle(hMapFile))
{
printf( " \nclosing the mapping object error %d! " ,
GetLastError());
}
// 关闭文件
if ( ! CloseHandle(hFile))
{
printf( " \nError %ld occurred closing the file! " ,
GetLastError());
}
return 0 ;
}
2、如何使用文件映射进行内存共享
1)通过Mapping File在进程间传递和共享数据
进程间通信、共享数据有很多种方法,文件映射是常用的一种方法。因为mapping对象系统中是全局的,一个进程创建的Mapping对象可以从另外一个进程中打开,映射视图就进程间共享的内存了。一般在共享的内存数据量比较大时,选择使用文件映射进行共享。
示例代码
*《精通Windows API》
* 示例代码
* pro_s1.c
* 4.4.2 通过Mapping File在进程间共享内存
************************************* */
/* 头文件 */
#include < windows.h >
#include < stdio.h >
#include < conio.h >
/* 预处理申明 */
#define BUF_SIZE 256
/* 全局变量 */
LPTSTR szName = TEXT( " SharedFileMappingObject " );
LPTSTR szMsg = TEXT( " 进程的消息 " );
/* ************************************
* int main(void)
* 功能 演示文件mapping共享内存,写入数据到共享内存
*
* 参数 无
*
* 返回值 0代表执行完成,代表发生错误
************************************* */
void main( int argc, PCHAR argv[])
{
// 文件映射句柄
HANDLE hMapFile;
// 共享数据缓冲区指针
LPTSTR pBuf;
// 创建命名的文件映射,不代表任务硬盘上的文件
hMapFile = CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0 ,
BUF_SIZE,
szName);
if (hMapFile == NULL || hMapFile == INVALID_HANDLE_VALUE)
{
printf( " CreateFileMapping error: %d\n " , GetLastError());
return ;
}
// 创建View
pBuf = (LPTSTR) MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
0 ,
0 ,
BUF_SIZE);
if (pBuf == NULL)
{
printf( " MapViewOfFile error %d\n " , GetLastError());
return ;
}
// 将共享数据复制到文件映射中,如果运行时输入了参数则使用参数
if (argc == 1 )
{
CopyMemory((PVOID)pBuf, szMsg, strlen(szMsg));
}
else
{
DWORD dwCopyLen = (lstrlen(argv[ 1 ]) < BUF_SIZE) ? lstrlen(argv[ 1 ]): BUF_SIZE;
CopyMemory((PVOID)pBuf, argv[ 1 ], dwCopyLen);
}
printf( " 运行程序,完成运行后,按任意键退出。 " );
_getch();
// 取消映射,退出
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
}
*《精通Windows API》
* 示例代码
* pro_s2.c
* 4.4.2 通过Mapping File在进程间共享内存
************************************* */
#include < windows.h >
#include < stdio.h >
#include < conio.h >
/* 预处理申明 */
#pragma comment (lib, "User32.lib")
#define BUF_SIZE 256
/* 全局变量 */
TCHAR szName[] = TEXT( " SharedFileMappingObject " );
/* ************************************
* int main(void)
* 功能 演示文件mapping共享内存,从共享数据中读信息
*
* 参数 无
*
* 返回值 0代表执行完成,代表发生错误
************************************* */
void main()
{
HANDLE hMapFile;
LPTSTR pBuf;
// 打开文件mapping
hMapFile = OpenFileMapping(
FILE_MAP_ALL_ACCESS,
FALSE,
szName);
if (hMapFile == NULL)
{
printf( " OpenFileMapping error: %d.\n " , GetLastError());
return ;
}
// 映射
pBuf = MapViewOfFile(hMapFile,
FILE_MAP_ALL_ACCESS,
0 ,
0 ,
BUF_SIZE);
if (pBuf == NULL)
{
printf( " MapViewOfFile error %d\n " , GetLastError());
return ;
}
// 消息得到的共享数据
MessageBox(NULL, pBuf, TEXT( " Process2 " ), MB_OK);
// 取消mapping,关闭句柄,返回
UnmapViewOfFile(pBuf);
CloseHandle(hMapFile);
}
2)通过文件句柄获取文件路径
示例代码
*《精通Windows API》
* 示例代码
* handle_path.cpp
* 4.4.3 通过文件句柄获取文件路径
************************************* */
/* 头文件 */
#include < windows.h >
#include < stdio.h >
#include < tchar.h >
#include < string .h >
#include < psapi.h >
/* 预处理申明 */
#pragma comment (lib, "Psapi.lib")
#define BUFSIZE 512
/* 函数申明 */
BOOL GetFileNameFromHandle(HANDLE hFile) ;
/* ************************************
* BOOL GetFileNameFromHandle(HANDLE hFile)
* 功能 从文件句柄获取文件路径
*
* 参数 ANDLE hFile,需要获得路径的文件句柄
*
* 返回值BOOL 是否成功。
************************************* */
BOOL GetFileNameFromHandle(HANDLE hFile)
{
TCHAR pszFilename[MAX_PATH + 1 ];
HANDLE hFileMap;
PVOID pMem;
// 获得文件大小,并决断是否为
DWORD dwFileSizeHigh = 0 ;
DWORD dwFileSizeLow = GetFileSize(hFile, & dwFileSizeHigh);
if ( dwFileSizeLow == 0 && dwFileSizeHigh == 0 )
{
printf( " 不能map文件大小为的文件.\n " );
return FALSE;
}
// 创建mapping对象
hFileMap = CreateFileMapping(hFile,
NULL,
PAGE_READONLY,
0 ,
1 ,
NULL);
if ( ! hFileMap)
{
printf( " CreateFileMapping error: %d " ,GetLastError());
return FALSE;
}
pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0 , 0 , 1 );
if ( ! pMem)
{
printf( " MapViewOfFile error: %d " ,GetLastError());
return FALSE;
}
// 从mapping对象获得文件名
if ( 0 == GetMappedFileName (GetCurrentProcess(),
pMem,
pszFilename,
MAX_PATH))
{
printf( " GetMappedFileName error: %d " ,GetLastError());
return FALSE;
}
// 将设备名转换为路径
TCHAR szTemp[BUFSIZE] = { 0 };
if ( 0 == GetLogicalDriveStrings(BUFSIZE - 1 , szTemp))
{
printf( " GetLogicalDriveStrings error: %d " ,GetLastError());
return FALSE;
}
TCHAR szName[MAX_PATH];
TCHAR szDrive[ 3 ] = { 0 };
BOOL bFound = FALSE;
PTCHAR p = szTemp;
do
{
CopyMemory(szDrive,p, 2 * sizeof (TCHAR));
// 通过路径查找设备名
if ( ! QueryDosDevice(szDrive, szName, BUFSIZE))
{
printf( " QueryDosDevice error: %d " ,GetLastError());
return FALSE;
}
UINT uNameLen = lstrlen(szName);
if (uNameLen < MAX_PATH)
{
// 比较驱动器的设备名与文件设备名是否匹配
bFound = strncmp(pszFilename, szName,uNameLen) == 0 ;
if (bFound)
{
// 如果匹配,说明已经找到,构造路径。
TCHAR szTempFile[MAX_PATH];
wsprintf(szTempFile,
TEXT( " %s%s " ),
szDrive,
pszFilename + uNameLen);
lstrcpy(pszFilename, szTempFile);
}
}
// 循环到下一个NULL
while ( * p ++ );
} while ( ! bFound && * p);
UnmapViewOfFile(pMem);
CloseHandle(hFileMap);
printf( " File path is %s\n " , pszFilename);
return TRUE;
}
/* ************************************
* int main()
* 功能 查找第一个目录中第一个txt文件
* 打开文件,并根据文件句柄获得文件路径。
*
* 参数 未使用
*
* 返回值0表示成功,表示失败。
************************************* */
int main()
{
HANDLE hFile;
HANDLE hFind;
WIN32_FIND_DATA wfd;
hFind = FindFirstFile( " *.txt " , & wfd);
if (hFind == INVALID_HANDLE_VALUE)
{
printf( " can not find a file " );
return 1 ;
}
// CloseHandle(hFind);
printf( " find %s at current dir\n " ,wfd.cFileName);
hFile = CreateFile(wfd.cFileName,
GENERIC_READ | GENERIC_WRITE,
0 ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf( " create file error, %d " ,GetLastError());
}
else
{
GetFileNameFromHandle(hFile) ;
}
CloseHandle(hFile);
return 0 ;
}