20170509Windows03_Windows文件操作

Windows I/O操作:

什么是Windows IO操作:

    1:任何系统和软件都会有自己的IO操作,所在的层级不同,IO操作的定义也会变得不同,C语言中的scanf和printf,openfile等也是IO操作。
    2:在语言的层面的IO都是指从文件读入为Input,写入到文件里面去是Output,而在操作系统上面,有几大类定义,队伍外部设备的操作都是IO操作,文件,usb,网络通讯等都是IO操作。

完成端口机制:

    1:Windows是一个多任务多线程的操作系统,多任务是指在Windows系统下面可执行多个进程,多线程是指在一个进程中可以同时执行多个线程。进程是程序的单位,线程是实际工作的功能。在编写程序的时候我们可以用到电脑的每一个内核,操作系统可以将线程和多个内核对应起来,我们可以让每一个核心来运行一个线程来做一件事情,就可以达到多任务并行处理。
    2:但是实现多进程和多线程后,又出现了一个问题,计算机的瓶颈不再计算速度(CPU)上,而在硬盘等外部设备上面,会导致我们正在工作的线程挂起,比如,成都要读取1GB的内容,读取要2分钟,读完之后才可以进行后续操作,线程就会挂起,他必须等待IO操作完成时候才能进行。Windows就使用了一套IO完成端口的机制来解决线程被挂起,从而提高程序的性能。
    3:IO完成端口的机制:每当有一个IO请求的时候,他就会发送这个IO请求,这时不会等待这个IO操作处理完成,他会直接返回,这边线程要做什么还是做什么,他会处理后面其他的事,这种操作称为IO完成端口,他不会让程序卡死,一直等待IO操作完成。

文件内核对象理解:

    1:Windows的IO操作都是基于一些设备而言的,这些设备都是很简单的,可以认为除了内存之外的所有东西都可以是系统的设备,包括硬盘,USB,串口,显卡,网卡等,内存是运行所有程序的载体,不算是设备。
    2:与显卡交互也是IO操作,但是不是标准IO操作,标准操作分为几大类:文件,目录,逻辑磁盘,物理磁盘,串口,并口,邮件槽,命名管道,匿名管道,套接字,控制台(控制台基本不用了)
    3:Windows中对文件的定义:二进制数据集合,与我们理解的文件有所不同。目录下就是文件。
        目录设备,C盘,里面每个文件夹等,也是属于一个设备,是对逻辑磁盘的细分。
        逻辑磁盘驱动器,磁盘分区(CDEF盘),就是从操作系统的层面的,硬盘的分区是从逻辑层面的分区,Windows可以将一个物理磁盘模拟成几个逻辑磁盘。
        当然也会有物理上的划分,一般一个电脑只有一个硬盘,如果装多个就是有多个磁盘驱动器。
    4:逻辑磁盘,目录,文件等都是虚拟的,Windows会自己维护一个文件(一个文件就是磁盘上一段连续的控件存的东西),通过文件系统的内核对象来进行维护的。一个文件内核对象就代表从文件开始到文件结束的内存区域。一个文件对象就是一个结构体,可以理解问C++中的类的对象,所拥有的文件对象都是为了来指代出一些单位。文件有文件对象,目录有目录对象,逻辑磁盘有逻辑磁盘的对象,物理磁盘有物理磁盘的对象。我们可以通过Win32的API来获取对应的文件内核对象。

所有的设备类型讲解:

    1:串口对象:是一个外接设备,也会有其内核对象的存在,串口和并口是计算机和外部设备的数据交换的设备,USB还是不属于标准IO操作的设备。单通道。
    2:并口对象:8通道。并不一定比串口快,只是两种不同的通讯方式
    3:邮件槽:比较老的一种一对多的局域网,通过网络传输的,是一对多,一台主机。
    4:命名管道:管道分两种。管道的通讯,常用于数据传输,一对一的。
    5:匿名管道:主要用于本机之间的通讯,进程之间是隔离的,进程时间要通讯的话就可以使用匿名管道,也可以使用socket通讯,可以一对一也可以一对多。是基于数据流的。

R0和R3文件对象交互:

    1:之前Windows的NT结构中提到:ring3层既是用户态,ring0层即使核心态。我们写的软件都是作用于ring3层提供的一些API,我们调用ring3层的API,最终想要做的事是来操作文件,R0和R3是断开的,从R3层到R0层是通过一种机制进入,R0层会在相关的硬盘上找到相关的数据,
    2:每个文件都在硬盘有一块空间。打开成功后,就会返回一个文件对象,R3和R0层是不可以直接通讯的,R0只会返回一个句柄给R3层,R0和R3有一块公用的控件,R3层就通过这个句柄里面的信息就去这块数据共享区里面去取。这个句柄就是文件内核对象。句柄是一类事物的抽象。
    3:R3层会对使用的API进行检测(是读取的那个一文件内核对象),他必须确保到R0层的是正确的。R0层就会打开文件对应的空间,最终会产生一个内核对象(就代表刚刚打开的这块区域的信息表),之后的操作都是根据这块信息表来操作,R3层并不会直接操作信息表,必须有些检测。

设备的打开方式:

打开文件:CreateFile:不仅可以新建文件,还可以打开文件,需要传递多个参数,例如需要指定文件路径或者UNC路径。
打开目录:CreateFile:也需要传递路径和UNC路径,还需要FILE_BACKUP_SEMANTICS标志
逻辑磁盘:CreateFile:参数特别,为(\\.\?:)两个斜线加个点代表本机,斜线加问号就是盘符(?代表盘符)。
物理磁盘:CreateFile:参数(\\.\PHYSICALDRIVE?)。
串口:CreateFile:参数:(COM??),问号代表串口号。
并口:CreateFile:参数:(LPT??),问号代表编号。
邮件槽服务器:CreateMailslot:参数:(\\.\mailslot\邮件槽名)。
邮件槽客服端:CreateFile:参数:(\\servemame\mailslot\邮件槽名)。
命名管道服务器:CreateNamedPipe:参数:(\\.\pipe\管道名)。
命名管道客户端:CreateFile:参数:(\\servermame\pipe\管道名)。
匿名管道:CreatePipe。本身就在在本机,上面两个牵涉到网络,所以要指定。
套接字:Socket.accept。

文件操作:

CreateFile:

    1:CreateFile函数是用来闯将一个对象,可以为控制台,通讯资源,目录(只读),磁盘驱动器,文件等,打开后返回可访问句柄。
    2:例子:
	HANDLE hFile;
	DWORD dwWritenSize = 0;
	hFile = CreateFile(L"Data.txt", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);

    3:函数原型:
HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);

    4:参数:
注意:参数前面的_In_,_In_opt_,是用来表示参数的形式,_In_表示参数为输入参数,_In_opt_代表输入指针型参数,还有_Out_为输出参数。这种参数一定是分配好空间的。
        1:返回值:HANDLE(就是void*)。
        2:lpFileName:文件路径及文件名。如果使用的ANSI版本,会有长度限制(MAXPATH:260)。在UNICODE中的限制就非常大了。
        3:dwDesiredAccess:访问模式,GENERIC_READ GENERIC_WRITE GENERIC_EXECUTE GENERIC_ALL,指以什么权限打开文件,可多个并用。如果设置为0,就不具备文件对象读写权限,有时候我们只是想访问其创建时间等信息,这样打开就会更加安全。
        4:dwShareMode:共享模式,FILE_SHARE_READ FILE_SHARE_WRITE FILE_SHARE_DELETE,指共享给别人的属性操作,共享给另一个软件一起使用就会使用到。就是文件打开后,其他软件是否拥有权限也打开,更改等。如果参数为0,代表不允许其他进程共享。
        5:lpSecurityAttributes:指向安全属性的指针,一般可为NULL(代表子进程无法继承这个句柄),可在MSDN查询。
        6:DWORD dwCreationDisposition, //如何创建,CREATE_NEW CREATE_ALWAYS OPEN_EXISTING OPEN_ALWAYS TRUNCATE_EXISTING。
        7:DWORD dwFlagsAndAttributes, //文件属性,很多种,一般用FILE_ATTRIBUTE_NORMAL,设置文件的属性。
        8:HANDLE hTemplateFile //用于复制文件句柄,一般为NULL即可。
    5:打开串口:
		hComm_ = CreateFile((TCHAR*)(LPCTSTR)strComm, GENERIC_READ | GENERIC_WRITE,
			0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 0);
		if (INVALID_HANDLE_VALUE == hComm_)
		{
			int nError = GetLastError();
			hComm_ = NULL;
			return FALSE;
		}

    6:CreateFile本身是一个宏,实际会调用CreateFileW或CreateFileA。区别在于传递路径的编码不同,就调用不同的函数。Windows本身用的宽字节,但也必须兼容窄字节版本软件,否则无法使用。就用宏的方式来调用W版本和A版本,方便使用。CreateFile在以前就是指的窄字节。但编程最好是自己指定宽窄字节,不要依靠微软写好的自动转换的哪些宏(可以方便转换),可能最后自己都不知道是宽字节还是窄字节。

CreateFile参数详解:

    2:MSDN是一个强大的利器。
    3:事务性操作最开始是基于数据库架构提出的,是指支持回滚的操作。比如:
        一个文件,读,写,改变,完成,这四步称之为一个事物,这四个过程每个都可能出现错误,如果出现错误,就说明这个事物执行失败,就会回滚回来,和原来的一样,不会发生改变。比如安装软件,就应该是事务性操作,安装出错就会回滚。事务性只支持同步性操作。
    4:

WriteFile:

    1:对文件写数据:写入成功返回TRUE,失败返回FALSE。
    2:例子:
	HANDLE hFile;
	DWORD dwWritenSize = 0;
	hFile = CreateFile(L"Data.txt", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
	BOOL bRet = WriteFile(hFile, &good1, sizeof(goodsMsg), &dwWritenSize, NULL);

    3:参数:
        1:hFile:文件的句柄
        2:lpBuffer:写入的数据
        3:nNumberOfBytesToWrite:写入的大小
        4:lpNumberOfBytesWritten:用于保存实际写入字节数的存储区域的指针,DWORD类型,传递地址。
        5:lpOverlapped:OVERLAPPED结构体指针,可用NULL。

ReadFile:

    1:读取数据:读取成功返回TRUE,失败返回FALSE。读取的时候,可以通过GetFileSize函数先获取文件大小来判定读取多少。
    2:例子:
	HANDLE hFile;
	DWORD dwWritenSize = 0;
	hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ, NULL,
		OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	/*if (GetLastError() == ERROR_ALREADY_EXISTS)//文件存在就会进入,仅测试用。
	{
		int i = 0;
	}*/
	goodsMsg good;
	size_t i = 0;
	DWORD fileSize = GetFileSize(hFile, NULL);
	for (; i < fileSize / sizeof(goodsMsg); ++i)
	{
		ReadFile(hFile, &good, sizeof(goodsMsg), &dwWritenSize, NULL);
		goods->push_back(good);
	}

    3:
        1:hFile, //将读取文件的句柄
        2:lpBuffer, //用于保存读入数据的一个缓冲区
        3:nNumberOfBytesToRead, //要读入的字节数
        4:lpNumberOfBytesRead, //指向实际读取字节数的指针
        5:lpOverlapped



    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值