1

I am trying to upload a csv, and it says BLOB is not a valid UTF-8 string.

public class ProductImportController{
    public Blob csvFileBody { get; set; }
    public String csvFileName { get; set; }

    public Boolean showResults { get; set; }
    public Boolean showImport { get; set; }
    public Boolean isUploading { get; set; }

    public List<Product2> prdctList { get; set; }
    public List<PricebookEntry> pbeListStandard  { get; set; }
    public List<PricebookEntry> pbeListCustom { get; set; }

    public ProductImportController(){
        //Show/hide sections
        showResults = false;
        showImport = true;
        isUploading = false;
    }

    public void upload(){

        if(isUploading){ return; }
        isUploading = true;

        //Show/hide sections
        showResults = true;
        showImport = false;

        try{
            parseCsvInsertProductsPricebooks();
        }catch(Exception e){
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, e.getMessage() ));

            //Show/hide sections
            showResults = false;
            showImport = true;
            isUploading = false;

            if(Test.isRunningTest()){
                throw e;
            }else{
                return;
            }
        }

        //Finished
        ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'Product import completed.'));
        isUploading = false;
    }

    public void parseCsvInsertProductsPricebooks(){

        if(csvFileBody == null){
            throw new ProductImportException('No CSV found.');
        }

        //Convert from blob to string
        String csvString = csvFileBody.toString();
        csvFileBody = null;
        csvFileName = null;

        if(String.isBlank(csvString)){
            throw new ProductImportException('Empty CSV found.');
        }

        //Parse CSV into separate fields
        List<List<String>> allFields = parseCSV(csvString);

        for(Integer i = 0; i < allFields.size(); i++){
            for(Integer j = 0; j < allFields.get(i).size(); j++){
                System.debug('* ** *** ' + i + '-' + j + ' : "' + allFields.get(i).get(j) + '"');
            }
        }

        if(allFields == null || allFields.isEmpty()){
            throw new ProductImportException('Empty CSV found.');
        }

        //Use first line as header
        List<String> headerFields = allFields.remove(0);
        List<HeaderWrapper> headerList = parseHeaders(headerFields);
        List<LineWrapper> lineList = new List<LineWrapper>();

        //Parse remaining lines
        if(allFields == null || allFields.isEmpty()){
            throw new ProductImportException('No rows found.');
        }else{
            for(List<String> line : allFields){
                lineList.add(new LineWrapper(line,headerList));
            }
        }

        //Get all products
        prdctList = new List<Product2>();
        for(LineWrapper line : lineList){
            prdctList.add(line.prdct);
        }

        //Insert products
        try{
            insert prdctList;
            System.debug(prdctList);
        }catch(Exception e){
            throw new ProductImportException('Could not insert products. ' + e.getMessage() ,e);
        } 


        //Insert standard pricebook entries
        pbeListStandard = new List<PricebookEntry>();
        for(LineWrapper line : lineList){
            List<PricebookEntry> l = line.getStandard();
            if(l != null){
                pbeListStandard.addAll(l);
            }
        }
        try{
            if(!pbeListStandard.isEmpty()){
                System.debug('* ** *** inserting standard pbe '  + pbeListStandard);
                insert pbeListStandard;
                System.debug(pbeListStandard);
            }
        }catch(Exception e){
            throw new ProductImportException('Could not insert pricebook entries. ' + e.getMessage() ,e);
        }

        //Insert custom pricebook entries
        pbeListCustom = new List<PricebookEntry>();
        for(LineWrapper line : lineList){
            List<PricebookEntry> l = line.getCustom();
            if(l != null && !l.isEmpty()){
                pbeListCustom.addAll(l);
            }
        }
        try{
            if(!pbeListCustom.isEmpty()){
                System.debug('* ** *** inserting custom pbe ' + pbeListCustom);
                insert pbeListCustom;
                System.debug(pbeListCustom);
            }
        }catch(Exception e){
            throw new ProductImportException('Could not insert pricebook entries. ' + e.getMessage(),e);
        }
    }
}
7
  • The Blob type only supports UTF-8 encoded string, ensure that the file you are uploading complies with this encoding, else you will get this error in cases where you have special characters.
    – Ashwani
    May 2, 2017 at 16:50
  • how do I know if it is a UTF-8, as per checking it looks like its normal csv file, how to diferrentiate it?
    – Sony PSP
    May 2, 2017 at 16:52
  • It should not contain any special characters.
    – Ashwani
    May 2, 2017 at 16:52
  • even dash? periods?
    – Sony PSP
    May 2, 2017 at 17:21
  • dash and periods are fine.
    – Ashwani
    May 2, 2017 at 17:22

1 Answer 1

2

UTF-8 only allows certain combinations of bytes, which means you can't (directly) convert binary files to strings in Apex Code. Based on my experience, I would say that you probably used Microsoft Excel, and saved the file in a way that resulted in the file name looking like "My Obviously CSV File.csv.xlsx" or something like that, which Windows "helpfully" hides extensions, so you end up seeing "My Obviously CSV File.csv", and presume it really is a CSV. I've done this more than once myself, so I know how easy it is to do so by accident.

To verify if that's what's going on, check the file's properties (right-click on the file, choose Properties), it should say that it is a "Microsoft Excel Comma Separated Values File (.csv)"; if it says anything else, odds are, it's in the wrong format. Also, CSV files in Windows should show a page with an X (for Excel) on one side, and "a," within the page. Also, if you open it in Microsoft Excel, and there's more than one worksheet, it is not a CSV file.

Finally, you could also try opening it Notepad (right-click the file, choose Open With... Other Programs... c:\windows\notepad.exe), or open Noteped, choose File > Open, choose "All Files (.)" and then open the file. A real CSV will be "readable", something like the following:

"Column 1","Column 2","Column 3"...
"Row 1 Cell 1","Row 1 Cell 2","Row 1 Cell 3"...

If you see "random" symbols that make no sense, then it's probably an XLS, XLSX, or other format.

6
  • however it says that this is a csv file. maybe there is problem in the code?
    – Sony PSP
    May 2, 2017 at 19:29
  • @SonyPSP Did you try opening the file in Notepad? What do you see?
    – sfdcfox
    May 2, 2017 at 19:38
  • I open it on notepad, it opens like product code, product name next line is ct-jd-v2s, software license-double
    – Sony PSP
    May 2, 2017 at 19:52
  • Hi I already found the culprit! its a symbol wherein can act as character as well
    – Sony PSP
    May 2, 2017 at 20:33
  • @SonyPSP It sounds like bad UTF-8 data, then. It shouldn't technically happen, but glitches do happen from time to time. I'm glad you found it. You might add a warning when the file won't convert using toString.
    – sfdcfox
    May 2, 2017 at 20:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.