API读写32位系统4G以上大文件

     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_的,要弄清楚输入输出关系。

转载于:https://www.cnblogs.com/hbg200/p/6371684.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值