32位操作系统存放4G以上大文件需要NTFS分区支持,FAT32分区不支持且没优势。支持文件操作的有dos操作方式的、API操作方式的、编译器封装后的。dos文件操作方式有fopen,fclose,fwrite,fread,ftell,fseek,int型变量大多数编译器默认为32位字长,符号占一位,可寻址31位,寻址范围为 2^31 = 2.147GB。API操作方式说明如下:
--------------------------------------------------------------------------------
创建文件:
HANDLE WINAPI CreateFile(
LPCTSTR lpFileName, // 文件名字符长指针。
DWORD dwDesiredAccess, // 文件的操作访问方式
DWORD dwShareMode, // 共享模式
LPSECURITY_ATTRIBUTES lpSecurityAttributes, // 安全属性
DWORD dwCreationDisposition, // 创建方式
DWORD dwFlagsAndAttributes, // 文件属性
HANDLE hTemplateFile // 模板文件
);
返回:HANDLE,文件句柄,定义如下:
typedef PVOID HANDLE; // 类型定义为空指针。
typedef void* PVOID; // 空指针类型定义。
成功返回正数句柄值,失败返回INVALID_HANDLE_VALUE,定义如下:
#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1) // 为 -1 数值
参数(1) lpFileName:文件名字符长指针。
参数(2) dwDesiredAccess, 文件的访问请求,无符长字变量(DWORD),主要定义如下:
#define GENERIC_READ (0x80000000L) // 读文件请求
#define GENERIC_WRITE (0x40000000L) // 写文件请求
因为是掩码,可以通过 |(或)组合,比如:GENERIC_READ | GENERIC_WRITE 读或写。
参数(3) dwShareMode:共享模式,无符长字变量(DWORD),主要定义如下:
#define FILE_SHARE_READ 0x00000001 // 打开文件,只有在文件的访问请求(2),为读时才能返回成功。
#define FILE_SHARE_WRITE 0x00000002 // 打开文件,只有在文件的访问请求(2),为写时才能返回成功。
如果CreateFile打开成功,则其他程序不能访问,只有在使用CloseHandle关闭句柄后,才可使用。
参数(4) lpSecurityAttributes:安全属性结构指针,引用LPSECURITY_ATTRIBUTES结构,确定句柄是否被子进程继承。如果为NULL,则不能被子进程继承。
参数(5) dwCreationDisposition:创建方式,无符长字变量(DWORD),主要定义如下:
#define CREATE_NEW 1 // 创建新文件,如果文件存在就返回失败。
#define CREATE_ALWAYS 2 // 总是创建,如果文件存在就覆盖它。
#define OPEN_EXISTING 3 // 打开文件,如果文件不存在就返回失败。
#define OPEN_ALWAYS 4 // 打开已存在文件,如果文件不存在,在使用CREATE_NEW(或)组合时,则创建一个新文件。
参数(6) dwFlagsAndAttributes:文件属性,无符长字变量(DWORD),主要定义如下:
#define FILE_ATTRIBUTE_READONLY 0x00000001 // 只读文件属性
#define FILE_ATTRIBUTE_HIDDEN 0x00000002 // 隐藏属性
#define FILE_ATTRIBUTE_NORMAL 0x00000080 // 通常的文件属性,必须单独使用。
参数(7) hTemplateFile:模板文件,文件句柄类型。
可能存在的应用如下:
1. HANDLE hFile = CreateFile(sFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
(1) sFileName:文件路径及文件名。
(2) GENERIC_WRITE:写文件请求。
(3) FILE_SHARE_WRITE:独立写。
(4) NULL:不被子进程继承。
(5) CREATE_ALWAYS:总是创建,如果文件存在就覆盖它。
(6) FILE_ATTRIBUTE_NORMAL:通常的文件属性
(7) NULL:不使用文件模板。
说明:打开文件准备写,如果文件存在,正常打开,并清空数据,如果文件不存在,则创建。
//测试
void __fastcall TForm1::SpeedButton1Click(TObject *Sender)
{
HANDLE hFile; String sFileName;
sFileName = "D:\\1.txt";
hFile = CreateFile(sFileName.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(HWND_DESKTOP, "打开写或创建文件失败,系统发生错误。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
}
2. HANDLE hFile = CreateFile(sFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
(1) sFileName:文件路径及文件名。
(2) GENERIC_READ:读文件请求。
(3) FILE_SHARE_READ:独立读。
(4) NULL:不被子进程继承。
(5) OPEN_EXISTING:打开文件,如果文件不存在就返回失败。
(6) FILE_ATTRIBUTE_NORMAL:通常的文件属性
(7) NULL:不使用文件模板。
说明:打开文件准备读,如果文件存在,则正常打开,如果文件不存在,则返回失败。
//测试
void __fastcall TForm1::SpeedButton2Click(TObject *Sender)
{
HANDLE hFile; String sFileName;
sFileName = "D:\\18.txt";
hFile = CreateFile(sFileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(HWND_DESKTOP, "打开读文件失败,因为文件不存在。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
}
--------------------------------------------------------------------------------
设置文件指针:
BOOL WINAPI SetFilePointerEx(
HANDLE hFile, // 已打开的文件句柄
LARGE_INTEGER liDistanceToMove, // 移动位置
PLARGE_INTEGER lpNewFilePointer,// 返回新移动到的位置
DWORD dwMoveMethod // 移动方法
);
返回:BOOL,如果失败,返回False,如果成功返回True。
参数(1) hFile:由CreateFile打开的文件句柄。
参数(2) liDistanceToMove:移动位置,引用LARGE_INTEGER结构,传递64位文件位置变量。通过LARGE_INTEGER结构64位变量接口输入。
__int64 iFilePointerPos; //64位文件指针位置变量
liDistanceToMove.QuadPart = iFilePointerPos; //传递64位变量
(liDistanceToMove.LowPart为DWORD类型,liDistanceToMove.HighPart为LONG类型,合成为有符合64位类型变量)
LARGE_INTEGER结构定义如下:
#if defined(MIDL_PASS)
typedef struct _LARGE_INTEGER {
#else // MIDL_PASS
typedef union _LARGE_INTEGER {
struct {
DWORD LowPart;
LONG HighPart;
};
struct {
DWORD LowPart;
LONG HighPart;
} u;
#endif //MIDL_PASS
LONGLONG QuadPart;
} LARGE_INTEGER;
参数(3) lpNewFilePointer:返回新移动到的位置指针,引用LARGE_INTEGER结构,如果不使用,可以为NULL。
参数(4) dwMoveMethod:移动方法,无符长字变量(DWORD),主要定义如下:
#define FILE_BEGIN 0 //从文件开始处移动
#define FILE_CURRENT 1 //从文件当前处移动
#define FILE_END 2 //从文件尾部处移动
可能存在的应用:通过64位有符号变量范围内的文件位置,实现对大文件的读写。
//测试
void __fastcall TForm1::SpeedButton4Click(TObject *Sender)
{
HANDLE hFile; String sFileName; LARGE_INTEGER liDistanceToMove; __int64 iFilePointerPos;
sFileName = "D:\\1.txt";
hFile = CreateFile(sFileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(HWND_DESKTOP, "打开读文件失败,因为文件不存在。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
iFilePointerPos = 10; //设置文件位置
liDistanceToMove.QuadPart = iFilePointerPos; //传递64位变量
SetFilePointerEx(hFile, liDistanceToMove, NULL, FILE_BEGIN);
}
--------------------------------------------------------------------------------
读文件:
BOOL WINAPI ReadFile(
HANDLE hFile, // 已打开的文件句柄
LPVOID lpBuffer, // 读出的缓冲区
DWORD nNumberOfBytesToRead,// 读出的字节量
LPDWORD lpNumberOfBytesRead, // 反馈实际读出的字节量
LPOVERLAPPED lpOverlapped // 异步读写的结构指针
);
返回:BOOL,如果失败,返回False,如果成功返回True。
参数(1) hFile:由CreateFile打开的文件句柄。
参数(2) lpBuffer:空指针,由LPCVOID类型定义,读出时确定变量类型。
参数(3) nNumberOfBytesToWrite:读出的字节量,无符号长字类型,每次可读出 2^32位 = 4.294GB 字节量。
参数(4) lpNumberOfBytesWritten:反馈实际读出的字节量,无符号长字变量指针。
参数(5) lpOverlapped:异步读写的结构指针,引用LPOVERLAPPED结构,如果不使用,可以为NULL。
//测试
void __fastcall TForm1::SpeedButton6Click(TObject *Sender)
{
HANDLE hFile; String sFileName; bool bRet; BYTE chBuf[4];
DWORD dwReadCount,dwRetReadCount; String sS;
sFileName = "D:\\1.txt";
hFile = CreateFile(sFileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(HWND_DESKTOP, "打开读文件失败,因为文件不存在。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
dwReadCount = 4;
bRet = ReadFile(hFile, chBuf, dwReadCount, &dwRetReadCount, NULL);//读文件
if(!bRet)
{
MessageBox(HWND_DESKTOP, "读文件失败。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
sS.SetLength(4);//设置字符长度
for(int i = 0; i < 4; i++) sS[i+1] = chBuf[i];//拷贝字符
StaticText1->Caption = sS;//显示字符
}
--------------------------------------------------------------------------------
写文件
BOOL WINAPI WriteFile(
HANDLE hFile, // 已打开的文件句柄
LPCVOID lpBuffer, // 写入的缓冲区
DWORD nNumberOfBytesToWrite, // 写入的字节量
LPDWORD lpNumberOfBytesWritten,// 反馈实际写入的字节量
LPOVERLAPPED lpOverlapped // 异步读写的结构指针
);
返回:BOOL,如果失败,返回False,如果成功返回True。
参数(1) hFile:由CreateFile打开的文件句柄。
参数(2) lpBuffer:空指针,由LPCVOID类型定义,写入时确定变量类型。
参数(3) nNumberOfBytesToWrite:写入的字节量,无符号长字类型,每次可写入 2^32位 = 4.294GB 字节量。
参数(4) lpNumberOfBytesWritten:反馈实际写入的字节量,无符号长字变量指针。
参数(5) lpOverlapped:异步读写的结构指针,引用LPOVERLAPPED结构,如果不使用,可以为NULL。
//测试
void __fastcall TForm1::SpeedButton5Click(TObject *Sender)
{
HANDLE hFile; String sFileName; bool bRet; BYTE chBuf[4] = {'T','e','s','t'};
DWORD dwWriteCount,dwRetWriteCount;
sFileName = "D:\\1.txt";
hFile = CreateFile(sFileName.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(HWND_DESKTOP, "打开写或创建文件失败,系统发生错误。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
dwWriteCount = 4;
bRet = WriteFile(hFile, chBuf, dwWriteCount, &dwRetWriteCount, NULL);//写文件
if(!bRet)
{
MessageBox(HWND_DESKTOP, "写文件失败,请检查文件所在磁盘分区容量,或系统发生错误。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
}
--------------------------------------------------------------------------------
关闭句柄
BOOL CloseHandle(
HANDLE hObject // 句柄对象
);
返回:BOOL,如果失败,返回False,如果成功返回True。
参数(1) hObject:已打开的句柄对象,引用HANDLE的句柄对象。
//测试
void __fastcall TForm1::SpeedButton7Click(TObject *Sender)
{
HANDLE hFile; String sFileName; bool bRet;
sFileName = "D:\\1.txt";
hFile = CreateFile(sFileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(HWND_DESKTOP, "打开读文件失败,因为文件不存在。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
bRet = CloseHandle(hFile);//关闭文件
if(!bRet)
{
MessageBox(HWND_DESKTOP, "关闭文件失败。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
}
--------------------------------------------------------------------------------
获取文件长度
BOOL WINAPI GetFileSizeEx(
HANDLE hFile, //文件句柄
PLARGE_INTEGER lpFileSize //返回文件长度
);
返回:BOOL,失败返回False,成功返回True。
参数(1) hFile:由CreateFile打开的文件句柄。
参数(2) lpFileSize:返回文件长度,引用LARGE_INTEGER的结构指针,通过LARGE_INTEGER结构64位变量接口输出,传递64位变量。
typedef LARGE_INTEGER *PLARGE_INTEGER;//PLARGE_INTEGER结构指针类型定义
//测试
void __fastcall TForm1::SpeedButton8Click(TObject *Sender)
{
String sFileName; HANDLE hFile; PLARGE_INTEGER lpFileSize; __int64 iFileSize; bool bRet;
sFileName = "D:\\1.txt";
hFile = CreateFile(sFileName.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile == INVALID_HANDLE_VALUE)
{
MessageBox(HWND_DESKTOP, "打开读文件失败,因为文件不存在。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
bRet = GetFileSizeEx(hFile, lpFileSize);//获取文件长度
if(!bRet)
{
MessageBox(HWND_DESKTOP, "读文件长度失败。", "错误", MB_OK | MB_ICONINFORMATION);
return;//返回不再继续。
}
iFileSize = lpFileSize->QuadPart;//传递变量
StaticText1->Caption = IntToStr(iFileSize);//显示文件长度
}
--------------------------------------------------------------------------------
总结:ReadFile,WriteFile,一次可读写4.294GB内的数据,SetFilePointerEx移动文件读写位置为63位(一个符号位),可实现大于4.294GB的读写,2^63 = 9223372037GB足够大,不爽的是需要通过移动读写位置,间接实现。
--------------------------------------------------------------------------------
注1:以上在32位XP操作系统,C++Builder 6 测试通过。
注2:将API封装为一个文件类,在获取文件长度时出现了两次错误,内容如下:
错误1:
__int64 __fastcall TApiFile::GetFileSize(void)//获取文件长度
{
PLARGE_INTEGER lpFileSize; bool bRet;
bRet = GetFileSizeEx(hFile, lpFileSize);//获取文件长度
if(!bRet) return false;//失败返回
return lpFileSize->QuadPart;
}
因使用GetFileSizeEx,忽略了API还有个GetFileSize,重名错误,将其更名。
错误2:
__int64 __fastcall TApiFile::GetFileLength(void)//获取文件长度
{
PLARGE_INTEGER lpFileSize; bool bRet;
bRet = GetFileSizeEx(hFile, lpFileSize);//获取文件长度
if(!bRet) return false;//失败返回
return lpFileSize->QuadPart;
}
一调用就崩溃,问题出在PLARGE_INTEGER lpFileSize结构指针引用问题,指针不是变量,造成崩溃,用LARGE_INTEGER FileSize结构引用,因存在具体变量,在输入结构参数时取地址,问题得以解决。
正确程序:
__int64 __fastcall TApiFile::GetFileLength(void)//获取文件长度
{
LARGE_INTEGER FileSize; bool bRet;
bRet = GetFileSizeEx(hFile, &FileSize);//获取文件长度
if(!bRet) return false;//失败返回
return FileSize.QuadPart;
}
经测试没问题。为什么在TForm主程序不崩溃可以正常,一时难以说清楚。遇到函数参数为指针的,一定弄清楚是输入还是输出,再看一下获取文件长度原型:
BOOL WINAPI GetFileSizeEx(
_In_ HANDLE hFile, // 输入,文件句柄
_Out_ PLARGE_INTEGER lpFileSize // 输出,文件长度
);
PLARGE_INTEGER lpFileSize是输出的,指向LARGE_INTEGER结构的指针,是函数向外输出的,必须有具体结构变量地址,才能接收数据。如果是输入的指针,必须先指向具体的变量、结构等,才能传入数据。还有一类是_In_opt_的,要弄清楚输入输出关系。