這是在幾年前寫文本批量處理時遇到的問題。百度至今未能解決,特來求大神指點。
問題如下。
當時程式寫了個遍歷目錄的功能,然后卻發現總有某幾個檔案打不開,除錯后發現是檔案名錯誤。
檔案名是Unicoe或者UTF-8字符,或者是全部,或者是部分
最常見的就是其它字符可以識別,其中的空格變成了?
就好像 “VB 編程 論壇” 變成“VB?編程?論壇”
有些就是全部亂碼
除錯中發現,VB在獲取檔案名后自動轉換,例如變數什么的,一點解決的辦法也沒有‘
要是檔案內容存在編碼問題的話,還可以使用位元組轉換,而檔案名就無從下手了。
或者說,是不是也有一種辦法可以從位元組狀態去操作檔案名
哪怕識別判斷一下,要是就修改成正常的,再去打開。
uj5u.com熱心網友回復:
幫頂同問,因為這個問題我也遇到了,一直沒能解決……(比如含Alt+0160弄出來的這種空白字符的檔案名)uj5u.com熱心網友回復:
作業系統保存檔案名不是用UFT-8的吧,至少在WINDOWS中的NTFS中我記得應該是UTF-16,這個用FSO處理時應該支持。uj5u.com熱心網友回復:
不行的,已經試過N多方法了,用FSO,Dir,FindFirstFile等API來獲取該檔案名都獲取不了!
uj5u.com熱心網友回復:
求大神,這個應該有解決辦法,不然VB豈不是廢了,想寫個文本處理器都只能放棄了uj5u.com熱心網友回復:
用fso的for each file in fso.getfolder("path").files方法也不能獲取嗎?uj5u.com熱心網友回復:
試過,取得的檔案名稱全是?問號!
uj5u.com熱心網友回復:
不能正確顯示是字體、語言的問題。不要把不能顯示和不能取到檔案名混淆起來!
uj5u.com熱心網友回復:
也不是, 我就要求取得這個檔案的fullpath,但你試試能不能朝這個檔案寫內容你就知道了(我沒要求它顯示。)
uj5u.com熱心網友回復:
uj5u.com熱心網友回復:
請舉例。那個字符?Unicode編碼多少?
uj5u.com熱心網友回復:
請舉例。
那個字符?Unicode編碼多少?
你新建個文本檔案,用小鍵盤Alt + 0160為它命名(是個空白字符,我也不知道它的Unicode編碼是多少),確定之后,這就是一個空白字符的檔案名,你再用你的方法朝這個檔案寫內容試試。 反正我試過不行。
uj5u.com熱心網友回復:
啊,可以寫入呀。
Option Explicit
Sub test()
Dim FSO As New FileSystemObject, bFile As File
For Each bFile In FSO.GetFolder("f:\").Files
If bFile.Name Like "w?.txt" Then‘’這個檔案名就是Alt+0160輸入的
bFile.OpenAsTextStream(ForWriting).Write "sdvssnvs"
Debug.Print bFile.OpenAsTextStream(ForReading).ReadAll
End If
Next
End Sub
...
uj5u.com熱心網友回復:
啊,可以寫入呀。
Option Explicit
Sub test()
Dim FSO As New FileSystemObject, bFile As File
For Each bFile In FSO.GetFolder("f:\").Files
If bFile.Name Like "w?.txt" Then‘’這個檔案名就是Alt+0160輸入的
bFile.OpenAsTextStream(ForWriting).Write "sdvssnvs"
Debug.Print bFile.OpenAsTextStream(ForReading).ReadAll
End If
Next
End Sub
我主要是要寫入二進制資料,用的是Open陳述句
Dim c(1) As Byte
c(0) = &HFF
c(1) = &HD8
Open bFile.Name For Binary As #1
Put #1, , c
Close #1
提示錯誤的檔案名
uj5u.com熱心網友回復:
我把1.txt的檔案名加了Alt + 0160。全部要用Unicode版本的函式進行處理。
Option Explicit
Private Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileW" (ByVal lpFileName As Long, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileW" (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long
Private 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
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Any) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileW" (ByVal lpFileName As Long, 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
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
Const MAX_PATH = 260
Const MAXDWORD = &HFFFF
Const INVALID_HANDLE_VALUE = -1
Const FILE_SHARE_READ = &H1
Const FILE_SHARE_WRITE = &H2
Const CREATE_NEW = 1
Const OPEN_EXISTING = 3
Const GENERIC_READ = &H80000000
Const GENERIC_WRITE = &H40000000
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName(MAX_PATH * 2 - 1) As Byte 'Unicode 需要雙倍長度
cAlternate(14 * 2 + 1) As Byte 'Unicode 需要雙倍長度
End Type
Const eeEndOfFile = 62 'Input past end of file
Function StripNulls(bytes() As Byte) As String
Dim i As Long
For i = 0 To UBound(bytes) Step 2
If bytes(i) = 0 And bytes(i + 1) = 0 Then
Exit For
End If
Next
StripNulls = LeftB(bytes, i)
End Function
Function FindFiles(path As String, searchPattern As String) As Collection
Dim oFiles As Collection
Dim hSearch As Long
Dim bFound As Boolean
Dim sFileName As String
Dim WFD As WIN32_FIND_DATA
Set oFiles = New Collection
If Right(path, 1) <> "\" Then path = path & "\"
sFileName = path & searchPattern
hSearch = FindFirstFile(StrPtr(sFileName), WFD)
If hSearch <> INVALID_HANDLE_VALUE Then
bFound = True
While bFound
sFileName = StripNulls(WFD.cFileName)
If (sFileName <> ".") And (sFileName <> "..") Then
oFiles.Add path & sFileName
End If
bFound = FindNextFile(hSearch, WFD)
Wend
Call FindClose(hSearch)
End If
Set FindFiles = oFiles
End Function
Function ReadAllText(ByVal path As String) As String
Dim hFile As Long
Dim nSize As Long
Dim bytes() As Byte
Dim lBytesRead As Long
hFile = CreateFile(StrPtr(path), GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
nSize = GetFileSize(hFile, 0)
ReDim bytes(nSize - 1) As Byte
ReadFile hFile, bytes(0), nSize, lBytesRead, ByVal 0&
CloseHandle hFile
If lBytesRead <> nSize Then Err.Raise eeEndOfFile
ReadAllText = StrConv(bytes, vbUnicode)
End Function
Sub Main()
Dim oFiles As Collection
Dim i As Long
Dim s As String
Set oFiles = FindFiles(App.path, "1*.*")
For i = 1 To oFiles.Count
s = oFiles(i)
Debug.Print s, "U+" & Hex(AscW(Mid$(s, InStrRev(s, "\") + 2, 1)))
Debug.Print ReadAllText(s)
Next
End Sub
D:\temp\UnicodeFileName\1?.TXT U+A0
abc中文
又:不如改用VB.Net吧,一點問題都沒有。
Imports System.Text
Imports System.IO
Module Module1
Sub Main()
For Each s As String In My.Computer.FileSystem.GetFiles("D:\temp\UnicodeFileName\", FileIO.SearchOption.SearchTopLevelOnly, "1*.*")
Console.WriteLine(s)
Console.WriteLine(BitConverter.ToString(Encoding.Unicode.GetBytes(Path.GetFileName(s))))
Console.WriteLine(My.Computer.FileSystem.ReadAllText(s, Encoding.Default))
Next
Console.ReadLine()
End Sub
End Module
uj5u.com熱心網友回復:
試試:檔案名變數不要使用 String 型別。在中文系統下,如果是字串型別變數,不可識別的字符會統統被“自動”替換成?。
uj5u.com熱心網友回復:
我把1.txt的檔案名加了Alt + 0160。
全部要用Unicode版本的函式進行處理。
Option Explicit
Private Declare Function FindFirstFile Lib "kernel32" Alias "FindFirstFileW" (ByVal lpFileName As Long, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindNextFile Lib "kernel32" Alias "FindNextFileW" (ByVal hFindFile As Long, lpFindFileData As WIN32_FIND_DATA) As Long
Private Declare Function FindClose Lib "kernel32" (ByVal hFindFile As Long) As Long
Private 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
Private Declare Function ReadFile Lib "kernel32" (ByVal hFile As Long, lpBuffer As Any, ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, ByVal lpOverlapped As Any) As Long
Private Declare Function CreateFile Lib "kernel32" Alias "CreateFileW" (ByVal lpFileName As Long, 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
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function GetFileSize Lib "kernel32" (ByVal hFile As Long, lpFileSizeHigh As Long) As Long
Const MAX_PATH = 260
Const MAXDWORD = &HFFFF
Const INVALID_HANDLE_VALUE = -1
Const FILE_SHARE_READ = &H1
Const FILE_SHARE_WRITE = &H2
Const CREATE_NEW = 1
Const OPEN_EXISTING = 3
Const GENERIC_READ = &H80000000
Const GENERIC_WRITE = &H40000000
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName(MAX_PATH * 2 - 1) As Byte 'Unicode 需要雙倍長度
cAlternate(14 * 2 + 1) As Byte 'Unicode 需要雙倍長度
End Type
Const eeEndOfFile = 62 'Input past end of file
Function StripNulls(bytes() As Byte) As String
Dim i As Long
For i = 0 To UBound(bytes) Step 2
If bytes(i) = 0 And bytes(i + 1) = 0 Then
Exit For
End If
Next
StripNulls = LeftB(bytes, i)
End Function
Function FindFiles(path As String, searchPattern As String) As Collection
Dim oFiles As Collection
Dim hSearch As Long
Dim bFound As Boolean
Dim sFileName As String
Dim WFD As WIN32_FIND_DATA
Set oFiles = New Collection
If Right(path, 1) <> "\" Then path = path & "\"
sFileName = path & searchPattern
hSearch = FindFirstFile(StrPtr(sFileName), WFD)
If hSearch <> INVALID_HANDLE_VALUE Then
bFound = True
While bFound
sFileName = StripNulls(WFD.cFileName)
If (sFileName <> ".") And (sFileName <> "..") Then
oFiles.Add path & sFileName
End If
bFound = FindNextFile(hSearch, WFD)
Wend
Call FindClose(hSearch)
End If
Set FindFiles = oFiles
End Function
Function ReadAllText(ByVal path As String) As String
Dim hFile As Long
Dim nSize As Long
Dim bytes() As Byte
Dim lBytesRead As Long
hFile = CreateFile(StrPtr(path), GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, ByVal 0&, OPEN_EXISTING, 0, 0)
nSize = GetFileSize(hFile, 0)
ReDim bytes(nSize - 1) As Byte
ReadFile hFile, bytes(0), nSize, lBytesRead, ByVal 0&
CloseHandle hFile
If lBytesRead <> nSize Then Err.Raise eeEndOfFile
ReadAllText = StrConv(bytes, vbUnicode)
End Function
Sub Main()
Dim oFiles As Collection
Dim i As Long
Dim s As String
Set oFiles = FindFiles(App.path, "1*.*")
For i = 1 To oFiles.Count
s = oFiles(i)
Debug.Print s, "U+" & Hex(AscW(Mid$(s, InStrRev(s, "\") + 2, 1)))
Debug.Print ReadAllText(s)
Next
End Sub
D:\temp\UnicodeFileName\1?.TXT U+A0
abc中文
又:不如改用VB.Net吧,一點問題都沒有。
Imports System.Text
Imports System.IO
Module Module1
Sub Main()
For Each s As String In My.Computer.FileSystem.GetFiles("D:\temp\UnicodeFileName\", FileIO.SearchOption.SearchTopLevelOnly, "1*.*")
Console.WriteLine(s)
Console.WriteLine(BitConverter.ToString(Encoding.Unicode.GetBytes(Path.GetFileName(s))))
Console.WriteLine(My.Computer.FileSystem.ReadAllText(s, Encoding.Default))
Next
Console.ReadLine()
End Sub
End Module
嗯,試了下,用你的方法和writefile函式是可以了。看來應該是Open陳述句不支持Unicode字符檔案名。
uj5u.com熱心網友回復:
而且用CreateFile、ReadFile、WriteFile函式的話,用fileName=Dir("E:\Test\*.*")找出來的檔案名也同樣可以讀寫uj5u.com熱心網友回復:
錯了,Dir命令獲得的檔案名不可以。另外發現一個有趣的現象:Word 2003打開這種特殊字符檔案名的Doc檔案時,能打開,但是會出現錯誤提示“內在不足...”,另外修改后無法保存。而且如果你新建一個doc檔案,想保存為這種特殊檔案名時,根本無法保存。看來Office 2003也沒考慮到這種特殊檔案名啊。uj5u.com熱心網友回復:
特殊檔案名多了去了!uj5u.com熱心網友回復:
這兩天暫時在整別的,還沒有機會去試再把問題詳細說一下
這個檔案系統顯示一切正常,例如保存的網頁
IE可以打開,記事本可以打開
但是其中有幾個空格VB讀取就變成了?
例如a=檔案名
除錯的時候會發現vb第一時間把中間的某幾個字符換成?
然后才賦值。
最簡單的測驗是新建一個文本框,運行后,把這個空格粘帖進去就變成了?
當然遇到的不只是這個?
有些也就空格或者個別字符變成?
其它還能看出是哪個檔案
有些完全不行。全是亂碼
今天回去找網頁試試。
uj5u.com熱心網友回復:
文本框是當前語言相關的,不支持全部的Unicode編碼。只有存放在String變數里的內容才不會自動替換(雖然Debug顯示也有?,但是內容沒變)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/93865.html
標籤:VB基礎類
