保存使用 VBA 编码的 UTF-8 文本文件

Save text file UTF-8 encoded with VBA

提问人:Karsten W. 提问时间:3/27/2010 最后编辑:Karsten W. 更新时间:11/14/2023 访问量:226625

问:

如何将 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

应用程序级别是否有一些设置?

VBA UTF-8

评论


答:

98赞 Karsten W. 3/27/2010 #1

在网上找到了答案:

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

当然不是我预料的......

评论

0赞 Smith 1/7/2011
您好,如果我想保存在 UTF-16 中怎么办,我只需要将 8 更改为 16 即可?
33赞 Karsten W. 1/10/2011
我不知道,你试过吗?
0赞 Johnny 4/28/2021
尝试了你的代码。保存文件内容:特殊字符:äöÃ1/4Ãÿ
0赞 user202729 10/5/2021
@Johnny 这可能是您的文本编辑器的问题。确保它以正确的编码打开文件(记事本在这方面尤其糟糕) _____________________________________________________________________________________________ 相关问题:取决于区域设置,您可能无法像这样将特殊字符放在字符串文本中。请参见 vba - 如何在 Visual Basic 编辑器中键入货币符号 - 堆栈溢出
0赞 Panagiotis Kanavos 1/12/2022
@Johnny您发布的内容正是使用 Latin1 加载 UTF8 时的样子。每个字符使用 1 个或多个字节保存。对于高于 US-ASCII 范围的字符,第一个字节如下所示Ã
10赞 PhilHibbs 7/21/2011 #2

这会在文件的开头写入一个字节顺序标记,这在 UTF-8 文件中是不必要的,并且某些应用程序(在我的情况下是 SAP)不喜欢它。 解决方案:我可以在没有 BOM 的情况下使用 UTF-8 导出 excel 数据吗?

评论

1赞 Mahmut K. 4/23/2023
这是标准 UTF-8 的最佳解决方案。Android Studio 无法正确读取我使用其他方法创建的 .xml 文件。
28赞 Máťa - Stitod.cz 4/11/2012 #3

您可以使用 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 文档上查看详细信息

评论

0赞 Karsten W. 7/13/2012
有趣。对象是类的,对吧?我将如何写入此文件? ?FileSystemObject.Write
1赞 danieltakeshi 10/31/2017
如果要使用 MAC 和 Windows,请搜索 Boost FileSystem for C++ 或其他库。
2赞 Mathias Z 6/16/2020
在尝试了几个设置后,当我使用:fso。CreateTextFile(fileName, True, True) 格式为 UTF-16 LE,当我将代码更改为 ;FSO。CreateTextFile(fileName, True, False) 格式为 UTF-8
9赞 Falo 11/28/2013 #4

这是执行此操作的另一种方法 - 使用 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
3赞 Bennett Brown 1/1/2016 #5

我研究了 Máťa 的答案,他的名字暗示了编码资格和经验。VBA文档说,创建一个文件“作为Unicode或ASCII文件。如果文件创建为 Unicode 文件,则该值为 True;如果创建为 ASCII 文件,则为 False。如果省略,则假定为 ASCII 文件。文件存储 unicode 字符很好,但以什么编码?未编码的 unicode 不能在文件中表示。CreateTextFile(filename, [overwrite [, unicode]])

VBA 文档页面为以下格式提供了第三个选项:OpenTextFile(filename[, iomode[, create[, format]]])

  • TriStateDefault 2“使用系统默认值打开文件”。
  • TriStateTrue 1“以 Unicode 格式打开文件”。
  • TriStateFalse 0 “以 ASCII 格式打开文件。”

Máťa 为此参数传递 -1。

VB.NET 文档来看(不是 VBA,但我认为反映了底层 Windows 操作系统如何表示 unicode 字符串并回显到 MS Office,我不知道)的现实,系统默认值是使用 1 字节/unicode 字符的编码,使用区域设置的 ANSI 代码页。 是 UTF-16。文档还描述了 UTF-8 也是一种“Unicode 编码”,这对我来说很有意义。但是我还不知道如何为 VBA 输出指定 UTF-8,也不确定我使用 OpenTextFile(,,,1) 写入磁盘的数据是 UTF-16 编码的。Tamalek 的帖子很有帮助。UnicodeEncoding

0赞 Sancarn 10/9/2020 #6

将字符串转换为 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 对象

评论

2赞 GSerg 11/17/2021
StrConv(vbFromUnicode)返回一个字节数组,该数组包含将给定的 Unicode 字符串(所有字符串在 VBA 中都是 Unicode)转换为非 Unicode 程序的当前系统代码页的结果。此时,字符串中不在该代码页上的“特殊字符”将丢失(并不是说您首先可以将它们包含在原始文本中,因为 VBA 代码编辑器不是 Unicode)。
2赞 GSerg 11/17/2021
然后,这个垃圾字节数组被传递给专为字符串设计的数组,因此认为传递的数据是常规的Unicode字符串,因此它再次将其“从Unicode”转换,从而从中删除一半的字符。生成的抽取垃圾将显示在文件中。上面显示的代码创建一个长度为 14 字节的文本文件,因为原始字符串文本包含 24 个字符。在上述所有内容中,“Unicode”的意思是“UTF-16”。UTF-8 不会以任何形状或形式进入场景。Print
0赞 Sancarn 11/17/2021
@GSerg返回到我的 Excel 版本中。不知道为什么它会回来找你?此外,在我的 Excel 版本中,结果是字符串本身字节数的一半,即它正在执行 --> 转换。这可以通过将结果设置为字节数组来确认TypeName(StrConv("hello world",vbFromUnicode))StringByte()StrConv(...,vbFromUnicode)UTF-16UTF-8Dim b() as byte: b = strconv(...,vbFromUnicode)
0赞 Sancarn 11/17/2021
@GSerg您还可以看到 StrConv 旨在从文档中返回一个字符串
3赞 GSerg 11/17/2021
它不执行 UTF-16 到 UTF-8 的转换,而是使用您当前的全局代码页执行 UTF-16 到 ASCII 的转换。UTF-8 不是“每个字符使用一个字节的编码”的同义词,因为 1) 有数百种不同的编码每个字符使用一个字节,以及 2) UTF-8 每个字符最多使用 4 个字节,具体取决于字符。将字符串字节分配给字节数组的能力也不是 UTF-8 的固有属性,因此不是使用 UTF-8 的标志。
1赞 Shaybc 6/16/2022 #7

我不想仅仅为了支持几个 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

我用这个答案解决了文件开头的BOM未知字符