0%

File operate

文件操作

上篇博客说道了强大的CreateFile函数,现在就介绍如何进行文件的具体操作。

SetFilePointer移动文件指针

读文件的时候我们要标志我们具体读到了哪个地方,那么我们就需要一个指针,这个指针代表我们具体读到了什么地方。
SetFilePointer这个函数就是设置这个指针的位置,方便我们可以随机读取文件。
看下MSDN的一个介绍:

1
2
3
4
5
6
7
8
DWORD SetFilePointer(
HANDLE hFile, // handle of file
LONG lDistanceToMove, // number of bytes to move file pointer
PLONG lpDistanceToMoveHigh,
// pointer to high-order DWORD of
// distance to move
DWORD dwMoveMethod // how to move
);
  1. hFile这个就是我们打开文件的一个文件句柄,通过CreateFile就可获得。
  2. lDistanceToMove移动的一个距离
  3. lpDistanceToMoveHigh看名字就知道了这个是移动距离的高32位,一般至于超大文件才会用的到。
  4. dwMoveMethod指针的一个移动方式,主要是下面这三个值:
    • FILE_BEGIN:从文件的开头进行移动
    • FILE_CURRENT:从当前的一个位置进行移动
    • FILE_END:从文件的结尾进行移动
      简单易懂一下就看明白了。

返回值就是当前文件指针的位置,如果失败就是-1。
这个函数有个强大的功能,就是说比如你当前的这个文件有100KB,但是我却移动到了1000KB,那么再写入的时候我的文件就会增大。

SetEndOfFile截断文件

SetEndOfFile这个函数MSDN的一个定义:*The SetEndOfFile function moves the end-of-file (EOF) position for the specified file to the current position of the file pointer. *
简单的翻译一下:SetEndOfFile函数将指定文件的end-of (EOF)位置移动到文件指针的当前位置。
其实简单的说作用就是用来截断文件的。可以用来扩展,也可以用来截断一部分。

ReadFileWriteFile

看名字就知道这是读写文件的操作
首先我们看一下ReadFile的一个文件定义:

1
2
3
4
5
6
7
BOOL WriteFile(
HANDLE hFile, // handle to file to write to
LPCVOID lpBuffer, // pointer to data to write to file
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
LPOVERLAPPED lpOverlapped // pointer to structure for overlapped I/O
);

下面说几个重点的参数就好了

  • lpBuffer这个参数就是接受的一个缓冲区
  • nNumberOfBytesToWrite这个是用来读取的一个长度
  • lpNumberOfBytesWritten实际读取的一个大小,用来判断是否结束了一般
  • lpOverlapped重叠I/O的,NULL就好了,基本用不大到
    说了这么多我们操作一下试试,首先还是要用到我们之前的CreateFile来打开我们的文件,获得文件的一个指针:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
HANDLE hFile;
hFile = CreateFile("Wker.txt",
FILE_SHARE_READ,//要读这个文件
0,//不共享
NULL,//默认的安全属性
OPEN_EXISTING,//打开文件
FILE_ATTRIBUTE_NORMAL,//普通文件
NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
cout<<"打开失败,看看是不是有杀毒软件哦!"<<endl;
return -1;
}
DWORD realRead;
SetFilePointer(hFile,0, NULL, FILE_BEGIN);
do
{
char* t = new char[20];
if( !ReadFile(hFile,t,20,&realRead,NULL))
{
cout<<"fail";
break;
}
t[realRead] = 0;
cout<<t;
}while(realRead == 20);


return 0;
}

这个地方我们要注意我们的文件属性,要与你的文本属性相同!
写文件的话呢其实也很简单:

1
2
3
4
5
6
7
BOOL WriteFile(
HANDLE hFile, // handle to file to write to
LPCVOID lpBuffer, // pointer to data to write to file
DWORD nNumberOfBytesToWrite, // number of bytes to write
LPDWORD lpNumberOfBytesWritten, // pointer to number of bytes written
LPOVERLAPPED lpOverlapped // pointer to structure for overlapped I/O
);

参数可以看出基本上是一模一样的,那我们还是看个小例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
HANDLE hFile;
hFile = CreateFile("Wker.txt",
GENERIC_WRITE,//要写这个文件
0,//不共享
NULL,//默认的安全属性
OPEN_EXISTING,//打开文件
FILE_ATTRIBUTE_NORMAL,//普通文件
NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
cout<<"打开失败,看看是不是有杀毒软件哦!"<<endl;
return -1;
}
DWORD RealWrite;
char t[4] = "aaa";
WriteFile(hFile,t,3,&RealWrite,NULL);
if(RealWrite != 3)
{
cout<<"fail:"<<RealWrite;
}else
{
cout<<"Write Success";
}
return 0;
}

但在这个地方我们要注意,我们要写入的自己不需要带最后的00,他好像可以自己加上去。
PS:注意了!!!在用这个函数的时候,我们写完的时候,其实内容没有立马改变,而是写在了缓冲区中,Windows会找到合适的时机再写入磁盘的。
立即刷新的话呢,我们可以用CloseHandle或者使用比较有针对性的函数:FlushFileBuffers,参数都是一样的,最后一个是专门用来刷新缓冲区数据的。

LockFileUnlockFile

对于文件的安全性,防止文件在写入的过程中内容又被读取我们可以使用这两个函数,主要是对文件的缓冲区进行一定的保护作用,看一下这两个函数的一个定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//加锁
BOOL LockFile(
HANDLE hFile, // handle of file to lock
DWORD dwFileOffsetLow, // low-order word of lock region offset
DWORD dwFileOffsetHigh, // high-order word of lock region offset
DWORD nNumberOfBytesToLockLow,
// low-order word of length to lock
DWORD nNumberOfBytesToLockHigh
// high-order word of length to lock
);


//解锁
BOOL UnlockFile(
HANDLE hFile, // handle of file to unlock
DWORD dwFileOffsetLow, // low-order word of lock region offset
DWORD dwFileOffsetHigh, // high-order word of lock region offset
DWORD nNumberOfBytesToUnlockLow,
// low-order word of length to unlock
DWORD nNumberOfBytesToUnlockHigh
// high-order word of length to unlock
);

参数基本一致那几个High的值很明显就是针对于特大文件的高32位的值,我们用NULL就可以了的,其他参数就是一个文件的加锁开始位置和加锁区域。
在这里需要注意的是,虽然我们的加锁文件结束进程的时候会自动解锁,但是这个还是最好显示的调用解锁函数避免我们有的时候文件无法正常的打开,而且Windows解锁文件的时间取决于当前可用的系统内存。