Могу ли я экспортировать данные Excel с UTF-8 без спецификации?
Я экспортирую данные Microsoft Excel с помощью Excel Macro (VBScript).
Поскольку файл lua script, я экспортирую его как UTF-8.
Единственный способ сделать UTF-8 в Excel - использовать adodb.stream, как этот
set fileLua = CreateObject("adodb.stream")
fileLua.Type = 2
fileLua.Mode = 3
fileLua.Charset = "UTF-8"
fileLua.Open
fileLua.WriteText("test")
fileLua.SaveToFile("Test.lua")
fileLua.flush
fileLua.Close
Я хочу исключить BOM из Test.lua, но я не знаю, как это сделать.
(Поскольку у Test.lua есть некоторый текст в Юникоде, я должен использовать формат UTF-8.)
Вы знаете, как сделать файл UTF-8 без спецификации в файле excel?
Спасибо заранее.
Ответы
Ответ 1
У меня также та же проблема: нужно экспортировать данные из Excel (Office 2003, VBA6.5) в кодированный файл UTF-8. Нашел ответ на ваш вопрос! Ниже моего примера, где я также снимаю спецификацию с помощью трюка №2 от ответа boost (thanks!). Я не работал # 1 и никогда не пробовал # 3.
Sub WriteUTF8WithoutBOM()
Dim UTFStream As Object
Set UTFStream = CreateObject("adodb.stream")
UTFStream.Type = adTypeText
UTFStream.Mode = adModeReadWrite
UTFStream.Charset = "UTF-8"
UTFStream.LineSeparator = adLF
UTFStream.Open
UTFStream.WriteText "This is an unicode/UTF-8 test.", adWriteLine
UTFStream.WriteText "First set of special characters: öäåñüûú€", adWriteLine
UTFStream.WriteText "Second set of special characters: qwertzuiopõúasdfghjkléáûyxcvbnm\|Ä€Í÷×äðÐ[]í³£;?¤>#&@{}<;>*~¡^¢°²`ÿ´½¨¸0", adWriteLine
UTFStream.Position = 3 'skip BOM
Dim BinaryStream As Object
Set BinaryStream = CreateObject("adodb.stream")
BinaryStream.Type = adTypeBinary
BinaryStream.Mode = adModeReadWrite
BinaryStream.Open
'Strips BOM (first 3 bytes)
UTFStream.CopyTo BinaryStream
'UTFStream.SaveToFile "d:\adodb-stream1.txt", adSaveCreateOverWrite
UTFStream.Flush
UTFStream.Close
BinaryStream.SaveToFile "d:\adodb-stream2.txt", adSaveCreateOverWrite
BinaryStream.Flush
BinaryStream.Close
End Sub
Ссылка ADO Stream Object, которую я использовал.
Ответ 2
Несколько возможностей:
-
Поместите текст в буфер как UTF-8, Type = 2, но затем установите Type = 1 (как двоичный) и запишите это. Это может убедить ADODB.Stream пропустить добавление спецификации.
-
Создайте еще один буфер, как тип двоичный, и используйте CopyTo для копирования данных в этот буфер из точки после спецификации.
-
Снова прочитайте файл, используя Scripting.FileSystemObject, обрезайте спецификацию, снова выпишите
Ответ 3
Если кто-то еще борется с константой adTypeText, вам нужно включить "Объектная библиотека объектов Microsoft ActiveX 2.5" в разделе "Инструменты- > Ссылки".
Ответ 4
Если вы предпочитаете собственный T-SQL вместо внешнего кода
DECLARE @FILE_NAME VARCHAR(255) = 'd:\utils\test.xml' --drive:\path\filename\
DECLARE @FILE_DATA VARCHAR(MAX) = '<?xml version="1.0" encoding="UTF-8"?>test</xml>' --binary as varchar(max)
DECLARE @FILE_NAME_TO VARCHAR(255) --Temp name for text stream
DECLARE @FSO_ID_TXTSTRM INT --Text Stream
DECLARE @FSO_ID_BINSTRM INT --Binary Stream
DECLARE @RC INT
EXEC @RC = sp_OACreate 'ADODB.Stream', @FSO_ID_TXTSTRM OUTPUT
EXEC @RC = sp_OASetProperty @FSO_ID_TXTSTRM, 'Type', 2 --1 = binary, 2 = text
EXEC @RC = sp_OASetProperty @FSO_ID_TXTSTRM, 'Mode', 3 --0 = not set, 1 read, 2 write, 3 read/write
EXEC @RC = sp_OASetProperty @FSO_ID_TXTSTRM, 'Charset', 'UTF-8' --'ISO-8859-1'
EXEC @RC = sp_OASetProperty @FSO_ID_TXTSTRM, 'LineSeparator', 'adLF'
EXEC @RC = sp_OAMethod @FSO_ID_TXTSTRM, 'Open'
EXEC @RC = sp_OAMethod @FSO_ID_TXTSTRM, 'WriteText', NULL, @FILE_DATA --text method
--Create binary stream
EXEC @RC = sp_OACreate 'ADODB.Stream', @FSO_ID_BINSTRM OUTPUT
EXEC @RC = sp_OASetProperty @FSO_ID_BINSTRM, 'Type', 1 --1 = binary, 2 = text
EXEC @RC = sp_OAMethod @FSO_ID_BINSTRM, 'Open'
EXEC @RC = sp_OASetProperty @FSO_ID_BINSTRM, 'Mode', 3 --0 = not set, 1 read, 2 write, 3 read/write
--Move 3 positions forward in text stream (BOM is first 3 positions)
EXEC @RC = sp_OASetProperty @FSO_ID_TXTSTRM, 'Position', 3
--Copy text stream to binary stream
EXEC @RC = sp_OAMethod @FSO_ID_TXTSTRM, 'CopyTo', NULL, @FSO_ID_BINSTRM
--Commit data and close text stream
EXEC @RC = sp_OAMethod @FSO_ID_TXTSTRM, 'Flush'
EXEC @RC = sp_OAMethod @FSO_ID_TXTSTRM, 'Close'
EXEC @RC = sp_OADestroy @FSO_ID_TXTSTRM
--Save binary stream to file and close
EXEC @RC = sp_OAMethod @FSO_ID_BINSTRM, 'SaveToFile', NULL, @FILE_NAME, 2 --1 = notexist 2 = overwrite
EXEC @RC = sp_OAMethod @FSO_ID_BINSTRM, 'Close'
EXEC @RC = sp_OADestroy @FSO_ID_BINSTRM
Ответ 5
Здесь другой BOM-утилита взлома, из ответа, который перекрывает ваш вопрос.
Извинения за поздний ответ - это больше для других людей, которые сталкиваются с маркерами байтового порядка, и просмотры страниц по этому вопросу говорят мне, что ваш вопрос имеет отношение к нескольким связанным проблемам: на удивление сложно написать BOM-Free файл в VBA - даже некоторые из библиотек общих потоков делят спецификацию на вашем выходе, независимо от того, вы ее просили или нет.
Я говорю, что мой ответ "перекрывается", потому что приведенный ниже код решает немного другую проблему - основная цель - писать файл схемы для папки с гетерогенной коллекцией файлов, но это рабочий пример BOM-удаления и спецификации - использование свободной записи в использовании, и соответствующий сегмент четко обозначен.
Ключевая функциональность заключается в том, что мы перебираем все файлы ".csv" в папке, и мы тестируем каждый файл с быстрым полубайтом первых четырех байтов: и мы только берем на себя всю тяжёлую задачу по удалению если мы его увидим.
Мы работаем с низкоуровневым кодом обработки файлов из первичного C. Мы должны, вплоть до использования байтовых массивов, потому что все остальное, что вы делаете в VBA, будет откладывать маркеры байтового байта встроенный в структуру строковой переменной.
Итак, без дальнейшего adodb, здесь код:
BOM-Код удаления текстовых файлов в файле schema.ini:
Public Sub SetSchema (strFolder As String)
При ошибке Продолжить дальше
"Это необходимо, если у нас нет привилегий реестра для установки
'correct' ImportMixedTypes = Text 'значение реестра, которое переопределяет IMEX = 1
"Код, определенный кодовой страницей OEM, не поддерживается: требуется дополнительное кодирование
Dim strSchema As String
Dim strFile As String
Dim hndFile As Long
Dim arrFile() как байт
Dim arrBytes (от 0 до 4) В качестве байта
"\" Затем strFolder = strFolder и "\"
0
hndFile = FreeFile Открыть strFolder и strFile для двоичных файлов как #hndFile ReDim arrFile (0 К LOF (hndFile) - 1) Получить #hndFile, arrFile Закрыть #hndFile
0, то
Код легче понять, если вы знаете, что байт-массив можно назначить VBA.String и наоборот. Функция BigReplace() - это взлом, который оборачивает некоторые из неэффективной обработки строк VBA, особенно распределение: вы обнаружите, что большие файлы вызывают серьезные проблемы с памятью и производительностью, если вы сделаете это любым другим способом.
Ответ 6
Я успешно использовал метод user272735 в течение года, когда обнаружил, что он добавил LF в конце файла. Я не заметил этого дополнительного LF, пока не сделал очень подробное тестирование, поэтому это не является важной ошибкой. Тем не менее, моя последняя версия отбрасывает этот LF на случай, если это когда-либо станет важным.
Public Sub PutTextFileUtf8(ByVal PathFileName As String, ByVal FileBody As String)
' Outputs FileBody as a text file (UTF-8 encoding without leading BOM)
' named PathFileName
' Needs reference to "Microsoft ActiveX Data Objects n.n Library"
' Addition to original code says version 2.5. Tested with version 6.1.
' 1Nov16 Copied from http://stackoverflow.com/a/4461250/973283
' but replaced literals with parameters.
' 15Aug17 Discovered routine was adding an LF to the end of the file.
' Added code to discard that LF.
' References: http://stackoverflow.com/a/4461250/973283
' https://www.w3schools.com/asp/ado_ref_stream.asp
Dim BinaryStream As Object
Dim UTFStream As Object
Set UTFStream = CreateObject("adodb.stream")
UTFStream.Type = adTypeText
UTFStream.Mode = adModeReadWrite
UTFStream.Charset = "UTF-8"
' The LineSeparator will be added to the end of FileBody. It is possible
' to select a different value for LineSeparator but I can find nothing to
' suggest it is possible to not add anything to the end of FileBody
UTFStream.LineSeparator = adLF
UTFStream.Open
UTFStream.WriteText FileBody, adWriteLine
UTFStream.Position = 3 'skip BOM
Set BinaryStream = CreateObject("adodb.stream")
BinaryStream.Type = adTypeBinary
BinaryStream.Mode = adModeReadWrite
BinaryStream.Open
UTFStream.CopyTo BinaryStream
' Oriinally I planned to use "CopyTo Dest, NumChars" to not copy the last
' byte. However, NumChars is described as an integer whereas Position is
' described as Long. I was concerned by "integer" they mean 16 bits.
'Debug.Print BinaryStream.Position
BinaryStream.Position = BinaryStream.Position - 1
BinaryStream.SetEOS
'Debug.Print BinaryStream.Position
UTFStream.Flush
UTFStream.Close
Set UTFStream = Nothing
BinaryStream.SaveToFile PathFileName, adSaveCreateOverWrite
BinaryStream.Flush
BinaryStream.Close
Set BinaryStream = Nothing
End Sub