16.2使用文 件设备
16.2.1定位文件指针:
当CreateFile返回一个文件句柄时,系统给句柄关联了一个文件指针,这个文件指针给出了文件内部一个64位偏移量, 下次的同步读写将在此处进行。开始时这个指针被设置成0,所以在你调用CreateFile返回一个文件句柄后,立即调用ReadFile,你将从文件的 偏移0处开始读。如果你读取100字节的数据到内存中,系统将会更新与文件句柄关联的指针位置,使得在下一次调用ReadFile时,从文件的第101字 节开始读取文件的数据。
举例说明:
HANDLE hFile = CreateFile(……);
ReadFile(hFile,lpBuffer,100,&dwBytesRead,NULL); 是从指针为0处开始读
WriteFile(hFile,lpBuffer,100,&dwBytesWrite,NULL); 是从指针为100处开始写
在这 段代码中,文件的前100个字节用于执行ReadFile函数,而WriteFile是从文件的第101个字节开始的,这是因为在执行完ReadFile 后,与文件关联的指针已经被更新为100了,所以在调用函数WriteFile时,是从文件的第100字节开始写的。
如 果是打开同一文件多次的话,就与上面的情况不一样了,每打开一次文件,与文件句柄关联的指针都会被设置成0,所以如果这样写这段代码,
HANDLE hFileA = CreateFile(“MyFile”,…);
HANDLE hFileB = CreateFile(“MyFile”,…);
ReadFile(hFileA,lpBuffer,100,&dwBytesRead,NULL);是从指针为0处开始读
WriteFile(hFileB,lpBuffer,100,&dwBytesWrite,NULL);是从指针为0处开始写
另外介绍一个函数SetFilePointer,
DWORD SetFilePointer(HANDLE hFile,LONG lDistanceToMove,
PLONG lpDistanceToMoveHigh,DWORD dwMoveMethod);
参数说明:
lDistanceToMove告诉系统你想要移动指针多少个字节。注意,你指定的值是增加到指针的当前值,也就是说,你传递给该参 数负值的话,等同于将指针向后移。
LpDistanceToMoveHigh: 当你移动指针的范围是正负2GB以内,那么参数lpDistanceToMoveHigh设置为NULL。如果你移动指针的范围是正负180GB,那么你 需要在这个值的高32位传递给该参数。实际上,不能直接将这个值的高32位传递给该参数,而是将这个值的高32的地址传递给参数 lpDistanceToMoveHigh。这样传递的原因是,SetFilePointer函数返回文件指针以前的位置。如果你感兴趣的是这个指针的低 32位,那么SetFilePointer直接返回这个值。如果你对指针的高32位也感兴趣,那么SetFilePointer在返回前填充参数 lpDistanceToMoveHigh的值。
DwMoveMethod: 它告诉SetFilePointer如何解释参数lDistanceToMove 和lpDistanceToMoveHigh,可以传递给该参数三个值,它们是:
值 | 说明 |
FILE_BEGIN | 文件指针变成由两 个DistanceToMove参数指定的无符号值 |
FILE_CURRENT | 文件指针被加上由 两个参数DistanceToMove指定的有符号值 |
FILE_END | 文件指针变成由文 件的字节数加上由两个参数DistanceToMove指定的有符号值 |
如果函数SetFilePointer没有改变文件的指针,它将返回 0xFFFFFFFF,lpDistanceToMoveHigh的缓冲区将包含NULL。最好调用GetError,看GetError是否返回 NO_ERROR,来验证SetFilePointer是否成功。
16.2.2设置文件尾:
BOOL SetEndOfFile(HANDLE hFile);该函数改变文件长度,例如,你想强制一个文件的长度为1024字节,你可以这样做,
HANDLE hFile = CreateFile(…);
SetFilePointer(hFile,1024,NULL,FILE_BEGIN);
SetEndOfFile(hFile);
16.2.3加锁和解锁文件的区域:
1. 文件的加锁和解锁只影响文件的部分区域,使用函数LockFile来锁定一个文件的某一块区域,
BOOL LockFile(HANDlE hFile,DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh,DWORD cbLockLow,DWORD cbLockHigh);
参 数说明:
hFile是要锁定的文件句柄。
DwFileOffsetLow和 dwFileOffsetHigh指定你想开始锁定的文件的64位偏移量。
DwLockLow和 dwLockHigh指定你想锁定的字节数。
举例 说明:假如你想锁定数据库中的第一百条记录,
LockFile(hFile,sizeof(CUSTOMER_RECORD)*(100 - 1),0,
sizeof(CUSTOMER_RECORD),0);
如 果锁定成功LockFile将返回TRUE。当文件的一个区域被锁时,所有其它想读写该区域的进程都将会失败。
注意:锁定的区域超过当前的文件尾也是合法的,例如:在你在数据库中增加新记录时。可以锁定超过文件尾的一块区域,之后把新客户数据 写到这个区域里。
还有一点需要注意,你锁定的区域不能包括已经锁定的区域。举例说明:看如下这两个对LockFile函数的调用,第一个会成功调用,第二个会失败,原因是第二LockFile锁定的区域已经包括在第一个 LockFile锁定的区域内了,
LockFile(hFile,sizeof(CUSTOMER_RECORD)*(100 - 1),0,
sizeof(CUSTOMER_RECORD),0);// 锁定第100条记录
LockFile(hFile,sizeof(CUSTOMER_RECORD)*(100 - 2),0,
2 * sizeof(CUSTOMER_RECORD),0);//锁定第99条合第100条记录
很明显,在第二次对LockFile的调用时,也锁定了第100条记录,而在第一调用 时,LockFile已经锁定了这条记录,所以第二次对LockFile的调用将失败。
2.在对锁定的区域操作结束后,需要使用UnLockFile来释放这块锁定的区域,
BOOL UnLockFile(HANDLE hFile,DWORD dwFileOffsetLow,
DWORD dwFileOffsetHigh,DWORD dwUnLockLow,DWORD dwUnLockHigh);
UnLockFile与函数LockFile的参数相同,返回值也一样。当你解锁一个区域时, 必须与加锁一个区域时相同。举例说明:
LockFile(hFile,sizeof(CUSTOMER_RECORD)*(100 - 1),0,
sizeof(CUSTOMER_RECORD),0); 锁定第100条记录
LockFile(hFile,sizeof(CUSTOMER_RECORD)*(100 - 2),0,
sizeof(CUSTOMER_RECORD),0);// 锁定批99条记录
下面解锁这两个锁定区域,
UnLockFile(hFile,sizeof(CUSTOMER_RECORD)*(100 - 1),0,
sizeof(CUSTOMER_RECORD),0);
UnLockFile(hFile,sizeof(CUSTOMER_RECORD)*(100 - 1),0,
sizeof(CUSTOMER_RECORD),0);
注意:解锁时,必须与加锁时相同,不能用一个UnLockFile把前面两个LockFile 加锁的区域一次解锁,加锁与解锁要一 一对应。
还有一点需要注意:在关闭一个文件或终结进程前一定要解锁全部加锁区域。
3.函数LockFileEx:
LockFileEx 比函数LockFile多了两个功能,一、它在锁定文件的某个区域时,可以设定属性以使其它进程可以读该锁定区域,二、可以告诉LockFileEx直接 锁定文件成功后返回。第二个功能比起LockFile要好多了,因为当调用LockFile时,如果想锁定的文件区域已经被另一个线程锁定了,那么 LockFile会立即返回,但是你可以告诉LockFileEx一直等到获得文件为止才返回。下面列出函数LockFileEx的定义,
BOOL LockFileEx(HANDLE hFile,DWORD dwFlags,
DWORD dwReserved,DWORD nNumberOfBytesToLockLow,
DWORD nNumberOfBytesToLockHigh,
LPOVERLAPPED lpOverLapped);
LockFileEx使用 OVERLAPPED结构中的成员Offset和OffsetHigh。
下面列出结构 OVERLAPPED的定义:
typedef struct _OVERLAPPED{
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent; //事件内核对象
}OVERLAPPED,*LPOVERLAPPED;