Creating CSV files in Salesforce from Apex

Author: Bruce Tollefson Published: January 15, 2022; Modified: May 9, 2022
database

Whether looking through Developer Console or wanting a process/trigger to create a file here are a few quick methods that can be used to create a CSV or generic file from Apex. This is to show a few quick methods that can be used to create a CSV from Apex however they could be modified for other types of files, CSV seems to be the most common I have needed. The following used an overloaded method with several different parameters for a variety of inputs.

Creating the file

The following will be the main method that is used to create a generic file that can be used in conjunction with other methods to create different types of files or on its own:

/** @description create a file - generic */ public static void createFile(String versionData, String title) { ContentVersion cv = new ContentVersion(); cv.ContentLocation = 'S'; //denotes it resides on Salesforce cv.Title = title; //title of the file cv.PathOnClient = title; // full path within Salesforce this can just be the name of file to be in the library cv.VersionData = Blob.valueOf(versionData); //file data insert cv; }

The above creates a Content Version marks it as a file in Salesforce, places it in Files, and then inserts the content version. This is used with the rest of the methods to create the files. Below will create a CSV from a list of strings.

CSV from List of Strings

If you have a list of strings (remember each comma in the string will separate to the next cell) below will iterator through the list and create the CSV.

/** @description create a CSV file from a list of Strings each string should be a row */ public static void createCSV(List<String> csvHeaders, List<String> csvRowList, String title){ String headerRow = String.join(csvHeaders,',') + '\n'; String concantenatedStr = headerRow; Integer i = 0; Integer rowListSize = csvRowList.size(); //assuming the rowList is in the correct format and each object in the list is a new record for(String row :csvRowList){ i++; concantenatedStr += (String)row + ((i != rowListSize) ? '\n' : '');//add new line } title += '.csv'; createFile(concantenatedStr, title); }

CSV from List of Object List

Let’s say you need more control when building your CSV file from Apex and instead of building the list as a string you want to use output based on each cell. As an example a bunch of Integer values. Below uses a list of list objects each object in the list is a cell and each list of lists is a row.

/** @description create a CSV file from a list of Object Lists each Object List is a row in a list of lists. Each Object is a cell in the CSV */ public static void createCSV(List<String> csvHeaders, List<List<Object>> csvRowList, String title){ String headerRow = String.join(csvHeaders,',') + '\n'; String concantenatedStr = headerRow; Integer i = 0; Integer rowListSize = csvRowList.size(); for(List<Object> row :csvRowList){ if(csvHeaders.size() != row.size()) throw new FileMakerException('The row size needs to be the same size as the header');//check the row list is the same size as the header list concantenatedStr += String.join(row, ','); i++; if(i != rowListSize) concantenatedStr += '\n';//add new line } title += '.csv'; createFile(concantenatedStr, title); } public class FileMakerException extends Exception{}

CSV from List of sObjects

VSC can be used to create a CSV file from a SOQL query with the SFDX data command however if either you don’t want to, can’t use, or need to modify the data before creating the CSV below has 2 different variations when using sObjects.

Common sObject Method

Since there are multiple variations I created a method that is referenced in both of them:

/** @description private method for looping through and creating the CSV string from a list of sOBjects */ private static String createSObjectString(List<String> csvFieldAPINames, List<sObject> csvRowList, String concantenatedStr){ Integer i = 0; Integer rowListSize = csvRowList.size(); Integer headerSize = csvFieldAPINames.size(); for(sObject row :csvRowList){ //assuming the rowList is in the correct format and each string in the list is a new record Map objFieldMap = (Map)JSON.deserializeUntyped(JSON.serialize(row)); Integer j = 0; for(String objField :csvFieldAPINames){ concantenatedStr += objFieldMap.get(objField) != null ? String.valueOf(objFieldMap.get(objField)) : ''; j++; concantenatedStr += j != headerSize ? ',' : '';//add comma separator } i++; if(i != rowListSize) concantenatedStr += '\n';//add new line } return concantenatedStr; }

the above will take a list of sObjects, use the API names to make sure each value is in the correct cell, and return the concatenated string.

CSV from sObjects with the API Names as the Header

Below uses the API names of the sObject as the header for the list of sObjects:

/** @description create a CSV from a list of sObjects in this method the CSV headers are the same as the api names of the fields to add */ public static void createCSV(List<String> csvHeaders, List<sObject> csvRowList, String title){ String headerRow = String.join(csvHeaders,',') + '\n'; String concantenatedStr = headerRow; concantenatedStr = createSObjectString(csvHeaders, csvRowList, concantenatedStr); title += '.csv'; createFile(concantenatedStr, title); }

CSV from sObjects with a different Header than the API Names

Below uses a separate list of Strings as the header than the API names of the sObject as the header for the list of sObjects:

/** @description create a CSV from a list of sObjects in this method the CSV headers different than the api names of the fields to add */ public static void createCSV(List<String> csvHeaders, List<String> csvFieldAPINames, List<sObject> csvRowList, String title){ String headerRow = String.join(csvHeaders,',') + '\n'; String concantenatedStr = headerRow; concantenatedStr = createSObjectString(csvFieldAPINames, csvRowList, concantenatedStr); title += '.csv'; createFile(concantenatedStr, title); }

Here is a link to the GIT repo.

Leave a Reply

Your email address will not be published. Required fields are marked *