Win32文件系统编程
Win32文件系统编程
一丶了解什么是文件系统
文件系统是抽象的.是windows在软件层面提供的一层虚拟的数据结构.
文件系统分为NTFS 跟 FAT32. 具体看看两者的区别吧.
磁盘分区容量.
单个文件容量. 意思就是一个文件可以是多大的. NTFS 是可以4G以上的大文件. FAT32则不可以.
EFS加密. 这个加密主要针对当前用户的(例如Admins 管理员账户) 具体可以 点击一个文件. 文件->属性 -> 高级 -> 加密保护文件内容.
如果在当前用户则不会有什么结果. 但是如果换了用户访问.则不可以访问这个加密文件了.
加密后的文件.
文件颜色都会改变.
磁盘配额 意思就是可以限制别的用户访问这个硬盘多少G内存.
具体设置 xp下 盘符属性-> 配额
关于上面的讲解我们只需要了解即可.不深究.具体的的是学习API. API为我们封装好了.我们并不用关心NTFS 或者FAT32
二丶Windows提供的操作 "文件" 的 API
标题中文件为什么添加了引号. 意思是不光可以操作文件. 在windows系统中.一切东西都虚拟为了文件. 例如管道 等等.. 都可以使用这些API.
api具体介绍
1.了解卷 文件 跟目录的关系. 卷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[] = { NULL };
DWORD dwSize = sizeof(TCHAR) * ;
GetLogicalDriveStringsW(dwSize, wszBuf);
/*
逻辑驱动器返回后会存在wszBuf里面. 自己做分割即可.
例如 C:\ B:\
*/ //3.根据指定盘符获取它的类型. 可以移除的还是不可以移除的.
DWORD dwDriveType = GetDriveTypeW(TEXT("C:\\")); //具体返回值查询MSDN 注意从0开始 //4.获取卷的详细信息.
DWORD dwVolumneSerial = ; //驱动卷的序列号(不是硬盘序列号)
DWORD dwFileMaxLen = ; //系统允许的最大文件名的长度
DWORD dwFileSystem = ; //文件系统标识.
TCHAR dwFileSystemBuffer[] = { }; //文件操作系统的名称 TCHAR szVolName[] = { }; //返回的卷的别名
GetVolumeInformationW(
TEXT("c:\\"), // IN参数 你要查看那个卷的信息
szVolName, // OUT参数. 查询到的卷的别名会给你.例如你的别名是C
sizeof(TCHAR) * , // IN参数. 上面缓冲区的大小.
&dwVolumneSerial, // OUT 驱动卷的序列号
&dwFileMaxLen, // OUT 写文件读文件等等文件名最大可以是多大.
&dwFileSystem, // OUT 文件操作系统标识.有多中宏组合,具体可以查询MSDN. 标识你这个文件是
dwFileSystemBuffer, //你当前系统是 NTFS 还是FAT32
sizeof(TCHAR) * //上面缓冲区的大小.
); return ;
}
2.文件夹(目录) 操作的相关API
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[] = { };
DWORD dwBuffsize = sizeof(TCHAR) * ; GetCurrentDirectory(dwBuffsize, szCurrentDirectoryBuffer); //获取当前目录
SetCurrentDirectory(szCurrentDirectoryBuffer); //设置当前目录.
}
3.文件操作相关API
CreateFile( ) 创建文件
DeleteFile(); 删除文件
CloseHandle(); 关闭文件句柄
GetFileSize(); 获取文件大小.
ReadFile(); 读文件
WriteFile(); 写文件
CopyFile(); 拷贝文件
具体看如下代码详解参数意义.
void OptFileApi()
{
//1.创建文件
HANDLE hFile = CreateFile(
TEXT("D:\\123.txt"), //你要创建的文件名
GENERIC_READ | GENERIC_WRITE, // 创建的这个文件只读模式创建时只写模式创建还是读写都可以.如果只读则不可以写.
, // 文件共享模式. 意思就是你这个文件创建完毕之后.当前读写只能有一个人在用,其他人不能操作. 为0就是排他. 或者说你可以设置为其他人可以读.
NULL, // 每个内核对象都有的SD安全属性
OPEN_EXISTING, //创建文件的信息. 你这个文件是文件不存在就创建 还是打开已经存在的. 还是总是创建新的.
FILE_ATTRIBUTE_NORMAL, //创建的文件属性. 意思就是我创建的这个文件是隐藏文件啊 还是别的文件. 反正就是属性.
NULL
);
//2.获取文件大小
DWORD dwLowSize = ;
DWORD dwHighSize = ;
dwLowSize = GetFileSize(hFile, &dwHighSize); //如果是32位系统.返回值存储了大小.如果是64位系统.则高32位也会存储.
//3.写文件
TCHAR szBuffer[] =TEXT("HelloFile");
DWORD dwSize = sizeof(TCHAR) * ;
DWORD OutSize = ;
WriteFile(hFile, //往哪个文件中写
szBuffer, //写入的Buffer数据
dwSize, //写入的大小
&OutSize, //实际写入的大小.操作系统返回给你
NULL); //异步操作不需要
//4.读文件
//4.1设置File读取位置
SetFilePointer(hFile, //读取那个文件
, //低32位的偏移.具体偏移 就是从文件开始位置 + 偏移位置读取. 如果是64位那么第三个参数也要使用.
,
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 Characteristic(LPCTSTR lpFileName)
{
//打开文件,读取头八个字节.
HANDLE hFile = CreateFile(
lpFileName,
GENERIC_READ | GENERIC_WRITE,
,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
); if (INVALID_HANDLE_VALUE == hFile)
return FALSE; //读取文件特征.这里判断是否是PE.读取节个数.以及节开头的标志. HANDLE hFileMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, , 0X1000, NULL);
if (NULL == hFileMap)
return FALSE; LPVOID szBuffer = MapViewOfFile(hFileMap, FILE_MAP_ALL_ACCESS, , , );
if (NULL == szBuffer)
return FALSE; UnmapViewOfFile(szBuffer);
CloseHandle(hFileMap);
CloseHandle(hFile);
return ;
}
Win32文件系统编程的更多相关文章
- Win32 OpenGL 编程( 1 ) Win32 下的 OpenGL 编程必须步骤
http://blog.csdn.net/vagrxie/article/details/4602961 Win32 OpenGL 编程( 1 ) Win32 下的 OpenGL 编程必须步骤 wri ...
- win32 C++制作美观按钮,告别win32 API编程中默认的灰色按钮
使用win32 API制作美观按钮,当鼠标移入/移出按钮时改变按钮背景颜色,类似HTML网页中的效果,告别win32 API编程中默认的灰色按钮,效果图见下面动图和视频. 下载地址: 按钮效果(win ...
- Win32多线程编程(1) — 基础概念篇
内核对象的基本概念 Windows系统是非开源的,它提供给我们的接口是用户模式的,即User-Mode API.当我们调用某个API时,需要从用户模式切换到内核模式的I/O System Serv ...
- Win32多线程编程(2) — 线程控制
Win32线程控制只有是围绕线程这一内核对象的创建.挂起.恢复.终结以及通信等操作,这些操作都依赖于Win32操作系统提供的一组API和具体编译器的C运行时库函数.本篇围绕这些操作接口介绍在Windo ...
- Win32多线程编程(3) — 线程同步与通信
一.线程间数据通信 系统从进程的地址空间中分配内存给线程栈使用.新线程与创建它的线程在相同的进程上下文中运行.因此,新线程可以访问进程内核对象的所有句柄.进程中的所有内存以及同一个进程中其他所有线 ...
- win32多线程编程
关于多线程多进程的学习,有没有好的书籍我接触的书里头关于多线程多进程部分,一是<操作系统原理>里面讲的相关概念 一个是<linux基础教程>里面讲的很简单的多线程多进程编程 ...
- win32串口编程
翻译自:ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.WIN32COM.v10.en/dnfiles/html/msdn_serial.htm 老外写的文章, ...
- pthread Win32多线程编程的一些知识和感想
研究遗传算法的一大诟病就是每次运行程序的结果并不是完全一样的,有时候能找到最优解有时候找不到最优解,这就是遗传算法的概率性导致的.那么怎么评价你的方法的好坏呐,这时候就要多次独立运行程序最后取结果的平 ...
- Win32 API编程——前言
一丶什么是Win32 API? 微软为了保护操作系统的安全性和稳定性,把系统分为内核层和用户层(内核层的代码只能在当CPU的特权级为R0状态下执行,用户层的代码在CPU特权级为R0和R3都能执行),w ...
随机推荐
- 《Linux就该这么学》第十六天课程
今天笔记有点少就不发了,分享一下第23章 使用OpenLDAP部署目录服务很实用 下面是DHCP动态管理地址,如需深入学习请前往 https://www.linuxprobe.com/chapter- ...
- 数据结构C语言版-队列
#include <stdlib.h> #include <stdio.h> #include <iostream> using namespace std; ty ...
- PAT乙级1003
1003 我要通过! (20 point(s)) “答案正确”是自动判题系统给出的最令人欢喜的回复.本题属于 PAT 的“答案正确”大派送 —— 只要读入的字符串满足下列条件,系统就输出“答案正确”, ...
- java操作FTP的一些工具方法
java操作FTP还是很方便的,有多种开源支持,这里在apache开源的基础上自己进行了一些设计,使用起来更顺手和快捷. 思路: 1.设计FTPHandler接口,可以对ftp,sftp进行统一操作, ...
- 未能加载文件或程序集“ .....WebUI ”或它的某一个依赖项,试图加载格式不正确的程序
编译Web网站没有问题(需要引用oracle.dataAccess.dll),在运行时报错如下: 解决: 1. 将项目编译生成x86模式(win7 64位) 2. 有可能本机运行有问题,发布到IIS, ...
- 在ExtJS中查看视频
listeners: { render: function() { win.update( '<video src="' + path+ '" width="100 ...
- mongdb的索引及备份
1. mongodb的索引 1.1 为什么mongdb需要创建索引 加快查询速度 进行数据的去重 1.2 mongodb创建简单的索引方法 语法: db.集合.ensureIndex({属性:1}), ...
- 通配符的匹配很全面, 但无法找到元素 'xxxxxxxx'
首先,一般配置通配符之前,你都会有如下xml头吧 <beans xmlns="http://www.springframework.org/schema/beans" xml ...
- centos7.2安装图文详解
centos镜像下载地址 https://www.centos.org/download/ Install CentOS 7 ----直接安装Test this media & instal ...
- Python之路【第一篇】Linux常见命令语句
查看当前目录: pwd 查看文件具体大小: ls -l 返回上一级: cd.. 返回根目录: cd / 创建一个隐藏文件: vim .test 显示隐藏文件: l ...