VB6,读写Unicode编码的文本文件怎么会这样?

ynduanlian 2012-02-06 10:44:58
在VB6中用一段代码把文本文件1.txt中的半角字符“A”替换为全角字符“A”:

Private Sub Command1_Click()
Dim Str1 As String
Dim Str2 As String
Dim I As Long
Dim StrTmpFile As String
Dim iCompare As Integer
Dim C1 As String
Dim C2 As String
iCompare = vbBinaryCompare
StrTmpFile = App.Path & "\" & "SBC2DBC.tmp"

Open "C:\1.txt" For Input As #1
Open StrTmpFile For Output As #2
While Not EOF(1)
Line Input #1, Str1
Str2 = Str1
C1 = "A"
C2 = StrConv(C1, vbWide)
Str2 = Replace(Str2, C1, C2, , , iCompare)
Print #2, Str2
Wend
Close #1
Close #2
Kill "C:\1.txt"
Name StrTmpFile As "C:\1.txt"
End Sub

现测试文件:C:\1.txt的内容为:3841195078-87113-iMANHpBAcI
当把上述C:\1.txt放入上面字符串,存为Ansi编码时,运行上述程序后没有发现问题,A被成功替换成了“A”
当把上述C:\1.txt放入上面字符串,存为Unicode编码时,运行上述程序后,文件中的内容变成了:
?841195078-87113-iMANHpBAcI
前面的字符3变成了一个不可识别的符号加问号,而且用记事本查看,原来unicode编码的文件变成了Ansi编码。

请问,在VB6中,如何读写一个unicode编码的文本文件?
...全文
423 18 打赏 收藏 举报
写回复
18 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
Tiger_Zhao 2012-02-07
比较简便的方法如下:

首先用二进制方式读取文件的前几个字节,预判其编码
FF FE -> "Unicode"
FE FF -> "Unicode (big endian)"
EF BB BF -> "UTF-8"
其他 -> "Ascii" 如果有中文则用 "gb2312"

然后就可以直接用 ADO 的 Stream 对象读取指定编码的文本
'读
Dim oStream As ADODB.Stream
Dim sText As String

Set oStream = New ADODB.Stream
oStream.Open
oStream.Charset = "Unicode"
oStream.Type = adTypeText
oStream.LoadFromFile FileName
sText = oStream.ReadText()
oStream.Close

'写
Dim oStream As ADODB.Stream
Dim sText As String

Set oStream = New ADODB.Stream
oStream.Open
oStream.Charset = "Ascii"
oStream.Type = adTypeText
oStream.WriteText sText
oStream.SaveToFile FileName, adSaveCreateOverWrite
oStream.Close
  • 打赏
  • 举报
回复
Tiger_Zhao 2012-02-07
[Quote=引用 13 楼 rrrfff 的回复:]这样看来VB写个文件都麻烦,用C++不过几行代码。[/Quote]
做梦,看看这个 http://topic.csdn.net/t/20020404/16/622806.html
  • 打赏
  • 举报
回复
ynduanlian 2012-02-07
非常感谢各位的指点,真的很有收获,谢谢!
  • 打赏
  • 举报
回复
赵4老师 2012-02-07
仅供参考
Private Declare Function MultiByteToWideChar Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByRef lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long) As Long
Private Declare Function WideCharToMultiByte Lib "kernel32" (ByVal CodePage As Long, ByVal dwFlags As Long, ByVal lpWideCharStr As Long, ByVal cchWideChar As Long, ByRef lpMultiByteStr As Any, ByVal cchMultiByte As Long, ByVal lpDefaultChar As Long, ByVal lpUsedDefaultChar As Long) As Long
'常用的代码页:
const cpUTF8 =65001
const cpGB2312 = 936
const cpGB18030=54936
const cpUTF7 =65000
Function MultiByteToUTF16(UTF8() As Byte, CodePage As Long) As String
Dim bufSize As Long
bufSize = MultiByteToWideChar(CodePage, 0&, UTF8(0), UBound(UTF8) + 1, 0, 0)
MultiByteToUTF16 = Space(bufSize)
MultiByteToWideChar CodePage, 0&, UTF8(0), UBound(UTF8) + 1, StrPtr(MultiByteToUTF16), bufSize
End Function

Function UTF16ToMultiByte(UTF16 As String, CodePage As Long) As Byte()
Dim bufSize As Long
Dim arr() As Byte
bufSize = WideCharToMultiByte(CodePage, 0&, StrPtr(UTF16), Len(UTF16), 0, 0, 0, 0)
ReDim arr(bufSize - 1)
WideCharToMultiByte CodePage, 0&, StrPtr(UTF16), Len(UTF16), arr(0), bufSize, 0, 0
UTF16ToMultiByte = arr
End Function

Private Sub Command1_Click()
MsgBox MultiByteToUTF16(UTF16ToMultiByte("ab中,c", cpUTF8), cpUTF8)
End Sub

  • 打赏
  • 举报
回复
RLib 2012-02-06
这样看来VB写个文件都麻烦,用C++不过几行代码。
  • 打赏
  • 举报
回复
RLib 2012-02-06
[Quote=引用 2 楼 ynduanlian 的回复:]

试了下FileSystemObject,一样存在这个问题:

结果变成:
? 8 4 1 1 9 5 0 7 8 - 8 7 1 1 3 - i M A N H p B A c I
[/Quote]

写文件头
  • 打赏
  • 举报
回复
东方之珠 2012-02-06
  • 打赏
  • 举报
回复
东方之珠 2012-02-06
Unicode little endian 开头2个字节是:FF FE
Unicode big endian 开头2个字节是:FE FF
  • 打赏
  • 举报
回复
赵4老师 2012-02-06
推荐使用WinHex软件查看文件或内存中的原始字节内容。
  • 打赏
  • 举报
回复
东方之珠 2012-02-06
很简单啊,读取文件头,判断一下是否是Unicode编码.
  • 打赏
  • 举报
回复
ynduanlian 2012-02-06
[Quote=引用 1 楼 chenjl1031 的回复:]
Ansi,Unicode(little endian),Unicode big endian,UTF-8编码文件相互转换
http://blog.csdn.net/chenjl1031/article/details/6059767
[/Quote]
您的空间文章我拜读了,但是有个问题:程序读取一个文件时并不知道它是哪种编码(Ansi或Unicode)的,所以就到不了您空间中转换的那些个方法。
  • 打赏
  • 举报
回复
贝隆 2012-02-06

Private Sub Form_Load()
Text2.Text = "3841195078-87113-iMANHpBAcI"
End Sub
  • 打赏
  • 举报
回复
贝隆 2012-02-06

Private Sub cmdRead_Click() '读Unicode文本

Dim textBytes() As Byte, headBytes(2) As Byte

fn = App.Path & "\MyUnicode.txt"
If Dir(fn) = "" Then
MsgBox "文件不存在,请先单击【写入】按钮生成“MyUnicode.txt”文件。", vbInformation
Exit Sub
End If

Open fn For Binary As #1
Get #1, , headBytes() '读取文件头。
Close #1

If headBytes(0) = 255 And headBytes(1) = 254 Then '是Unicode编码。十六进制为:FF 、FE。

Open fn For Binary As #1
ReDim textBytes(LOF(1) - 2) '减去文件头占用的2个字节。
Get #1, 3, textBytes() '第三个字节起为文本内容。
Close #1

Text1.Text = textBytes() '在 VB 中字符串是 UniCode 格式,所以Unicode码直接赋值即可显示文本内容。

Else
MsgBox "非Unicode编码,不予读入,请单击【写入】按钮。", vbInformation
End If

End Sub

Private Sub cmdWrite_Click() '写Unicode文本。

Dim textBytes() As Byte, headBytes(2) As Byte

headBytes(0) = 255: headBytes(1) = 254
textBytes() = Text2.Text

Open App.Path & "\MyUnicode.txt" For Binary As #1
Put #1, 1, headBytes() ' 写文件头。
Put #1, 3, textBytes() ' 写文本内容。
Close #1

End Sub

  • 打赏
  • 举报
回复
贝隆 2012-02-06
把前两个字节去掉
  • 打赏
  • 举报
回复
东方之珠 2012-02-06
你用的vbWide,那是当然的。你看看我博客里面的是怎么用的。
  • 打赏
  • 举报
回复
ynduanlian 2012-02-06
试了下FileSystemObject,一样存在这个问题:
Private Sub Command2_Click()
Dim fs As Scripting.FileSystemObject
Dim ss As Scripting.TextStream
Set fs = CreateObject("Scripting.FileSystemObject")
Dim C1, C2 As String
Set ss = fs.OpenTextFile("C:\1.txt")
Dim Str As String
Str = ss.ReadAll
C1 = "A"
C2 = StrConv(C1, vbWide)
Str = Replace(Str, C1, C2, , , iCompare)
Set ss = fs.OpenTextFile("C:\1.txt", ForWriting)
ss.Write (Str)

End Sub

结果变成:
? 8 4 1 1 9 5 0 7 8 - 8 7 1 1 3 - i M A N H p B A c I
  • 打赏
  • 举报
回复
东方之珠 2012-02-06
Ansi,Unicode(little endian),Unicode big endian,UTF-8编码文件相互转换
http://blog.csdn.net/chenjl1031/article/details/6059767
  • 打赏
  • 举报
回复
worldy 2012-02-06
使用二进制方式打开,存到数组,赋值给字串变量
  • 打赏
  • 举报
回复
发帖
VB基础类
加入

7605

社区成员

VB 基础类
社区管理员
  • VB基础类社区
申请成为版主
帖子事件
创建了帖子
2012-02-06 10:44
社区公告
暂无公告