SetFilePointer 回卷文件指针后,WriteFile 和 ReadFile 函数失败

of123 2008-05-16 01:48:57
用 CreateFile 函数创建一个磁盘文件,写文件正常:
hFile = CreateFile(strFileName, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, CREATE_NEW, 0, 0)

现需要更新其文件头部分的一个 TLV 对象的 Value 域。从文件起始查找该对象成功(SetFilePointer 和 ReadFile)。

ReadFile hFile, lngTmp, 4, ret, ByVal 0&
If ret <> 4 Then Exit Function

lngNumber = lngNumber + lngTmp '这里正常

ret = SetFilePointer(hFile, -4, 0, FILE_CURRENT) ' ret 得到新的指针,本例 = 2
ret = WriteFile(hFile, lngNumber, 4, n, ByVal 0&) '这里出现问题

'注:ret = 0(期望 1), n = 0(期望 4), GetLastError = 0

'如果上面正常或跳过上面的写,执行下面的读
ret = SetFilePointer(hFile, -4, 0, FILE_CURRENT) ' ret 得到新的指针,本例 = 2
ret = ReadFile(hFile, lngTmp, 4, n, ByVal 0&) '这里出现问题

'注:ret = 1(期望 1), n = 0(期望 4), GetLastError = 0
'按照 MSDN 的说法,返回值 = 1 且 lpNumberofBytesRead = 0 表示指针超出可读区域。

我现在的做法是绕过这一难题:

ret = SetFilePointer(hFile, -4, 0, FILE_CURRENT)
ret = SetFilePointer(hFile, ret, 0, FILE_BEGIN)
ret = WriteFile(hFile, lngNumber, 4, n, ByVal 0&)
'......

ret = SetFilePointer(hFile, -4, 0, FILE_CURRENT)
ret = SetFilePointer(hFile, ret, 0, FILE_BEGIN)
ret = ReadFile(hFile, lngTmp, 4, n, ByVal 0&)

这样可以正常读写。

但是总觉得有点别扭,也奇怪为什么回卷指针后会出现这样的问题。
...全文
624 14 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
Tiger_Zhao 2008-05-19
  • 打赏
  • 举报
回复
API中64位的值不多,到真是忘了它通过两个Long传递负数高位也要设置,所以应该是
ret = SetFilePointer(hFile, -4, -1, FILE_CURRENT)
舉杯邀明月 2008-05-16
  • 打赏
  • 举报
回复
你的执行语句与原来的也不一样了呀。
of123 2008-05-16
  • 打赏
  • 举报
回复
明白了,MSDN 说:

If lpDistanceToMoveHigh is not NULL, lpDistanceToMoveHigh and lDistanceToMove form a single 64-bit signed value that specifies the distance to move.

If lpDistanceToMoveHigh is NULL, lDistanceToMove is a 32-bit signed value. A positive value for lDistanceToMove moves the file pointer forward in the file, and a negative value moves the file pointer back.

实际上将 lpDistanceToMoveHigh 置为 ByVal 0& ,就是置为 Null。

不过现在不这样做了:

' 找到该对象的 Value 域,读取
n = SetFilePointer(hFile, 0, ByVal 0&, FILE_CURRENT)
ReadFile hFile, lngTmp, 4, ret, ByVal 0&
If ret <> 4 Then Exit Function

' 计算新值
lngNumber = lngNumber + lngTmp
Call SetFilePointer(hFile, n, 0, FILE_BEGIN)
Call WriteFile(hFile, lngNumber, 4, ret, ByVal 0&)
If ret <> 4 Then Exit Function

Call SetFilePointer(hFile, n, 0, FILE_BEGIN)
Call ReadFile(hFile, lngTmp, 4, ret, ByVal 0&)
If ret <> 4 Then Exit Function

If lngTmp = lngNumber Then Update_Trace_File_Number_of_Traces_Ex = True

谢谢大家的提示。结贴。
舉杯邀明月 2008-05-16
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 myjian 的回复:]
引用 3 楼 of123 的回复:
原来就是用的 Open, Get, Put 语句。但是用户要求文件大小可达 64 G。


真变态........单个文件就大于我的D分区了-_-
[/Quote]

你的E分区呢? ^_^

我的最大分区才60G。
160G的硬盘(有点小 ^_^),分了6个分区。
tanjiunnya 2008-05-16
  • 打赏
  • 举报
回复
虽然不明白怎么用setfilepointer,不过我在老外的网站给找了有关资料,希望可以帮忙楼主。

http://www.codeguru.com/vb/controls/vb_file/directory/article.php/c12917__3/
of123 2008-05-16
  • 打赏
  • 举报
回复
Public Declare Function SetFilePointer Lib "kernel32" (ByVal hFile As Long, ByVal lDistanceToMove As Long, lpDistanceToMoveHigh As Long, ByVal dwMoveMethod As Long) As Long

不完全是冗余的。因为我不能确定用户文件中该对象的位置,第一个 SetFilePointer 使我得到了当前指针位置,类似 Open 系统中的 Seek 函数,第二个 SetFilePointer 才可以从头偏移。

目前发现,如果不将偏移量高位置为 Null 就行了。

' 找到该对象的 Value 域,读取
ReadFile hFile, lngTmp, 4, ret, ByVal 0&
If ret <> 4 Then Exit Function

' 计算新值
lngNumber = lngNumber + lngTmp

ret = SetFilePointer(hFile, -4, ByVal 0&, FILE_CURRENT)
ret = WriteFile(hFile, lngNumber, 4, n, ByVal 0&)
If n <> 4 Then Exit Function

ret = SetFilePointer(hFile, -4, ByVal 0&, FILE_CURRENT)
ret = ReadFile(hFile, lngTmp, 4, n, ByVal 0&)
If n <> 4 Then Exit Function

If lngTmp = lngNumber Then Update_Trace_File_Number_of_Traces_Ex = True

大家可以继续讨论,晚一点结贴。
Tiger_Zhao 2008-05-16
  • 打赏
  • 举报
回复
SetFilePointer怎么声明的?

又:你所谓绕过的方式中第一个SetFilePointer是冗余的,它执行是否正确你根本没检查。
嗷嗷叫的老马 2008-05-16
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 of123 的回复:]
原来就是用的 Open, Get, Put 语句。但是用户要求文件大小可达 64 G。
[/Quote]

真变态........单个文件就大于我的D分区了-_-
m60a1 2008-05-16
  • 打赏
  • 举报
回复
顶一个,,学习一下.............
of123 2008-05-16
  • 打赏
  • 举报
回复
加了 FILE_FLAG_RANDOM_ACCESS ,问题依旧。

hFile = CreateFile(strFileName, GENERIC_READ Or GENERIC_WRITE, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, CREATE_NEW, FILE_FLAG_RANDOM_ACCESS, 0)
tanjiunnya 2008-05-16
  • 打赏
  • 举报
回复
我通常都用Put , Get 的说。。。
of123 2008-05-16
  • 打赏
  • 举报
回复
原来就是用的 Open, Get, Put 语句。但是用户要求文件大小可达 64 G。
Tiger_Zhao 2008-05-16
  • 打赏
  • 举报
回复
你用了 CREATE_NEW 参数,但是上来就要读,好像不一致。
要随机访问试试加上 FILE_FLAG_RANDOM_ACCESS 标志。

还有VB本身就能操作二进制文件,为什么还要API?
舉杯邀明月 2008-05-16
  • 打赏
  • 举报
回复
高手的难题,不是一般的啊。

我也没法理解为什么会有这个问题。

Up...

1,488

社区成员

发帖
与我相关
我的任务
社区描述
VB API
社区管理员
  • API
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧