Save Excel Sheet as UTF-8 CSV file
The biggest problem of Excel is that Excel does not support saving file as UTF-8 CSV format.
I have googled and tried to find the solution for saving excel as UTF-8 CSV but all of them requires 2 steps - 1) saving Excel file as Unicode csv 2) Open it by text editor and save it again as UTF-8 CSV.
If you are a software developer, it is easy to write Java or C# program to manipulate Excel.
But it means people (non developer users) need to install or launch the application.
So I have wrriten Excel VBA addin for saving Excel sheet as UTF-8 CSV file so that we can save UTF-8 excel files only using Excel.
Code for saving UTF-8 CSV
Okie!, here is my solution!
Sme notes for the code:
- The code saves an active sheet to UTF-8 CSV file in temp folder.
- The error handring part is not robust. I have only wrriten minimum error handling. You might need to add your custome error handring.
- If you are okay to add BOM on the file, please remove the corresponding part for adding BOM.
Sub SaveAsCSV() On Error GoTo ErrorHandler Const ROW_LIMIT As Long = 1000 Const OUTPUT_DIR = "C:\temp\" '============================== ' Get Range '============================== Dim maxRow As Long Dim maxCol As Long If ActiveSheet Is Nothing Then MsgBox "Sheet Not Found!", vbExclamation Exit Sub End If With ActiveSheet.UsedRange maxRow = .Rows.Count maxCol = .Columns.Count End With If maxRow < 2 Then MsgBox "Data is Empty!", vbExclamation Exit Sub End If Dim fileIndex As Long: fileIndex = 1 '============================== ' Prepare stream '============================== Dim outStream As ADODB.Stream '============================== ' Write data to stream '============================== Dim r As Long Dim c As Long Dim line As String Dim Data As Variant Dim shop As String Dim header As String Dim isFileOutput As Boolean: isFileOutput = False Dim isNewFile As Boolean: isNewFile = True With ActiveSheet Data = .Range("A1:" & Col_Letter(maxCol) & .Range("A1").End(xlDown).Row) End With '============================== ' Write header row '============================== header = """" & Data(1, 1) & """" For c = 2 To maxCol If Data(1, c) = "" Then header = header & "," & """""" Else header = header & ",""" & Replace(Trim(Data(1, c)), """", """""") & """" End If Next Dim baseName As String: baseName = GetBaseFileName() '============================== ' Write data rows '============================== For r = 2 To maxRow Application.StatusBar = String(Int(r / 1000), "*") If isNewFile Then ' create new out stream for next file Set outStream = New ADODB.Stream With outStream .Charset = "UTF-8" .Type = 2 'adTypeText .Open End With outStream.WriteText header, adWriteLine isNewFile = False End If ' Data line ' 1st column line = """" & Data(r, 1) & """" ' after 1st column For c = 2 To maxCol If Data(r, c) = "" Then line = line & "," & """""" Else line = line & ",""" & Replace(Trim(Data(r, c)), """", """""") & """" End If Next outStream.WriteText line, adWriteLine ' File output isFileOutput = (r Mod ROW_LIMIT = 0 Or r = maxRow) If isFileOutput Then ' Skip BOM With outStream .Position = 0 .Type = 1 'adTypeBinary .Position = 3 'skip 3 byte in order to remive BOM End With ' stream for copy Dim csvStream As ADODB.Stream Set csvStream = New ADODB.Stream ' open binary mode csvStream.Type = adTypeBinary csvStream.Open ' copy data after BOM outStream.CopyTo csvStream csvStream.SaveToFile (OUTPUT_DIR & baseName & "_" & fileIndex & ".csv"), adSaveCreateOverWrite outStream.Close fileIndex = fileIndex + 1 isNewFile = True End If Next Application.StatusBar = False MsgBox "Output " & fileIndex - 1 & " csv files on " & vbCrLf & OUTPUT_DIR & " from " & ActiveSheet.Name & " in " & Application.ActiveWorkbook.Name, vbInformation, "Csv Output" Exit Sub ErrorHandler: Application.StatusBar = False MsgBox "Error Details:" & Err.Description, vbCritical, "Error" End Sub Private Function Col_Letter(lngCol As Long) As String Dim vArr: vArr = Split(Cells(1, lngCol).Address(True, False), "$") Col_Letter = vArr(0) End Function Private Function GetBaseFileName() Dim extIndex As Integer: extIndex = InStrRev(Application.ActiveWorkbook.Name, ".") If extIndex > 0 Then GetBaseFileName = Left(Application.ActiveWorkbook.Name, extIndex - 1) Else GetBaseFileName = Application.ActiveWorkbook.Name End If End Function
Adding the Funtionality to Menu
If you would like to add this functionality to Excel, you need to create menu which executes the UTF-8 to csv macro and add it to Excel menu.
- Create a standard Excel VBA module in VBA editor.
- Copy and paste the above main VBA code (SaveAsCSV funciton etc.) to the module created in the previous step.
- Also add the folliwng code which adds custom menu to Excel
Sub AddNewMenu() On Error GoTo ErrHand Dim cbrCmd As CommandBar Dim cbcMenu As CommandBarControl 'Create menu Set cbrCmd = Application.CommandBars("Worksheet Menu Bar") 'Delete menu if it already exists cbrCmd.Controls("UTF-8 CSV").Delete 'Add menu Set cbcMenu = cbrCmd.Controls.Add(Type:=msoControlPopup) cbcMenu.Caption = "UTF-8 CSV" cbcMenu.Tag = "UTF-8 CSV" With cbcMenu.Controls.Add(Type:=msoControlButton) .Caption = " UTF-8 CSV" .OnAction = "SaveAsCSV" .FaceId = 3 End With Set cbrCmd = Nothing Set cbcMenu = Nothing Exit Sub ErrHand: If Err.Number = 5 Then Resume Next Else MsgBox Err.Description End If End Sub
Option Explicit Private Sub Workbook_Open() Call AddNewMenu End Sub
コメント