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

コメント