文件系统是抽象的.是windows在软件层面提供的一层虚拟的数据结构.
文件系统分为NTFS 跟 FAT32. 具体看看两者的区别吧.
磁盘分区容量.
单个文件容量. 意思就是一个文件可以是多大的. NTFS 是可以4G以上的大文件. FAT32则不可以.
EFS加密. 这个加密主要针对当前用户的(例如Admins 管理员账户) 具体可以 点击一个文件. 文件->属性 -> 高级 -> 加密保护文件内容.
如果在当前用户则不会有什么结果. 但是如果换了用户访问.则不可以访问这个加密文件了.
加密后的文件.
文件颜色都会改变.
磁盘配额 意思就是可以限制别的用户访问这个硬盘多少G内存.
具体设置 xp下 盘符属性-> 配额
关于上面的讲解我们只需要了解即可.不深究.具体的的是学习API. API为我们封装好了.我们并不用关心NTFS 或者FAT32
标题中文件为什么添加了引号. 意思是不光可以操作文件. 在windows系统中.一切东西都虚拟为了文件. 例如管道 等等.. 都可以使用这些API.
api具体介绍
卷指的就是我们的的逻辑硬盘. 例如C盘.
目录则是C盘里面的文件夹. 文件夹里面可能还是以文件夹. 也可能是文件.
卷操作API 很简单. 常用的就四个.
DWORD GetLogIcalDrives() 获取卷 返回值是10进制.我们需要转化成16进制.然后转换成二进制查看.每一位为1代表有这个磁盘.否则则没有
GetLogIcalDriveStrings(buffsize,buf) 获取一个卷的盘符的字符串
GetDriveType(""目录名称") 获取卷的类型
GetVolumeInformation() 获取卷的类型
如以下代码例子:
// A.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <Windows.h>
int main()
{
//1.获取磁盘逻辑驱动卷
DWORD dwGetDrives = GetLogicalDrives();
/*
例如我的返回值是 252
转化为16进制 FC
转化为二进制 11111100 代表我们有六个磁盘.
CDEFGH 而我的恰好就是 CDEFGH 盘.
*/
//2.获取磁盘卷字符串.
TCHAR wszBuf[1024] = { NULL };
DWORD dwSize = sizeof(TCHAR) * 1024;
GetLogicalDriveStringsW(dwSize, wszBuf);
/*
逻辑驱动器返回后会存在wszBuf里面. 自己做分割即可.
例如 C:\ B:\
*/
//3.根据指定盘符获取它的类型. 可以移除的还是不可以移除的.
DWORD dwDriveType = GetDriveTypeW(TEXT("C:\\")); //具体返回值查询MSDN 注意从0开始
//4.获取卷的详细信息.
DWORD dwVolumneSerial = 0; //驱动卷的序列号(不是硬盘序列号)
DWORD dwFileMaxLen = 0; //系统允许的最大文件名的长度
DWORD dwFileSystem = 0; //文件系统标识.
TCHAR dwFileSystemBuffer[255] = { 0 }; //文件操作系统的名称
TCHAR szVolName[255] = { 0 }; //返回的卷的别名
GetVolumeInformationW(
TEXT("c:\\"), // IN参数 你要查看那个卷的信息
szVolName, // OUT参数. 查询到的卷的别名会给你.例如你的别名是C
sizeof(TCHAR) * 255, // IN参数. 上面缓冲区的大小.
&dwVolumneSerial, // OUT 驱动卷的序列号
&dwFileMaxLen, // OUT 写文件读文件等等文件名最大可以是多大.
&dwFileSystem, // OUT 文件操作系统标识.有多中宏组合,具体可以查询MSDN. 标识你这个文件是
dwFileSystemBuffer, //你当前系统是 NTFS 还是FAT32
sizeof(TCHAR) * 255 //上面缓冲区的大小.
);
return 0;
}
CreateDirectory();//创建目录 RemoveDirectory();//删除目录 MoveFile(); //修改目录名称. GetCurrentDirectory(); //获取进程当前目录 SetCurrentDirectory(); //设置进程当前目录.
具体代码例子:
main函数调用即可.
void GetDirectoryApi()
{
CreateDirectory(TEXT("D:\\123"),NULL);//创建目录
MoveFile(TEXT("D:\\123"), TEXT("D:\\456")); //修改目录名称.
RemoveDirectory(TEXT("D:\\456"));//删除目录
TCHAR szCurrentDirectoryBuffer[255] = { 0 };
DWORD dwBuffsize = sizeof(TCHAR) * 255;
GetCurrentDirectory(dwBuffsize, szCurrentDirectoryBuffer); //获取当前目录
SetCurrentDirectory(szCurrentDirectoryBuffer); //设置当前目录.
}
CreateFile( ) 创建文件
DeleteFile(); 删除文件
CloseHandle(); 关闭文件句柄
GetFileSize(); 获取文件大小.
ReadFile(); 读文件
WriteFile(); 写文件
CopyFile(); 拷贝文件
具体看如下代码详解参数意义.
void OptFileApi()
{
//1.创建文件
HANDLE hFile = CreateFile(
TEXT("D:\\123.txt"), //你要创建的文件名
GENERIC_READ | GENERIC_WRITE, // 创建的这个文件只读模式创建时只写模式创建还是读写都可以.如果只读则不可以写.
0, // 文件共享模式. 意思就是你这个文件创建完毕之后.当前读写只能有一个人在用,其他人不能操作. 为0就是排他. 或者说你可以设置为其他人可以读.
NULL, // 每个内核对象都有的SD安全属性
OPEN_EXISTING, //创建文件的信息. 你这个文件是文件不存在就创建 还是打开已经存在的. 还是总是创建新的.
FILE_ATTRIBUTE_NORMAL, //创建的文件属性. 意思就是我创建的这个文件是隐藏文件啊 还是别的文件. 反正就是属性.
NULL
);
//2.获取文件大小
DWORD dwLowSize = 0;
DWORD dwHighSize = 0;
dwLowSize = GetFileSize(hFile, &dwHighSize); //如果是32位系统.返回值存储了大小.如果是64位系统.则高32位也会存储.
//3.写文件
TCHAR szBuffer[1024] =TEXT("HelloFile");
DWORD dwSize = sizeof(TCHAR) * 1024;
DWORD OutSize = 0;
WriteFile(hFile, //往哪个文件中写
szBuffer, //写入的Buffer数据
dwSize, //写入的大小
&OutSize, //实际写入的大小.操作系统返回给你
NULL); //异步操作不需要
//4.读文件
//4.1设置File读取位置
SetFilePointer(hFile, //读取那个文件
1, //低32位的偏移.具体偏移 就是从文件开始位置 + 偏移位置读取. 如果是64位那么第三个参数也要使用.
0,
FILE_BEGIN //偏移起始位置. 文件开始 文件结束. 还是文件中间
);
ReadFile(hFile, //读哪个
szBuffer, //读入的数据放到Buffer
dwSize, //Buffer大小
&OutSize, //实际读入的大小.操作系统返回给你
NULL); //异步操作不需要
CloseHandle(hFile);
//5.拷贝文件
CopyFile(
TEXT("D:\\123.txt"), //源文件
TEXT("E:\\123.txt"), //目的文件
TRUE //是否覆盖目的文件
);
//.关闭文件句柄
//6.删除文件
DeleteFile(TEXT("d:\\123.txt"));
}
我们上几篇博客讲解了CreateFileMaping 创建物理内存页. 那么我们可以把文件跟物理页绑定.
例如下图:
其实文件映射到物理内存了.那么我们直接操作内存就可以. 想相当于操作文件.
具体步骤.
1.创建文件.如果文件已经存在.则打开文件.获取文件句柄.
2.申请共享内存.使用CreateFileMapping. 将文件句柄传入.
3,将物理内存映射到线性地址(虚拟内存)中.使用 MapViewOfFile.
4.操作的虚拟地址就是文件内容了.
具体看如下代码.
void OptFileApi()
{
//1.创建文件
HANDLE hFile = CreateFile(
TEXT("D:\\calc.exe"), //你要创建的文件名
GENERIC_READ | GENERIC_WRITE, // 创建的这个文件只读模式创建时只写模式创建还是读写都可以.如果只读则不可以写.
0, // 文件共享模式. 意思就是你这个文件创建完毕之后.当前读写只能有一个人在用,其他人不能操作. 为0就是排他. 或者说你可以设置为其他人可以读.
NULL, // 每个内核对象都有的SD安全属性
OPEN_EXISTING, //创建文件的信息. 你这个文件是文件不存在就创建 还是打开已经存在的. 还是总是创建新的.
FILE_ATTRIBUTE_NORMAL, //创建的文件属性. 意思就是我创建的这个文件是隐藏文件啊 还是别的文件. 反正就是属性.
NULL
);
//2.创建内存物理页.跟文件挂靠
HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE,0, 0X1000, NULL); //读写的方式映射.不需要其它进程使用.
//3.映射到虚拟内存位置.
LPVOID szBuffer = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
//直接操作内存即可.
printf("%x",*(PDWORD)szBuffer); //打印前四个字节.
*(PDWORD)szBuffer = 0xFFFF0000; //修改文件前四个字节.
/*
此API可以 强制更新缓存.
BOOL FlushViewOfFile( LPCVOID lpBaseAddress, // starting address
SIZE_T dwNumberOfBytesToFlush // number of bytes in range);
*/
//4.取消映射
UnmapViewOfFile(szBuffer);
CloseHandle(hFileMap);
CloseHandle(hFile);
}
如果映射到虚拟内存中.也就是调用完毕 MapViewOfFile的时候.其缓冲区就是文件的起始位置. 可以直接指针修改了.
例如我们的Calc计算器.头四个字节已经被我们修改成了 0xFFFF了.
很简单. 多动手做即可.
如下图所示:
A进程映射物理内存.并且映射文件. B进程使用这块物理内存其实也是操作文件.
只不过附带了一个文件.修改修改物理内存的时候变成修改文件了.具体代码不在贴了.
主需要申请共享内存的时候给定一个名字. 那么双进程就可以使用了.
完整代码
bool BasicForm::xxxx()
{
auto filepath = edt_file_path->GetText();
HANDLE hFile = INVALID_HANDLE_VALUE;
HANDLE hFileMap = NULL;
LPVOID lpBase = NULL;
LARGE_INTEGER laFileSize = { 0 };
//1.打开文件以及获取文件大小
hFile = CreateFile(
filepath.c_str(),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (INVALID_HANDLE_VALUE == hFile)
{
return false;
}
if (0 == GetFileSizeEx(hFile, &laFileSize))
{
CloseHandle(hFile);
return false;
}
//2.创建内存物理页.跟文件挂靠
hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, laFileSize.LowPart, laFileSize.HighPart, NULL); //读写的方式映射.不需要其它进程使用.
if (nullptr == hFileMap)
{
CloseHandle(hFile);
return false;
}
//3.映射到虚拟内存位置.
lpBase = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if (nullptr == lpBase)
{
CloseHandle(hFileMap);
CloseHandle(hFile);
return 0;
}
//直接操作内存即可.
printf("%x", *(PDWORD)lpBase); //打印前四个字节.
*(PDWORD)lpBase = 0xFFFF0000; //修改文件前四个字节.
/*
此API可以 强制更新缓存.
BOOL FlushViewOfFile( LPCVOID lpBaseAddress, // starting address
SIZE_T dwNumberOfBytesToFlush // number of bytes in range);
*/
//4.取消映射
if (nullptr != lpBase)
{
UnmapViewOfFile(lpBase);
lpBase = nullptr;
}
if (nullptr != hFileMap)
{
CloseHandle(hFileMap);
hFileMap = nullptr;
}
if (INVALID_HANDLE_VALUE != nullptr)
{
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
}
return true;
}