VB6 中使用以下方式讀取一個 UTF-8 文件後,另存爲一個新文件時出錯 “invalid procedure call or argument”
‘ 讀取
Dim adoS As Object
Set adoS = CreateObject("adodb.stream")
With adoS
.Charset = "utf-8"
.Type = 2
.Open
.LoadFromFile sUTF8File
ReadUTF8 = .ReadText
.Close
End With
’ 另存文件
Dim fso As New FileSystemObject
Dim txtFile As TextStream
Set txtFile = fso.CreateTextFile(sFile, True)
txtFile.Write (strContent)
txtFile.Close
一個臨時解決方法:
1, 將 txt中的內容Copy至 Word中
2, 在Word中所有所有文字,使用轉半角功能(Aa 圖標下: Change Case \ Half-width),對文字進行半角轉換
3, 再從Word文件中將轉換後的文字Copy至原 txt 文件中,保存
再次上傳即可成功
另一個解決方法:
不使用另存文件,而直接使用讀取到的 String ,將字串轉爲數據,然後再對數據進行處理。
Dim oarrLine() As String
oarrLine = Split(ReadUTF8, vbCrLf)
真正的原因:
爲何會出錯,真正的原因可能是因爲文件內容有一些特別的字符,導致寫文件時錯誤。如下示例:
https://stackoverflow.com/questions/17094281/getting-invalid-procedure-call-or-argument-in-vbscript
用如下解決方法:
>> f.close
>> Set f = goFS.CreateTextFile(".\tmp.txt", True, True) ' overwrite, unicode
>> f.WriteLine ChrW(&H1F00)
>>
>> --- no news are good news --
但出來的文件變爲了一個 unicode 文件,而非 UTF-8 文件。
如直接使用 unicode 方式進行處理,後續會發現其中一些中文會亂碼,導致保存至DB後,數據不正確。
最後的發現:
最終確實使用Notepad++ 的Encoding \ Convert to ANSI 後,即可發現有些原爲空格的位置,變爲了問題"?" 或亂碼,將此類記錄處理後,即可正常處理了。
最後的最後:
歸根結底,還是VB6 的 CreateTextFile 及 File.write 方法太舊,太過時,無法處理新的特殊字符,還是要升級使用 .Net 的處理方法才能從根本上解決問題,而不再擔心用戶的輸入。
補充:
UTF-8轉GBK的悲劇:特殊字符C2A0
這個問題出現得比較早:在傳給印象派的作品描述XML(GBK編碼)中一些文字信息經常包含亂碼,而且會一亂到底,甚至導致不同頁的錯亂。剛開始一直都沒有什麼頭緒,不過後來終於發現了部分頭緒:GBK的字符集過小,對一些特殊字符的轉碼會出現亂碼—-一些生僻字也就算了,但是其中卻包括這個字符:C2A0—-一個在網頁上經常使用排版用全角空格。就是這麼個字符,用戶從網頁端拷貝了一段文字,複製到界面上顯示正常,保存到作品XML文件中(UTF8編碼),顯示正常。但是上傳作品時由於將相應的XML編碼格式轉換成GBK,於是出現了亂碼……處理方法:
方法一:轉換時對文本信息做特殊處理,用0×20代替掉0xC2A0。
方法二:作品XML文件直接以UTF8編碼傳輸。
方法一有點頭疼治頭腳疼治腳的味道,雖然解決了這個問題,但是總歸不夠規範不夠完美—-很多頁面都是這麼做。而方法二則需要服務器支持,但可以完美的解決這個問題。以前服務器之所以用GBK編碼很大的理由可能在於GBK相對UTF8更省空間—-在這麼個硬盤空間足夠,帶寬足夠的現狀下,節約出來的那麼點東西又有什麼用呢?
- /**
- *
- * 將不換行空格(NO-BREAK SPACE,Unicode 0x00a0,UTF-8編碼:0xC2A0)替換爲普通空格。
- *
- * 用於避免因數據庫字符集不兼容導致這個字符變爲問號“?”的情況。
- */
- public static String nobreakSpaceToSpace(String str) {
- if (str == null) {
- return null;
- }
- char nbsp = 0x00a0;
- return str.replace(nbsp, ' ');
- }