VB二进制文件的问题

我做了两个程序:
第一个把一个普通文件(不是二进制,是用记事本就能打开的文件,但是里面有许多中文)和一些别的文件加密后保存到另一个二进制文件里;
第二个把加密后的文件边解密边读取信息,并不在硬盘上保存任何临时文件,直接将最原始的那个普通文件中的数据分离到内存中
原来是可以的,但要保存临时文件;现在想改进一下,不保存临时文件了直接读取,其中有几个关键的函数:
LInputQ函数:类似于Line Input #语句,却是从二进制文件中读取一行(以遇到Chr(13)为准);t = &HFF - t Xor Q是解密方法,Q是一个全局Byte变量
Public Function LInputQ(ByVal FileNumber As Integer) As String
Dim t As Byte
Get #FileNumber, , t
t = &HFF - t Xor Q
Do Until t = 13
LInputQ = LInputQ & Chr(t)
Get #FileNumber, , t
t = &HFF - t Xor Q
Loop
Get #FileNumber, , t
End Function
现在,当我用它(LInputQ)去读取英文时,很正常;但是,一旦遇到中文,就出问题了,返回值有问题,就像" "(四个空格)一样。
比如,原始文件内容为一个“不”字(它的Ascii是13,78),在读取时就变成了178,187不知道是怎么回事。
请大家帮忙,以下是第一个程序的关键代码:
(PB是进度条,Wname是是否写入名称(不管是否写入名称都出现以上问题))
Private Sub AppendMix(ByVal OutNumber As Integer, ByVal FileN As String, ByRef PGBR As ProgressBar, Optional Wname As Boolean = True, Optional k As Byte = &H7F)
Dim i As Long, fLen As Long, tmp As Byte, st As String * 64

Open FileN For Binary As #2

If Wname Then
st = Mid(FileN, InStrRev(FileN, "\") + 1) & String(128, " ")
Put #1, , st
End If

fLen = LOF(2)
Put #1, , CByte(Int(fLen / &H1000000))
Put #1, , CByte(Int(fLen / &H10000) Mod &H100)
Put #1, , CByte(Int(fLen / &H100) Mod &H100)
Put #1, , CByte(fLen Mod &H100)

PGBR.Max = fLen

For i = 1 To fLen
Get #2, , tmp
Put #1, , CByte((&HFF - tmp) Xor k)
PGBR.Value = i
Next i

Close #2
End Sub
既然"不"的编码是178,187,那么如何从178,187得到字符串"不"?

添加一个类模块,粘贴如下代码:
Dim lFileName As String
Dim lFileNum As Integer
Dim lStatus As Integer '-1=closed;1=opened;2=已经开始读取
Dim lIsEndRead As Boolean '=true表示或者读完文件或者出错,即不能在继续读了,主程序应退出读取
Dim lTrimSpaces As Boolean

Dim lAutoOpen As Boolean '是否设置 FileName 属性时自动打开文件,默认为true(类初始化时设为true)
Dim lAutoClose As Boolean '是否 读取行读完文件或出错时 自动关闭文件,默认为true(类初始化时设为true)

Dim af_BlockBytes() As Byte

Dim af_lngFileLength As Long
Dim af_lngBuffStartPos As Long, af_LastTailPos As Long

Dim af_LeftBytes() As Byte, af_LeftBytesLen As Integer '上次剩余的字节
Dim af_strBuf As String

Dim af_RetBufLen As Integer
Dim af_PtrInBuf As Long
Dim af_blIgnoreFirstVbLf As Boolean

Dim BufBytes() As Byte '此仅为GetNextLine函数用,为了不每次调用GetNextLine时候都重新定义,故将之做为全局的了,其实应是局部的

Public Function GetNextLine(ByRef RetString As String) As Integer
'返回1表示正常读取了
'返回-1表示正常,但读完了文件
'返回0表示出错

Dim j As Long

If lStatus < 0 Then GoTo errExit

lStatus = 2
Do Until af_lngBuffStartPos > af_lngFileLength '缓冲块起始循环,逐渐每次加缓冲块大小,直到缓冲块起始超过文件总长读完文件

If af_PtrInBuf < 0 Then '此作为标志,=-1表示下次运行该函数要重新读取新的缓冲区块,否则不重新读取,仍使用当前缓冲区和af_PtrInBuf指针

'----从af_lngBuffStartPos读取一些字节放入缓冲块af_RetBytes
af_RetBufLen = FileGetBytesLocal(lFileNum, af_lngBuffStartPos, af_BlockBytes())

'************出错处理******************
If af_RetBufLen <= 0 Then GoTo errExit

'===============逐个扫描缓冲块中的字节是否是vbCr或vbLf===================
af_PtrInBuf = 1
af_LastTailPos = 1 '缓冲块上次vbCr或vbLf后的字节位置(结果字符串包含该字节)
End If

Do Until af_PtrInBuf > af_RetBufLen

If af_blIgnoreFirstVbLf And af_PtrInBuf = 1 And af_BlockBytes(af_PtrInBuf) = 10 Then '如果需要忽略第一个vblf
af_LastTailPos = af_LastTailPos + 1
af_blIgnoreFirstVbLf = False '恢复标志:当前缓冲块不需要忽略第一个字节(若是vblf)
GoTo NextBuffLoop
End If

If af_BlockBytes(af_PtrInBuf) = 13 Or af_BlockBytes(af_PtrInBuf) = 10 Then
'发现一个13/10
'本行读到位置:af_PtrInBuf - 1

'将这一行存入
If af_PtrInBuf - af_LastTailPos + af_LeftBytesLen < 1 Then
af_strBuf = ""
Else
'-----将要返回的字符串的所有字节全部弄到BufBytes()--
ReDim BufBytes(1 To af_PtrInBuf - af_LastTailPos + af_LeftBytesLen) 'af_PtrInBuf - 1 - af_LastTailPos + 1

'先加上LeftBytes
For j = 1 To af_LeftBytesLen
BufBytes(j) = af_LeftBytes(j)
Next j

'加上af_RetBytes
For j = 1 To af_PtrInBuf - af_LastTailPos
BufBytes(j + af_LeftBytesLen) = af_BlockBytes(af_LastTailPos + j - 1)
Next j

af_strBuf = BufBytes
af_strBuf = StrConv(af_strBuf, vbUnicode)
End If

RetString = af_strBuf
If lTrimSpaces Then RetString = Trim(RetString)

Erase af_LeftBytes
af_LeftBytesLen = 0

'----设置一个缓冲块内部的下一行的起始的位置(下一行字符包括这个字节)
af_LastTailPos = af_PtrInBuf + 1

'判断是否是vbcr+vblf连着的,若是,跳过下一个vblf
If af_BlockBytes(af_PtrInBuf) = 13 Then
If af_PtrInBuf + 1 > af_RetBufLen Then '如果下一个字节已经超过这个缓冲块,则只设置标志
af_blIgnoreFirstVbLf = True
Else '下一个没超过这个缓冲块,直接跳过下一个字节
If af_BlockBytes(af_PtrInBuf + 1) = 10 Then af_LastTailPos = af_LastTailPos + 1: af_PtrInBuf = af_PtrInBuf + 1
End If
End If

'返回
If af_PtrInBuf + 1 > af_RetBufLen And af_lngBuffStartPos + af_RetBufLen > af_lngFileLength Then
GetNextLine = -1
lIsEndRead = True
If lAutoClose Then CloseFile
Else
GetNextLine = 1
End If
af_PtrInBuf = af_PtrInBuf + 1 '下一条是Exit Function ,不执行NextBuffLoop里的+1了
Exit Function

End If 'if af_BlockBytes(af_PtrInBuf) = 13 Or af_BlockBytes(af_PtrInBuf) = 10

NextBuffLoop: '扫描当前缓冲块的下一个字节
af_PtrInBuf = af_PtrInBuf + 1
Loop
af_PtrInBuf = -1 '此作为标志,=-1表示下次运行该函数要重新读取新的缓冲区块,否则不重新读取,仍使用当前缓冲区和af_PtrInBuf指针

'============看缓冲块中是否还有剩余为处理的字节,若有,将剩余的存入af_LeftBytes============
If af_LastTailPos <= af_RetBufLen Then
ReDim Preserve af_LeftBytes(1 To af_RetBufLen - af_LastTailPos + 1 + af_LeftBytesLen)
For j = 1 To af_RetBufLen - af_LastTailPos + 1
af_LeftBytes(j + af_LeftBytesLen) = af_BlockBytes(af_LastTailPos + j - 1)
Next j
af_LeftBytesLen = af_RetBufLen - af_LastTailPos + 1 + af_LeftBytesLen
End If

'===========继续读下一批缓冲块==============
af_lngBuffStartPos = af_lngBuffStartPos + af_RetBufLen
Loop

'///////////////////全部读完文件,,看还有无剩余的////////////////////
If af_LeftBytesLen > 0 Then
RetString = af_LeftBytes
If lTrimSpaces Then RetString = Trim(RetString)
Erase af_LeftBytes
af_LeftBytesLen = 0

If lAutoClose Then CloseFile
GetNextLine = -1
lIsEndRead = True
Exit Function
End If

errExit:
GetNextLine = 0
lIsEndRead = True
If lAutoClose Then CloseFile
End Function

Public Sub Init()
ReDim af_BlockBytes(1 To 1) '缓冲块

Erase af_LeftBytes
af_LeftBytesLen = 0

af_strBuf = ""
af_lngFileLength = 0
af_lngBuffStartPos = 1 '当前缓冲块的起始处所在的文件位置
af_LastTailPos = 1
af_PtrInBuf = -1 '此作为标志,=-1表示下次运行该函数要重新读取新的缓冲区块,否则不重新读取,仍使用当前缓冲区和af_PtrInBuf指针

af_blIgnoreFirstVbLf = False '初始化标志:当前缓冲块不需要忽略第一个字节(若是vblf)

lIsEndRead = False
End Sub

Public Function GetPercent() As Single
If af_lngFileLength > 0 Then
If af_PtrInBuf < 0 Then GetPercent = (af_lngBuffStartPos - 1) / _
af_lngFileLength Else GetPercent = (af_lngBuffStartPos _
+ af_PtrInBuf - 1) / af_lngFileLength
End If
End Function

Public Sub CloseFile()
If lFileNum > 0 Then Close lFileNum: lFileNum = 0
lStatus = -1
'不Init,防止读取行后自动关闭文件时候状态变量被初始化;在OpenFile时会Init
End Sub

Public Function OpenFile() As Boolean
If lFileNum > 0 Then CloseFile
lFileNum = FreeFile
On Error GoTo errH
Open lFileName For Binary As #lFileNum
lStatus = 1
Init
af_lngFileLength = LOF(lFileNum)
OpenFile = True
Exit Function
errH:
If lFileNum > 0 Then CloseFile
OpenFile = False
End Function

Public Property Get FileName() As String
FileName = lFileName
End Property

Public Property Let FileName(ByVal vNewValue As String)
If lFileNum > 0 Then CloseFile
lFileName = vNewValue
If lAutoOpen Then OpenFile
End Property

Public Property Get FileNum() As Integer
FileNum = lFileNum
End Property

Private Function FileGetBytesLocal(FileNum As Integer, _
ReadPos As Long, _
ArrBytes() As Byte, _
Optional EndingBorder As Long = 0, _
Optional ReadMax As Integer = 4096, _
Optional ShowResume As Byte = 1) As Integer
'从文件号FileNum中的ReadPos位置开始读取一批字节
'若EndingBorder=0 则在不超过文件末尾的条件下读ReadMax个字节,若不足_
'ReadMax则只读到文件末尾
'若EndingBorder>0 则不是不超过文件末尾,而是不超过EndingBorder地读
'会重新定义ArrBytes()数组
'ShowResume为若出错是否出对话框问重试=0不提示,=1提示取消和重试,=2_
'提示终止、重试、忽略
'返回读取的字节数,若失败返回<=0,若重试对话框用户终止,则返回<0;_
'若用户“忽略”则返回=0为一般错误
'要求文件以Binary方式打开

'************************注意:提前应定义redim一下ArrBytes();_
'再有一次读的字节数不超过32K**********************************

Dim Ending As Long
Dim BytesUBound As Integer

If EndingBorder > 0 Then Ending = EndingBorder Else Ending = LOF(FileNum)
If Ending < ReadPos Then
If ShowResume > 0 Then MsgBox "致命错误:读取位置超出可读边界!", 16
FileGetBytesLocal = -1
Exit Function
End If
If Ending - ReadPos + 1 >= ReadMax Then BytesUBound = ReadMax Else _
BytesUBound = Ending - ReadPos + 1
If UBound(ArrBytes) <> BytesUBound Or LBound(ArrBytes) <> 1 Then
ReDim ArrBytes(1 To BytesUBound) As Byte
End If

On Error GoTo errH
Get #FileNum, ReadPos, ArrBytes

FileGetBytesLocal = BytesUBound
Exit Function
errH:
Dim ms As Integer
If ShowResume > 0 Then
ms = RetryBoxLocal(ShowResume = 1)
If ms = vbRetry Then
Resume
ElseIf ms = vbIgnore Then
FileGetBytesLocal = 0
Else
FileGetBytesLocal = -1
End If
Else
FileGetBytesLocal = -1
End If
End Function

Private Function RetryBoxLocal(Optional RetryCancelStyle As Boolean = True, _
Optional IsRead As Boolean = True, _
Optional tFileNum As Integer = -1) As Integer
'显示一个读取/写入文件失败的重试对话框
'IsRead=true为读取,false为写入
'tFileNum 若给出,则错误对话框中显示错误位置,否则不显示错误位置
'RetryCancelStyle=true 为vbRetryCancel,否则为vbAbortRetryIgnore样式

'返回用户选择的按扭值

Dim ms As Integer
Dim MsgButtonStyle As VbMsgBoxStyle
Dim strWorkStyle As String
Dim strPos As String

If RetryCancelStyle Then
MsgButtonStyle = vbRetryCancel
Else 'ShowResume = 2
MsgButtonStyle = vbAbortRetryIgnore
End If
strWorkStyle = IIf(IsRead, "读取", "写入")

If tFileNum > 0 Then strPos = "错误位置:" & CStr(Seek(tFileNum)) Else strPos = ""
ms = MsgBox("软件无法" & strWorkStyle & "指定的文件。" & strPos _
& vbCrLf _
& "请确保磁盘可用并且文件可以访问。", MsgButtonStyle + vbCritical, _
strWorkStyle & "文件失败")
RetryBoxLocal = ms
End Function

Private Sub Class_Initialize()
lAutoOpen = True '设置 FileName 属性时自动打开文件
lAutoClose = True '读取行读完文件或出错时 自动关闭文件
lTrimSpaces = False '不自动Trim()结果行
End Sub

Public Property Get Status() As Integer
Status = Status
End Property

Public Property Let Status(ByVal vNewValue As Integer)
lStatus = vNewValue
End Property

Public Property Get IsEndRead() As Boolean
IsEndRead = lIsEndRead
End Property

Public Property Get TrimSpaces() As Boolean
TrimSpaces = lTrimSpaces
End Property

Public Property Let TrimSpaces(ByVal vNewValue As Boolean)
lTrimSpaces = vNewValue
End Property

Public Property Get AutoOpen() As Boolean
AutoOpen = lAutoOpen
End Property

Public Property Let AutoOpen(ByVal vNewValue As Boolean)
lAutoOpen = vNewValue
End Property

Public Property Get AutoClose() As Boolean
AutoClose = lAutoClose
End Property

Public Property Let AutoClose(ByVal vNewValue As Boolean)
lAutoClose = vNewValue
End Property

'在主程序中的代码:
Dim aFile As clsReadLines
Dim strLine As String
Set aFile = New clsReadLines
aFile.FileName = "H:\abc1.txt"

'************这一块可不设置,按默认即可*******************
' 设置属性
aFile.TrimSpaces = True '返回结果是否删除首尾空格
aFile.AutoClose = True
aFile.AutoOpen = True
'**********************************************************

Do Until aFile.IsEndRead
If aFile.GetNextLine(strLine) <> 0 Then '读完文件(=-1)或出错(=0)
Debug.Print strLine
Debug.Print aFile.GetPercent
End If
Loop
温馨提示:答案为网友推荐,仅供参考
第1个回答  2009-10-15
下面是改进后的LInputQ函数,应该可以正确读取汉字字符的。

Public Function LInputQ(ByVal FileNumber As Integer) As String
Dim t As Byte
Get #FileNumber, , t
t = &HFF - t Xor Q
Do Until t = 13
LInputQ = LInputQ & t
Get #FileNumber, , t
t = &HFF - t Xor Q
Loop
Get #FileNumber, , t
LInputQ = StrConv(LInputQ, vbUnicode)
End Function本回答被提问者采纳
第2个回答  2009-10-05
Dim bytes() As Byte
dim lLength as Long
Open "c:\main.exe" For Binary As #1 '读取字节
lLength=LOF(1)
ReDim bytes(1 To lLength) As Byte
Get 1, , bytes
Close #1

'将文件以十六进制方式输出到Text1中,这个过程很耗时,130K的文件大概需要2分钟,而且越到后面速度越慢
Dim strTmp As String
For i = 1 To lLength
strTmp = strTmp & " " & Hex(bytes(i))
DoEvents
Next
Text1.Text = strTmp

Open "d:\abcd.exe" For Binary As #1 '将字节转存
Put 1, , bytes
Close #1

End Sub

这个是以前用过的,你稍微改下就可以用了
第3个回答  2009-10-07
‘不’ 的16进制吗是 B2 BB
单个字节换成十进制当然是178,187
你的(Ascii是13,78)是如何得来的

''''''''''''''''''''
如何从178,187得到字符串"不"?:

你吧这两个字节按顺序写到文件里自然就是"不"字了
你都把它拆成字节了还要还原干嘛,中文是以字为单位的
VB的string类型确实很难理解
像VB里的 ‘不A’是用3个字节储存的 ‘B2 BB 41’
你要找点Windows字串储存格式资料看看
第4个回答  2009-10-06
对于中文最好的方法是使用unicode码!