Подтвердить что ты не робот

Могу ли я экспортировать данные 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? Спасибо заранее.

4b9b3361

Ответ 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