web-dev-qa-db-ja.com

BOMなしでUTF-8でExcelデータをエクスポートできますか?

Microsoft ExcelデータをExcelマクロ(VBScript)でエクスポートしています。ファイルはluaスクリプトなので、UTF-8としてエクスポートします。私がExcelでUTF-8を作ることができる唯一の方法は、このように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

Test.luaからBOMを削除したいのですが、方法がわかりません。 (Test.luaにはUnicodeテキストが含まれているため、UTF-8形式を使用する必要があります。)

ExcelファイルでBOMなしでUTF-8ファイルを作成する方法を知っていますか?前もって感謝します。

23
P-P

同じ問題もあります。Excel(Office 2003、VBA6.5)からUTF-8でエンコードされたファイルにデータをエクスポートする必要があります。あなたの質問から答えを見つけました!ブーストの(ありがとう!)回答からトリック#2を使用してBOMも削除する私の例の下に。私は#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ストリームオブジェクト参照 私が使用しました。

35
user272735

他の誰かがadTypeText定数で苦労している場合は、「ツール」->「参照」の下に「Microsoft ActiveXデータオブジェクト2.5オブジェクトライブラリ」を含める必要があります。

9
PhilHibbs

いくつかの可能性:

  1. テキストをUTF-8、Type = 2としてバッファーに入れますが、Type = 1(バイナリーとして)を設定し、それを書き出します。これは、BOMの追加をスキップするようにADODB.Streamを説得する可能性があります。

  2. タイプバイナリとして別のバッファを作成し、CopyToを使用して、BOMの後のポイントからそのバッファにデータをコピーします。

  3. Scripting.FileSystemObjectを使用してファイルを再度読み取り、BOMを切り取り、再度書き込みます

7
bugmagnet

編集

Rellampecからのコメントにより、LFを削除するより良い方法がuser272735のメソッドによってファイルの最後に追加されたことがわかりました。新しいバージョンのルーチンを最後に追加しました。

元の投稿

User272735のメソッドを1年間首尾よく使用していて、ファイルの最後に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

ルーチンの新しいバージョン

このバージョンでは、最初にLFを追加するのを回避するため、最後に追加された不要なLFを破棄するコードを省略しています。元のバージョンを末尾の文字を削除する手法に誰もが興味がある場合。

Public Sub PutTextFileUtf8NoBOM(ByVal PathFileName As String, ByVal FileBody As String)

  ' Outputs FileBody as a text file named PathFileName using
  ' UTF-8 encoding without leading BOM

  ' 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.
  ' 11Oct17  Posted to StackOverflow
  '  9Aug18  Comment from rellampec suggested removal of adWriteLine from
  '          WriteTest statement would avoid adding LF.
  ' 30Sep18  Amended routine to remove adWriteLine from WriteTest statement
  '          and code to remove LF from file. Successfully tested new version.

  ' 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"
  UTFStream.Open
  UTFStream.WriteText FileBody

  UTFStream.Position = 3 'skip BOM

  Set BinaryStream = CreateObject("adodb.stream")
  BinaryStream.Type = adTypeBinary
  BinaryStream.Mode = adModeReadWrite
  BinaryStream.Open

  UTFStream.CopyTo BinaryStream

  UTFStream.Flush
  UTFStream.Close
  Set UTFStream = Nothing

  BinaryStream.SaveToFile PathFileName, adSaveCreateOverWrite
  BinaryStream.Flush
  BinaryStream.Close
  Set BinaryStream = Nothing

End Sub
2
Tony Dallimore

これは、質問と重複する回答からの別のBOM廃棄ハックです。

遅い回答への謝罪-これはバイトオーダーマーカーに遭遇している他の人のための詳細です-この質問のページビューは、あなたの質問がいくつかの関連する問題に関連していることを教えてくれます:VBAでBOMフリーのファイルを書くのは驚くほど難しい-一般的なストリームライブラリの一部でも、要求したかどうかにかかわらず、出力にBOMを配置します。

以下のコードは少し異なる問題を解決しているため、私の答えは「オーバーラップ」と言います-主な目的は、異種のファイルコレクションを含むフォルダーのスキーマファイルを書き込むことですが、BOM削除およびBOMフリーファイルの実用的な例です書き込み 使用中で、関連するセグメントが明確にマークされています。

重要な機能は、フォルダー内のすべての「.csv」ファイルを反復処理し、最初の4バイトの短いニブルで各ファイルをテストすることです。マーカーを取り除くという面倒なタスクは、 1つ参照してください。

原始的なCの低レベルのファイル処理コードを使用しています。バイト配列を使用するまでは、 vBAで行う他のすべては、文字列変数の構造に埋め込まれたバイトオーダーマーカーを配置します

したがって、さらにadodbを使わずに、コードを次に示します。

Schema.iniファイル内のテキストファイルのBOM廃棄コード:

 Public Sub SetSchema(strFolder As String)
 On Error Resume Next 
'Schema.iniファイルをデータフォルダに書き込みます。 
'これは、IMEX = 1を上書きする '正しい 'ImportMixedTypes = Text'レジストリ値を設定するレジストリ権限がない場合に必要です。 
'このコードは、ANSIまたはUTF-8およびUTF-16ファイルもチェックし、恐ろしいハックでCharacterSet(UNICODE | ANSI)に '使用可能な設定を適用します。 
'OEMコードページ定義のテキストはサポートされていません。さらにコーディングが必要です 
'...そして、バイトオーダーマーカーが表示された場合、それらを取り除きます。テキストファイル用のOLEDB SQL 'プロバイダーは、UTF-16またはUTF-8のBOMを処理できませんファイル 
'実​​装されていません:タブ区切りファイルまたはその他の区切り文字を処理しています。 'コードは列のあるヘッダー行を想定し、「すべての行をスキャンする」を指定し、 」はデータ型が混在している場合は「列をテキストとして読み取る」ことを強制します。 
Dim strSchema As String Dim strFile As String Dim hndFile As Long Dim arrFile()As Byte Dim arrBytes(0 To 4)バイトとして 
If Right(strFolder、1)<> "\" Then strFolder = strFolder& "\" 
'Dir()は、ワイルドカードを使用して呼び出す場合の反復関数です。 
strFile = VBA.FileSystem.Dir(strFolder& "* .csv") 
Do While Len(strFile)> 0 
hndFile = FreeFile バイナリのstrFolder&strFileを#hndFile として開く#hndFile、、arrBytes を閉じる#hndFile 
strSchema = strSchema& "["&strFile& "]"&vbCrLf strSchema&strSchema& "Format = CSVDelimited"&vbCrLf strSchema = strSchema& "ImportMixedTypes = Text" &vbCrLf strSchema = strSchema& "MaxScanRows = 0"&vbCrLf 
If arrBytes(2)= 0 Or arrBytes(3)= 0 Then 'これはハックです strSchema = strSchema& "CharacterSet = UNICODE"&vbCrLf Else strSchema = strSchema& "CharacterSet = ANSI"&vbCrLf End If 
strSchema = strSchema& "ColNameHeader = True"&vbCrLf strSchema = strSchema&vbCrLf 
'******************************************** *************** 
'BOMの破棄-バイトオーダーマークにより、Access OLEDBテキストプロバイダーが壊れます。
if arrBytes(0)=&HFE And arrBytes(1)=&HFF _ またはarrBytes(0)=&HFF And arrBytes(1)=&HFE Then 
hndFile = FreeFile バイナリ用にstrFolderとstrFileを#hndFile として開くReDim arrFile(0 To LOF(hndFile)-1) Get #hndFile、、arrFile #hndFileを閉じる 
BigReplace arrFile、arrBytes(0)&arrBytes(1)、 "" 
hndFile = FreeFile バイナリのstrFolderとstrFileを#hndFile として開きます#hndFile、、arrFile を閉じます#hndFile を削除しますarrFileを消去します 
ElseIf arrBytes(0)=&HEF And arrBytes(1)=&HBB And arrBytes(2)=&HBF Then 
hndFile = FreeFile バイナリ用にstrFolderとstrFileを#hndFile として開くReDim arrFile(0 To LOF(hndFile)-1) Get #hndFile、、arrFile 閉じる#hndFile BigReplace arrFile、arrBytes(0)&arrBytes(1)&arrBytes(2)、 "" 
hndFile = FreeFile バイナリ用にstrFolderとstrFileを#hndFile として開きます#hndFile、、arrFile を閉じます#hndFile を削除しますarrFileを消去します 
終了する場合 
'******************************************** *************** 

strFile = "" strFile = Dir 
ループ 
If Len(strSchema)> 0 Then 
strFile = strFolder& "Schema.ini" 
hndFile = FreeFile #hndFile としてバイナリのstrFileを開く#hndFile、、strSchema Put #hndFile 
終了する場合 

End Sub 

Public Sub BigReplace(ByRef arrBytes()As Byte、_ ByRef SearchFor As String、_ ByRef ReplaceWith As String) On Error Resume Next 
Dim varSplit As Variant 
varSplit = Split(arrBytes、SearchFor) arrBytes = Join $(varSplit、ReplaceWith) 
varSplitを消去する 
サブを終了

バイト配列をVBA.Stringに割り当てることができ、その逆も可能であることがわかっている場合は、コードを理解しやすくなります。 BigReplace()関数は、VBAの非効率的な文字列処理、特に割り当ての一部を回避するハックです。他の方法で実行すると、大きなファイルはメモリとパフォーマンスの問題を引き起こすことがわかります。

0
Nigel Heffernan

外部コードではなくネイティブ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
0
Laurens