Сохраните текстовый файл UTF-8 в кодировке VBA
Как я могу записать строки в кодировке UTF-8 в текстовый файл из VBA, как
Dim fnum As Integer
fnum = FreeFile
Open "myfile.txt" For Output As fnum
Print #fnum, "special characters: äöüß" 'latin-1 or something by default
Close fnum
Есть ли какие-то настройки на уровне приложения?
7 ответов
Я нашел ответ в Интернете:
Dim fsT As Object
Set fsT = CreateObject("ADODB.Stream")
fsT.Type = 2 'Specify stream type - we want To save text/string data.
fsT.Charset = "utf-8" 'Specify charset For the source text data.
fsT.Open 'Open the stream And write binary data To the object
fsT.WriteText "special characters: äöüß"
fsT.SaveToFile sFileName, 2 'Save binary data To disk
Конечно, не так, как я ожидал...
Вы можете использовать метод CreateTextFile или OpenTextFile, оба имеют атрибут "unicode", полезный для настроек кодирования.
object.CreateTextFile(filename[, overwrite[, unicode]])
object.OpenTextFile(filename[, iomode[, create[, format]]])
Пример: перезаписать:
CreateTextFile:
fileName = "filename"
Set fso = CreateObject("Scripting.FileSystemObject")
Set out = fso.CreateTextFile(fileName, True, True)
out.WriteLine ("Hello world!")
...
out.close
Пример: Добавить:
OpenTextFile Set fso = CreateObject("Scripting.FileSystemObject")
Set out = fso.OpenTextFile("filename", ForAppending, True, 1)
out.Write "Hello world!"
...
out.Close
Подробнее о документах MSDN
Это записывает метку порядка байтов в начале файла, которая не нужна в файле UTF-8, и некоторым приложениям (в моем случае, SAP) это не нравится. Решение здесь: Могу ли я экспортировать данные Excel с UTF-8 без спецификации?
Вот еще один способ сделать это - использовать функцию API WideCharToMultiByte:
Option Explicit
Private Declare Function WideCharToMultiByte Lib "kernel32.dll" ( _
ByVal CodePage As Long, _
ByVal dwFlags As Long, _
ByVal lpWideCharStr As Long, _
ByVal cchWideChar As Long, _
ByVal lpMultiByteStr As Long, _
ByVal cbMultiByte As Long, _
ByVal lpDefaultChar As Long, _
ByVal lpUsedDefaultChar As Long) As Long
Private Sub getUtf8(ByRef s As String, ByRef b() As Byte)
Const CP_UTF8 As Long = 65001
Dim len_s As Long
Dim ptr_s As Long
Dim size As Long
Erase b
len_s = Len(s)
If len_s = 0 Then _
Err.Raise 30030, , "Len(WideChars) = 0"
ptr_s = StrPtr(s)
size = WideCharToMultiByte(CP_UTF8, 0, ptr_s, len_s, 0, 0, 0, 0)
If size = 0 Then _
Err.Raise 30030, , "WideCharToMultiByte() = 0"
ReDim b(0 To size - 1)
If WideCharToMultiByte(CP_UTF8, 0, ptr_s, len_s, VarPtr(b(0)), size, 0, 0) = 0 Then _
Err.Raise 30030, , "WideCharToMultiByte(" & Format$(size) & ") = 0"
End Sub
Public Sub writeUtf()
Dim file As Integer
Dim s As String
Dim b() As Byte
s = "äöüßµ@€|~{}[]²³\ .." & _
" OMEGA" & ChrW$(937) & ", SIGMA" & ChrW$(931) & _
", alpha" & ChrW$(945) & ", beta" & ChrW$(946) & ", pi" & ChrW$(960) & vbCrLf
file = FreeFile
Open "C:\Temp\TestUtf8.txt" For Binary Access Write Lock Read Write As #file
getUtf8 s, b
Put #file, , b
Close #file
End Sub
Я посмотрел на ответ от Маны, чье имя намекает на квалификацию и опыт кодирования. Документы VBA говорят CreateTextFile(filename, [overwrite [, unicode]])
создает файл "как файл Unicode или ASCII. Значение True, если файл создан как файл Unicode; False, если он создан как файл ASCII. Если не указан, предполагается, что файл ASCII". Хорошо, что файл хранит символы Юникода, но в какой кодировке? Не закодированный Unicode не может быть представлен в файле.
Страница документа VBA для OpenTextFile(filename[, iomode[, create[, format]]])
предлагает третий вариант для формата:
- TriStateDefault 2 "открывает файл, используя систему по умолчанию".
- TriStateTrue 1 "открывает файл как Unicode."
- TriStateFalse 0 "открывает файл как ASCII."
Маня передает -1 за этот аргумент.
Судя по документации VB.NET (не VBA, но я думаю, что отражает реальность того, как базовая ОС Windows представляет строки Unicode и отражается в MS Office, я не знаю), система по умолчанию представляет собой кодировку с использованием символа 1 байта / Unicode с использованием ANSI кодовая страница для локали. UnicodeEncoding
это UTF-16. Документы также описывают, что UTF-8 также является "кодировкой Unicode", что имеет смысл для меня. Но я пока не знаю, как указать UTF-8 для вывода VBA, и не уверен, что данные, которые я записываю на диск с помощью OpenTextFile(,,,1), имеют кодировку UTF-16. Пост Тамалека полезен.
Я не хотел менять весь свой код только для поддержки нескольких строк UTF8, поэтому я позволил своему коду делать свое дело, и после того, как файл был сохранен (в коде ANSI, так как это значение по умолчанию для excel), я затем преобразовал файл в UTF-8, используя этот код:
Sub convertTxttoUTF(sInFilePath As String, sOutFilePath As String)
Dim objFS As Object
Dim iFile As Double
Dim sFileData As String
'Init
iFile = FreeFile
Open sInFilePath For Input As #iFile
sFileData = Input$(LOF(iFile), iFile)
sFileData = sFileData & vbCrLf
Close iFile
'Open & Write
Set objFS = CreateObject("ADODB.Stream")
objFS.Charset = "utf-8"
objFS.Open
objFS.WriteText sFileData
'Save & Close
objFS.SaveToFile sOutFilePath, 2 '2: Create Or Update
objFS.Close
'Completed
Application.StatusBar = "Completed"
End Sub
и я использую этот сабвуфер вот так (это пример):
Call convertTxttoUTF("c:\my.json", "c:\my-UTF8.json")
я нашел этот код здесь: VBA для изменения кодировки файлов ANSI на UTF8 - текст в Unicode
и поскольку это написано маркером BOM, чтобы удалить bom, я изменил Sub на это:
Sub convertTxttoUTF(sInFilePath As String, sOutFilePath As String)
Dim objStreamUTF8 As Object
Dim objStreamUTF8NoBOM As Object
Dim iFile As Double
Dim sFileData As String
Const adSaveCreateOverWrite = 2
Const adTypeBinary = 1
Const adTypeText = 2
'Init
iFile = FreeFile
Open sInFilePath For Input As #iFile
sFileData = Input(LOF(iFile), iFile)
Close iFile
'Open files
Set objStreamUTF8 = CreateObject("ADODB.Stream")
Set objStreamUTF8NoBOM = CreateObject("ADODB.Stream")
' wrute the fules
With objStreamUTF8
.Charset = "UTF-8"
.Open
.WriteText sFileData
.Position = 0
.SaveToFile sOutFilePath, adSaveCreateOverWrite
.Type = adTypeText
.Position = 3
End With
With objStreamUTF8NoBOM
.Type = adTypeBinary
.Open
objStreamUTF8.CopyTo objStreamUTF8NoBOM
.SaveToFile sOutFilePath, 2
End With
' close the files
objStreamUTF8.Close
objStreamUTF8NoBOM.Close
End Sub
я использовал этот ответ , чтобы решить неизвестный символ спецификации в начале файла
Традиционный способ преобразования строки в строку UTF-8 следующий:
StrConv("hello world",vbFromUnicode)
Проще говоря:
Dim fnum As Integer
fnum = FreeFile
Open "myfile.txt" For Output As fnum
Print #fnum, StrConv("special characters: äöüß", vbFromUnicode)
Close fnum
Никаких специальных COM-объектов не требуется