CSDN-CSDN社区-VB-API

收藏 关于SetFilePointer在大于2g的文件中的定位[问题点数:20,结帖人:MOODSKY2002]

楼主发表于:2008-05-21 15:47:40
当文件的定位区域小于2g时用下面的方式就可以正确定位
SetFilePointer hdlSRCFile, NowsSart, ByVal 0&, FILE_BEGIN
当定位区域超过2g时也就是nowstart的数值大于2g时,就会溢出,看了一下网上的说明,SetFilePointer可以用高低位的方式为定位超2g的文件支持64bit
但小弟不知这个高低位应该是怎么算出来呢?
在SetFilePointer hdlSRCFile, NowsSart, ByVal 0&, FILE_BEGIN
中应该怎么写呢?例如nowstart现在的值需要为2146959360也就是说超过2g时,直接将nowstart设为该值,肯定要益出,那么设成高低位该怎么写呢。。。
还望高人们写个简单的例子就成了。。。。。小弟感激不尽啊。
回复次数:18
#1楼 得分:0回复于:2008-05-21 16:10:55
阿门,谁说超过2G会溢出

Long型的正数最大可以表示到 2147483647

超过这个的部分放到后面的那个高位参数去

#2楼 得分:0回复于:2008-05-21 16:15:20
嗯???该怎么用呢??
SetFilePointer hdlSRCFile, NowsSart,2146959360, FILE_BEGIN
这样???那前面该填什么呢?
小弟对于变量之类的东东还有数学基础很差,还望高人指点。
#3楼 得分:0回复于:2008-05-21 16:19:19
比如开始位应该是2146959360
是否应该这样呢?
SetFilePointer hdlSRCFile, 2147483647,2146959360-2147483647, FILE_BEGIN
我这样写好向没有益出,但结果好向不对。。。。。
#4楼 得分:0回复于:2008-05-21 16:21:05
起始参数打错了,起始参数应该是大于2147483647的,
刚才粘贴复制过来此参数没看。。。。
#5楼 得分:20回复于:2008-05-21 19:46:56
  • myjian用户头像
  • myjian
  • (嗷嗷叫的老马---我郁闷.)
  • 等 级:
  • 2

#6楼 得分:0回复于:2008-05-21 20:11:58
lDistanceToMove和lpDistanceToMoveHigh组合起来就是一个64位的值,是不是就是所谓的INT_64?
#7楼 得分:0回复于:2008-05-21 20:15:59
55~~~~我开始在baidu上也搜索到了这个贴子并且还下载了例子代码,

其中有几段
看起来就是Size2Long Position, PosL, PosH这里是关键,可我怎么看它们之间也没办法联系起来呀,都是sub没有返回参数。posl,posh是从哪里来的呢????55~~~~~~高人要是能提醒一下就好了。Size2Long关键应该就是在这里,可我看里面的ByRef LongLow As Long, ByRef LongHigh As Long并没有输出啊。。。。真的是搞不明白了,,,,

Public Sub API_ReadFile(ByVal FileNumber As Long, ByVal Position As Currency, ByRef BlockSize As Long, ByRef Data() As Byte)
Dim PosL As Long
Dim PosH As Long
Dim SizeRead As Long
Dim Ret As Long
Size2Long Position, PosL, PosH
Ret = SetFilePointer(FileNumber, PosL, PosH, FILE_BEGIN)
Ret = ReadFile(FileNumber, Data(0), BlockSize, SizeRead, 0&)
BlockSize = SizeRead
End Sub

Private Sub Size2Long(ByVal FileSize As Currency, ByRef LongLow As Long, ByRef LongHigh As Long)
'&HFFFFFFFF unsigned = 4294967295
Dim Cutoff As Currency
Cutoff = 2147483647
Cutoff = Cutoff + 2147483647
Cutoff = Cutoff + 1 ' now we hold the value of 4294967295 and not -1
LongHigh = 0
Do Until FileSize < Cutoff
    LongHigh = LongHigh + 1
    FileSize = FileSize - Cutoff
Loop
If FileSize > 2147483647 Then
    LongLow = -CLng(Cutoff - (FileSize - 1))
Else
    LongLow = CLng(FileSize)
End If
End Sub

Private Sub Long2Size(ByVal LongLow As Long, ByVal LongHigh As Long, ByRef FileSize As Currency)
Dim Cutoff As Currency
Cutoff = 2147483647
Cutoff = Cutoff + 2147483647
Cutoff = Cutoff + 1
FileSize = Cutoff * LongHigh
If LongLow < 0 Then
    FileSize = FileSize + (Cutoff + (LongLow + 1))
Else
    FileSize = FileSize + LongLow
End If
End Sub
#8楼 得分:0回复于:2008-05-21 20:22:02
这几天为2g以上文件的,下载,获取进度,获取总大小,本地总大小,等等问题是调了又调试了又试,现在暂时就只差这一个问题了。。。。SetFilePointer定位超过2g以后的内容到底是该如何操作呢。。。。。唉,人感觉很疲惫,脑袋都不好使了。。。。还望高人,有个简单的程序写法方面的提示,真心的说声谢谢。
#9楼 得分:0回复于:2008-05-21 20:33:40
我试了一下这样。
FileKB是Currency变量
并且filekb=大于2g的数
用此种方法

Size2Long filekb, LongLow, LongHigh
SetFilePointer hdlSRCFile, LongLow, LongHigh, FILE_BEGIN


Private Sub Size2Long(ByVal FileSize As Currency, ByRef LongLow As Long, ByRef LongHigh As Long)
'&HFFFFFFFF unsigned = 4294967295
Dim Cutoff As Currency
Cutoff = 2147483647
Cutoff = Cutoff + 2147483647
Cutoff = Cutoff + 1 ' now we hold the value of 4294967295 and not -1
LongHigh = 0
Do Until FileSize < Cutoff
    LongHigh = LongHigh + 1
    FileSize = FileSize - Cutoff
Loop
If FileSize > 2147483647 Then
    LongLow = -CLng(Cutoff - (FileSize - 1))
Else
    LongLow = CLng(FileSize)
End If
End Sub


结果是 LongLow = -CLng(Cutoff - (FileSize - 1))益出。。。。。
唉。。。。上帝。。。。
#10楼 得分:0回复于:2008-05-22 11:32:06
VBScript code
Sub Main() Dim hdlSRCFile As Long Dim NowsStart As Currency Dim lMoveLo As Long, lMoveHi As Long ... NowsStart = 3146959360@ '假定这是你要定位的位置 Size2Long NowsStart, lMoveLo, lMoveHi '用你7楼的函数转换 SetFilePointer hdlSRCFile, lMoveLo, lMoveHi, FILE_BEGIN End Sub
#11楼 得分:0回复于:2008-05-22 12:06:31
1. 64位大整数
顾名思义,就是64位、8字节长的数据类型
在某些高级语言中有专门相对应的类型
在系统API中,有专门的LARGEINTEGER等结构来存放这种数
但不幸的是,VB中没有所谓的int64类型

2. Currency类型
在VB中,与64位大整数的性质最相似的数据类型就是Currency了
Currency是一个可以用来存储64位大整数的,比较理想的基本数据类型。
Currency的取值范围是-922,337,203,685,477.5808 到 922,337,203,685,477.5807,
在内存中的表示形式为从 &H8000000000000000 到 &H7FFFFFFFFFFFFFFF
但是要注意的是,该类型数值的最后四位在VB中表现为小数部分,因此,你虽然在使用该类型进行计算时可以不去理会小数点,但在表现时却要将其乘上10000,变为整数

3. 大文件处理
首先,文件大小、指针位置等需要用到64位大整数的地方都改用 Currency。其次,在实际使用时,或采取公式
函数中的移动距离 = 移动距离/10000,以配合Currency类型的特质

以下为代码:

首先是Currency类型和LARGEINTEGER结构之间的转换。这个东西比较简单,因为两个东西的内存布局是完全一样的,所以拿出CopyMemory即可。
VB.NET code
'货币类型转换为大整数结构 Public Function Currency2LargeInteger(ByVal curDistance As Currency) As LARGE_INTEGER CopyMemory Currency2LargeInteger, curDistance, 8 End Function '大整数结构转换为货币类型 Public Function LargeInteger2Currency(li As LARGE_INTEGER) As Currency CopyMemory LargeInteger2Currency, li, 8 End Function


接下去是对SetFilePointer的小小封装,参照了MSDN中的建议:
VB.NET code
Public Function MySeek(ByVal hFile As Long, ByVal curDistance As Currency, ByVal lMoveMethod As Long) As Currency Dim li As LARGE_INTEGER li = Currency2LargeInteger(curDistance) li.lowpart = SetFilePointer(hFile, li.lowpart, li.highpart, lMoveMethod) If li.lowpart = -1 Or Err.LastDllError <> 0 Then li = Currency2LargeInteger(-1@) End If MySeek = LargeInteger2Currency(li) Debug.Print "Seek to "; Hex(li.highpart); Hex(li.lowpart) End Function
#12楼 得分:0回复于:2008-05-22 12:10:15
这里是完整实现代码及测试代码

模块中的代码
VB.NET code
Option Explicit Public Const MOVEFILE_REPLACE_EXISTING = &H1 Public Const FILE_ATTRIBUTE_TEMPORARY = &H100 Public Const FILE_BEGIN = 0 Public Const FILE_SHARE_READ = &H1 Public Const FILE_SHARE_WRITE = &H2 Public Const CREATE_NEW = 1 Public Const OPEN_EXISTING = 3 Public Const GENERIC_READ = &H80000000 Public Const GENERIC_WRITE = &H40000000 Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long) Public Declare Function WriteFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToWrite As Long, lpNumberOfBytesWritten As Long, ByVal lpOverlapped As Any) As Long Public Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long Public Declare Function CreateFile Lib "kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long Public Declare Function SetFilePointer Lib "kernel32" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long Public Declare Function GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long Public Declare Function SetEndOfFile Lib "kernel32" (ByVal hFile As Long) As Long ' 32 bit 'signed int '1000 0000 0000 0000 0000 0000 0000 0000 ' = '8000 0000 -> -2147483648 ' '0111 1111 1111 1111 1111 1111 1111 1111 ' = '7FFF FFFF -> 0 ~ 2^31-1 2147483647 ' 'unsigned int '1111 1111 1111 1111 1111 1111 1111 1111 ' = 'FFFF FFFF -> 0 ~ 2^32-1 4294967295 ' ' 64 bit 'signed int '1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ' = '8000 0000 0000 0000 -> -9223372036854775808 ' '0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 ' = '7FFF FFFF FFFF FFFF -> 0 ~ 2^63-1 9223372036854775807 ' VB Currency 922337203685477.5807 ' 'unsigned int '1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 ' = 'FFFF FFFF FFFF FFFF -> 0 ~ 2^64-1 18446744073709551615 Public Type LARGE_INTEGER lowpart As Long highpart As Long End Type Public Function Currency2LargeInteger(ByVal curDistance As Currency) As LARGE_INTEGER CopyMemory Currency2LargeInteger, curDistance, 8 End Function Public Function LargeInteger2Currency(li As LARGE_INTEGER) As Currency CopyMemory LargeInteger2Currency, li, 8 End Function Public Function MyOpen(ByVal sFileName As String) As Long MyOpen = CreateFile(sFileName, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0&, OPEN_EXISTING, 0, 0) End Function Public Function MySeek(ByVal hFile As Long, ByVal curDistance As Currency, ByVal lMoveMethod As Long) As Currency Dim li As LARGE_INTEGER li = Currency2LargeInteger(curDistance) li.lowpart = SetFilePointer(hFile, li.lowpart, li.highpart, lMoveMethod) If li.lowpart = -1 Or Err.LastDllError <> 0 Then li = Currency2LargeInteger(-1@) End If MySeek = LargeInteger2Currency(li) Debug.Print "Seek to "; Hex(li.highpart); Hex(li.lowpart) End Function



这里是窗体测试代码,我测试读取了一个2.38G的页面文件,偏移量2451374078处1个字节的内容
VB.NET code
Option Explicit Private Sub Command1_Click() Dim hFile As Long hFile = MyOpen("c:\pagefile2.sys") If hFile Then Dim curPos As Currency curPos = 2451374078@ Debug.Print MySeek(hFile, curPos / 10000@, FILE_BEGIN) Dim b As Byte, lBytesRead As Long ReadFile hFile, b, 1, lBytesRead, ByVal 0 Debug.Print b CloseHandle hFile End If End Sub


#13楼 得分:0回复于:2008-05-22 14:51:12
谢谢大家对我的帮助,今天中午时在gogole发现了一段代码,是国外一个论坛的,试了一下好用。
特意转了进来,以后再有朋友有类似困扰就方便了,,,,,希望对大家有用。


'超过2g时利用指针定位SetFilePointer
Private Function SeekPosDouble(ByVal FHandle As Long, ByVal NewPos As Double) As Boolean
Dim SizeLow As Long, SizeHigh As Long
SizeLow = DoubleToLongs(NewPos, SizeHigh)
SeekPosDouble = SeekPos(FHandle, SizeLow, SizeHigh)
End Function

Private Function SeekPos(ByVal FHandle As Long, ByVal NewPos As Long, Optional ByVal PosHigh As Long = 0) As Boolean
Dim Ret As Long, dwError As Long
Ret = SetFilePointer(FHandle, NewPos, PosHigh, FILE_BEGIN)

If Ret = -1 Then
dwError = GetLastError
If dwError = NO_ERROR Then SeekPos = True
Else
SeekPos = True
End If

End Function

Private Function DoubleToLongs(ByVal Dbl As Double, ByRef SizeHigh As Long) As Long
Dim SizeLowDbl As Double
SizeHigh = Fix(Dbl / 4294967296#)
SizeLowDbl = Dbl - SizeHigh * 4294967296#
If SizeLowDbl > 2147483647 Then
DoubleToLongs = CLng(SizeLowDbl - 2147483648#) Xor &H80000000
Else
DoubleToLongs = SizeLowDbl
End If
'---------------------------------------
End Function
#14楼 得分:0回复于:2008-05-22 14:54:17
补一句,使用方法是SeekPosDouble 句柄,起点
然后后面的模块会将SetFilePointer 移到起点位置

YES!!!!头疼的问题终于解决了,另外今天14点时,跟朋友反复调试,居然发现我下载时的数据超2g时crc校验不正确居然是因为。。。。。。控件版本没有正确换成最新的。。。当时图方便用迅雷下载的控件,结果。。。。。该死的。。。。迅雷,害人啊。。。此问题及FTP下载超2g问题搞了我正正2天。。。。终于。。。。YES了!
#15楼 得分:0回复于:2008-05-24 14:08:01
DWORD SetFilePointer(
  HANDLE hFile,                // handle to file
  LONG lDistanceToMove,        // bytes to move pointer
  PLONG lpDistanceToMoveHigh,  // bytes to move pointer
  DWORD dwMoveMethod          // starting point
);


最後一個參數 可以有三值值
FILE_BEGIN  從開頭
FILE_CURRENT 從當前位 置 
FILE_END    從文件尾,

如果大於 4G,可以先用 SetFilePointer 把位置定到 4 G, 再用 SetFilePointer + FILE_CURRENT 再加一個新的位置上去


更簡單的方法是用


BOOL SetFilePointerEx(
  HANDLE hFile,                    // handle to file
  LARGE_INTEGER liDistanceToMove,  // bytes to move pointer
  PLARGE_INTEGER lpNewFilePointer, // new file pointer
  DWORD dwMoveMethod              // starting point
);
  • zhoutler用户头像
  • zhoutler
  • (一代程序巨浆--用浆糊粘贴别人)
  • 等 级:
#16楼 得分:0回复于:2008-05-24 18:45:24
用内存映射文件吧,不要折磨这些API了
#17楼 得分:0回复于:2008-05-24 20:13:19
引用 16 楼 zhoutler 的回复:
用内存映射文件吧,不要折磨这些API了



呵呵
#18楼 得分:0回复于:2008-05-28 00:39:34
啊。。。。。15楼的朋友早说就好了啊。。。。原来还可以这样的啊。。。。。晕死。。。。那我过2g时不就可以先移动到2g,再从当前位置移动到任意位置就使现了超2g?晕。。。。。。
16楼的朋友,内存影射对这些大文件也能高效么?????现在小弟还处于初学阶段,对这些还不甚了解
相关问题
vb 如何写一个大于2G的文件请教高手
在用CFile的seek()方法时遇到的问题,求达人援助一下VC/MFC / 基础类 ...
哪里有PE格式中文说明? C++ Builder / 基础类- CSDN社区community ...
300分征求一个文件格式的设计思路