Here is another way to do this — using the API function 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:TempTestUtf8.txt" For Binary Access Write Lock Read Write As #file
getUtf8 s, b
Put #file, , b
Close #file
End Sub
Функции ChangeFileCharset и ChangeTextCharset предназначены для изменения кодировки символов в текстовых файлах и строках.
Исходную и конечную (желаемую) кодировку можно задать в параметрах вызова функций.
ВНИМАНИЕ: Функции чтения и сохранения текста в файл в заданной кодировке
Список доступных на вашем компьютере кодировок можно найти в реестре Windows в ветке
HKEY_CLASSES_ROOTMIMEDatabaseCharset
Среди доступных кодировок есть koi8-r, ascii, utf-7, utf-8, Windows-1250, Windows-1251, Windows-1252, и т.д. и т.п.
Определить исходную и конечную кодировку можно, воспользовавшись онлайн-декодером:
http://www.artlebedev.ru/tools/decoder/advanced/
(после преобразования снизу будет написано, из какой кодировки в какую переведён текст)
Sub ПримерИспользования_ChangeTextCharset() ИсходнаяСтрока = "бНОПНЯ" ' вызываем функцию ChangeTextCharset с указанием кодировок ' (меняем кодировку с KOI8-R на Windows-1251) ПерекодированнаяСтрока = ChangeTextCharset(ИсходнаяСтрока, "Windows-1251", "KOI8-R") MsgBox "Результат перекодировки: """ & ПерекодированнаяСтрока & """", _ vbInformation, "Исходная строка: """ & ИсходнаяСтрока & """" End Sub
Function ChangeFileCharset(ByVal filename$, ByVal DestCharset$, _ Optional ByVal SourceCharset$) As Boolean ' функция перекодировки (смены кодировки) текстового файла ' В качестве параметров функция получает путь filename$ к текстовому файлу, ' и название кодировки DestCharset$ (в которую будет переведён файл) ' Функция возвращает TRUE, если перекодировка прошла успешно On Error Resume Next: Err.Clear With CreateObject("ADODB.Stream") .Type = 2 If Len(SourceCharset$) Then .Charset = SourceCharset$ ' указываем исходную кодировку .Open .LoadFromFile filename$ ' загружаем данные из файла FileContent$ = .ReadText ' считываем текст файла в переменную FileContent$ .Close .Charset = DestCharset$ ' назначаем новую кодировку .Open .WriteText FileContent$ .SaveToFile filename$, 2 ' сохраняем файл уже в новой кодировке .Close End With ChangeFileCharset = Err = 0 End Function
Function ChangeTextCharset(ByVal txt$, ByVal DestCharset$, _ Optional ByVal SourceCharset$) As String ' функция перекодировки (смены кодировки) текстовоq строки ' В качестве параметров функция получает текстовую строку txt$, ' и название кодировки DestCharset$ (в которую будет переведён текст) ' Функция возвращает текст в новой кодировке On Error Resume Next: Err.Clear With CreateObject("ADODB.Stream") .Type = 2: .Mode = 3 If Len(SourceCharset$) Then .Charset = SourceCharset$ ' указываем исходную кодировку .Open .WriteText txt$ .Position = 0 .Charset = DestCharset$ ' назначаем новую кодировку ChangeTextCharset = .ReadText .Close End With End Function
‘ Функция для перекодировки файла в UTF-8 без BOM (то же самое, что и UTF-8, только без первых 3 байтов)
Function ChangeFileCharset_UTF8noBOM(ByVal filename$, Optional ByVal SourceCharset$) As Boolean ' функция перекодировки (смены кодировки) текстового файла ' В качестве параметров функция получает путь filename$ к текстовому файлу, ' Функция возвращает TRUE, если перекодировка прошла успешно On Error Resume Next: Err.Clear DestCharset$ = "utf-8" With CreateObject("ADODB.Stream") .Type = 2 If Len(SourceCharset$) Then .Charset = SourceCharset$ ' указываем исходную кодировку .Open .LoadFromFile filename$ ' загружаем данные из файла FileContent$ = .ReadText ' считываем текст файла в переменную FileContent$ .Close .Charset = DestCharset$ ' назначаем новую кодировку "utf-8" .Open .WriteText FileContent$ 'Write your data into the stream. Dim binaryStream As Object Set binaryStream = CreateObject("ADODB.Stream") binaryStream.Type = 1 binaryStream.Mode = 3 binaryStream.Open 'Skip BOM bytes .Position = 3 .CopyTo binaryStream .Flush .Close binaryStream.SaveToFile filename$, 2 binaryStream.Close End With ChangeFileCharset_UTF8noBOM = Err = 0 End Function
Функция перекодировки текста в UTF-8 без BOM
Function EncodeUTF8noBOM(ByVal txt As String) As String For i = 1 To Len(txt) l = Mid(txt, i, 1) Select Case AscW(l) Case Is > 4095: t = Chr(AscW(l) 64 64 + 224) & Chr(AscW(l) 64) & Chr(8 * 16 + AscW(l) Mod 64) Case Is > 127: t = Chr(AscW(l) 64 + 192) & Chr(8 * 16 + AscW(l) Mod 64) Case Else: t = l End Select EncodeUTF8noBOM = EncodeUTF8noBOM & t Next End Function
- 144394 просмотра
Не получается применить макрос? Не удаётся изменить код под свои нужды?
Оформите заказ у нас на сайте, не забыв прикрепить примеры файлов, и описать, что и как должно работать.
So this was my initial question. The answer to my question below, seems to be that the only solution to get UTF-8 (and UTF-8 without BOM) encoding, is to use the ADODB.Stream object.
The answer to my new question in the subject line is posted as a code.
I am sitting here and trying to Save
an Excel sheet as a .CSV
-file with a VBA macro.
However, I am wondering if it matters whether I use ADODB
/ADODB.Stream
or just .SaveAs
Fileformat:=xlCSV
. I have tried to Google it, and it seems like I cannot find an answer to which method is the «best». I would need it to be comma delimited, UTF-8, and double quotations («») as text-identifier.
Is it correct that when you use Fileformat:=
, it is not possible to SaveAs
UTF-8, since the xlCSV
is not using that encoding?
YES, that is correct.
See my answer for the solution.
asked Apr 6, 2015 at 8:50
NiclasNiclas
1,0593 gold badges18 silver badges32 bronze badges
4
thank you for posting this question and also the solution. It helped me a lot.
Yes, I also found that SaveAs does not save the CSV file in UTF8. In my case it uses shift-JIS. The adodb.stream worked well for me.
However, I am not sure why but I had to declare some constants (enum) you used in the code. (I am really new to VBA so maybe I missed something about why this happens). I added this in the beginning of the function, then it worked perfectly:
Const adTypeText = 2
Const adModeReadWrite = 3
Const adTypeBinary = 1
Const adLF = 10
Const adSaveCreateOverWrite = 2
Const adWriteLine = 1
I got the value from Microsoft docs.
Once again, thanks!
answered Mar 21, 2018 at 1:24
Leonard ABLeonard AB
1,4191 gold badge17 silver badges29 bronze badges
3
So I came in the situation where I needed this code again, and I read the comments and Leonard’s answer, which made me update my code together with better descriptions.
This code will convert your Excel sheet and save it as a CSV file with the UTF-8 without BOM encoding. I found this code on a website, so I will not take credit for it. CSV without BOM link
Option Explicit
Sub CSVFileAsUTF8WithoutBOM()
Dim SrcRange As Range
Dim CurrRow As Range
Dim CurrCell As Range
Dim CurrTextStr As String
Dim ListSep As String
Dim FName As Variant
Dim UTFStream As Object
Dim BinaryStream As Object
' ADO Constants
Const adTypeBinary = 1 ' The stream contains binary data
Const adTypeText = 2 ' The stream contains text data (default)
Const adWriteLine = 1 ' write text string and a line separator (as defined by the LineSeparator property) to the stream.
Const adModeReadWrite = 3 ' Read/write
Const adLF = 10 ' Line feed only - default is carriage return line feed (adCRLF)
Const adSaveCreateOverWrite = 2 ' Overwrites the file with the data from the currently open Stream object, if the file already exists
' Open this workbook location
ChDrive Left(ThisWorkbook.Path, 1)
ChDir ThisWorkbook.Path
' ask for file name and path
FName = Application.GetSaveAsFilename("", "CSV File (*.csv), *.csv")
' prepare UTF-8 stream
Set UTFStream = CreateObject("adodb.stream")
UTFStream.Type = adTypeText
UTFStream.Mode = adModeReadWrite
UTFStream.Charset = "UTF-8"
UTFStream.LineSeparator = adLF
UTFStream.Open
'set field separator
ListSep = ";"
'set source range with data for csv file
If Selection.Cells.Count > 1 Then
Set SrcRange = Selection
Else
Set SrcRange = ActiveSheet.UsedRange
End If
For Each CurrRow In SrcRange.Rows
'enclose each value with quotation marks and escape quotation marks in values
CurrTextStr = ""
For Each CurrCell In CurrRow.Cells
CurrTextStr = CurrTextStr & """" & Replace(CurrCell.Value, """", """""") & """" & ListSep
Next
'remove ListSep after the last value in line
While Right(CurrTextStr, 1) = ListSep
CurrTextStr = Left(CurrTextStr, Len(CurrTextStr) - 1)
Wend
'add line to UTFStream
UTFStream.WriteText CurrTextStr, adWriteLine ' Writes character data to a text Stream object
Next
'skip BOM
UTFStream.Position = 3 ' sets or returns a long value that indicates the current position (in bytes) from the beginning of a Stream object
'copy UTFStream to BinaryStream
Set BinaryStream = CreateObject("adodb.stream")
BinaryStream.Type = adTypeBinary
BinaryStream.Mode = adModeReadWrite
BinaryStream.Open ' Opens a Stream object
'Strips BOM (first 3 bytes)
UTFStream.CopyTo BinaryStream ' Copies a specified number of characters/bytes from one Stream object into another Stream object
UTFStream.Flush ' Sends the contents of the Stream buffer to the associated underlying object
UTFStream.Close ' Closes a Stream object
'save to file
BinaryStream.SaveToFile FName, adSaveCreateOverWrite
BinaryStream.Flush ' Sends the contents of the Stream buffer to the associated underlying object
BinaryStream.Close ' Closes a Stream object
End Sub
answered Apr 2, 2020 at 21:43
NiclasNiclas
1,0593 gold badges18 silver badges32 bronze badges
Sub CallKML(control As IRibbonControl) Dim i As Integer Dim fn As Long Dim npg As Integer If ActiveSheet.Name = "Вуличні ПГ" Then wnet = "Вуличні ПГ" If ActiveSheet.Name = "Об'єктові ПГ" Then wnet = "Об'єктові ПГ" fn = FreeFile Open ThisWorkbook.Path & "ResultExcel.kml" For Output As fn Print #fn, "<?xml version='1.0' encoding='UTF-8'?>" Print #fn, "<kml xmlns='http://www.opengis.net/kml/2.2'>" Print #fn, "<Document>" Print #fn, "<Style id=""placemark-blue"">" Print #fn, "<IconStyle>" Print #fn, "<Icon>" Print #fn, "<href>images/1.png</href>" Print #fn, "</Icon>" Print #fn, "<hotSpot x='0.5' y='0.5' xunits='fraction' yunits='fraction'/>" Print #fn, "</IconStyle>" Print #fn, "<LabelStyle><color>ff000000</color><scale>0.5</scale><face>Arial</face><visible>1</visible><style>00000000</style></LabelStyle>" Print #fn, "</Style>" Print #fn, "<Style id=""placemark-red"">" Print #fn, "<IconStyle>" Print #fn, "<Icon>" Print #fn, "<href>images/2.png</href>" Print #fn, "</Icon>" Print #fn, "<hotSpot x='0.5' y='0.5' xunits='fraction' yunits='fraction'/>" Print #fn, "</IconStyle>" Print #fn, "<LabelStyle><color>ff000000</color><scale>0.5</scale><face>Arial</face><visible>1</visible><style>00000000</style></LabelStyle>" Print #fn, "</Style>" Print #fn, "<Style id=""placemark-orange"">" Print #fn, "<IconStyle>" Print #fn, "<Icon>" Print #fn, "<href>images/3.png</href>" Print #fn, "</Icon>" Print #fn, "<hotSpot x='0.5' y='0.5' xunits='fraction' yunits='fraction'/>" Print #fn, "</IconStyle>" Print #fn, "<LabelStyle><color>ff000000</color><scale>0.5</scale><face>Arial</face><visible>1</visible><style>00000000</style></LabelStyle>" Print #fn, "</Style>" npg = 0 For i = 2 To 1001 If ActiveSheet.Cells(i, 2) <> "" Then npg = npg + 1 Print #fn, "<Placemark>" If wnet = "Вуличні ПГ" Then Print #fn, "<description>" & "Вуличні ПГ" & "</description>" If wnet = "Об'єктові ПГ" Then Print #fn, "<description>" & "Об'єктові ПГ" & "</description>" Print #fn, "<name>" & ActiveSheet.Cells(i, 2) & "</name>" If ActiveSheet.Cells(i, 3) = "Справний" Then Print #fn, "<styleUrl>#placemark-blue</styleUrl>" If ActiveSheet.Cells(i, 3) = "Несправний" Then Print #fn, "<styleUrl>#placemark-red</styleUrl>" Print #fn, "<ExtendedData> " Print #fn, "<Data name='Вулиця'> <value>" & ActiveSheet.Cells(i, 1) & "</value> </Data>" Print #fn, "<Data name='Технічний стан'> <value>" & ActiveSheet.Cells(i, 3) & "</value> </Data>" Print #fn, "<Data name='Характер несправності'> <value>" & ActiveSheet.Cells(i, 4) & "</value> </Data>" Print #fn, "<Data name='Належність'> <value>" & ActiveSheet.Cells(i, 5) & "</value> </Data>" Print #fn, "<Data name='Примітка'> <value>" & ActiveSheet.Cells(i, 8) & "</value> </Data>" If ActiveSheet.Cells(i, 9) <> "" Then Print #fn, "<Data name='gx_media_links'> <value>" & ActiveSheet.Cells(i, 9) & "</value> </Data>" Print #fn, "</ExtendedData> " Print #fn, "<Point> <coordinates>" & ActiveSheet.Cells(i, 7); "," & ActiveSheet.Cells(i, 6) & ",0.0</coordinates> </Point>" Print #fn, "</Placemark>" End If Next i Print #fn, "</Document>" Print #fn, "</kml>" Close fn ChangeFileCharset Filename$, "utf-8" MsgBox "Експорт таблиці в kml завершено" End Sub Function ChangeFileCharset(ByVal Filename$, ByVal DestCharset$, _ Optional ByVal SourceCharset$) As Boolean On Error Resume Next: Err.Clear With CreateObject("ADODB.Stream") .Type = 2 If Len(SourceCharset$) Then .Charset = "Windows-1251" .Open .LoadFromFile "ResultExcel.kml" FileContent$ = .ReadText .Close .Charset = "utf-8" .Open .WriteText FileContent$ .SaveToFile "ResultExcel.kml", 2 .Close End With ChangeFileCharset = Err = 0 End Function
Сохранение файла в Юникод UTF-8 |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |
||||||||
Ответить |