Introduction

This article is showing one of the ways to efficiently reading a CSV/Flat Files using Apex code without breaking the character encoding.

Read from Content Version

String contentDocId = '0690D000000cQVVQA2';
List<ContentVersion> cvList =  [SELECT Title, VersionData, FileExtension FROM ContentVersion WHERE ContentDocumentId =: contentDocId];
String csvFileData = cv.VersionData;

Apply character encoding

String charset = 'ISO-8859-1';
Blob input = Blob.valueOf(csvFileData );
String hex = EncodingUtil.convertToHex(input);
Integer size = hex.length() >> 1;
List<String> bytes = new String[size];
for (Integer i = 0; i < size; ++i) {
    bytes.set(i, hex.mid(i << 1, 2));
}
String csvData = EncodingUtil.urlDecode('%' + String.join(bytes, '%'), charset);

Read data line by line

String[] rows = csvData.split('\n');
String[] columnNames = rows[0].split(',');
for(String row:rows){
    List<String> values = getCsvLineValue(row);
    for(String value:values){
        try{
            colValue=fields[i].replaceAll(':quotes:', '').replaceAll(':comma:', ',').trim();
        }catch(ListException le){
            continue;
        }
    }
}

public static List<String> getCsvLineValue(String csvLine){
    String prevLine = csvLine;
    Integer startIndex;
    Integer endIndex;
    while(csvLine.indexOf('"') > -1){
        if(startIndex == null){
            startIndex = csvLine.indexOf('"');
            csvLine = csvLine.substring(0, startIndex) + ':quotes:' + csvLine.substring(startIndex+1, csvLine.length());
        }
        else{
            if(endIndex == null){
                endIndex = csvLine.indexOf('"');
                csvLine = csvLine.substring(0, endIndex) + ':quotes:' + csvLine.substring(endIndex+1, csvLine.length());
            }
        }
        if(startIndex != null && endIndex != null){
            String sub = csvLine.substring(startIndex, endIndex);
            sub = sub.replaceAll(',', ':comma:');
            csvLine = csvLine.substring(0, startIndex) + sub + csvLine.substring(endIndex, csvLine.length());
            startIndex = null;
            endIndex = null;
        }
    }
    return csvLine.split(',');
}

CSV Upload Reusable Pack

We have created a re-usable package for handling csv uploads with duplicate checking and reporting errors and also the duplicates found.

You can learn or explore the package at below url:

Use Case

This customization can be used where you want to give your consumers/community users ability to upload their contacts or record in Salesforce as internal users can always use the Data Loader.