Working with Data in Unreal Engine

How to work with various data and files in the Unreal Engine?

Unreal Engine offers many ways of a form how data can be saved and how they can be managed. This page shows C++ example how to access various kind of data and how to work with them. For overview of design types, there's additional article in Czech language.

Check if a file exists on a disk

#include "HAL/PlatformFileManager.h" // Core
/**
 * Check whether a file exists on the disk
 * @param FilePath	The path of targeted file, e.g. "C:/Temp/MyFile.txt"
 * @param OutInfoMsg Help for action's result
 * @return The string content of the file
*/
UFUNCTION(BlueprintCallable)
static bool DoesFileExist(FString FilePath, FString& OutInfoMsg);
bool UExampleClass::DoesFileExist(FString FilePath, FString &OutInfoMsg)
{
    bool bFileExist = FPlatformFileManager::Get().GetPlatformFile().FileExists(*FilePath);
    if(!bFileExist) OutInfoMsg = FString::Printf(TEXT("Error: No File found at: '%s'"), *FilePath);
    return bFileExist;
}

Text files

Read content of any file from disk (Editor based)

Note: Verify that a file exists before trying to read it.

/**
 * Load a content of a text file
 * @param FilePath	The path of targeted file, e.g. "C:/Temp/MyFile.txt"
 * @param bOutSuccess	If the action was a success or not
 * @param OutInfoMsg	Help for action's result
 * @param FileContents  The string content of the file
*/
UFUNCTION(BlueprintCallable)
static void LoadStringFromFile(FString FilePath, bool& bOutSuccess, FString& OutInfoMsg, FString& FileContents);
#include "Misc/FileHelper.h"
void UImportAsset::LoadStringFromFile(FString FilePath, bool& bOutSuccess, FString& OutInfoMsg, FString& FileContents)
{
   bOutSuccess = FFileHelper::LoadFileToString(FileContents, *FilePath);
  OutInfoMsg = (!bOutSuccess) ? FString::Printf(TEXT("Error in loading the file - Check reading permissions at '%s'"), *FilePath) : FString::Printf(TEXT("File content '%s' was succesfully loaded"), *FilePath);
}

Load to text array

/**
 * Load a content of a text file to array
 * @param FilePath	The path of targeted file, e.g. "C:/Temp/MyFile.txt"
 * @param bOutSuccess	If the action was a success or not
 * @param OutInfoMsg	Help for action's result
 * @param FileContents  The string content of the file
*/
UFUNCTION(BlueprintCallable)
static void LoadStringArrayFromFile(FString FilePath, bool& bOutSuccess, FString& OutInfoMsg, TArray<FString>& OutFileContents);
void UExampleClass::LoadStringArrayFromFile(FString FilePath, bool& bOutSuccess, FString& OutInfoMsg, TArray<FString>& OutFileContents)
{
  bOutSuccess = FFileHelper::FFileHelper::LoadFileToStringArray(OutFileContents, *FilePath);
  OutInfoMsg = (!bOutSuccess) ? FString::Printf(TEXT("Error in loading the file - Check reading permissions at '%s'"), *FilePath) : FString::Printf(TEXT("File content '%s' was succesfully loaded to array"), *FilePath);
}

Write content to a file on disk

In this way, a file is either created with desired content, or the content is just updated in the already existing file.

/**
* Create a text file and fill it with a content
* @param FilePath	The path of targeted file, e.g. "C:/Temp/MyFile.txt"
* @param String		The string to write into the file
* @param OutInfoMsg	Help for action's result
* @return	If the action was a success or not
*/
UFUNCTION(BlueprintCallable)
static bool WriteStringToFile(FString FilePath, FString String, FString& OutInfoMsg);
#include "Misc/FileHelper.h"
bool ExampleClass::WriteStringToFile(FString FilePath, FString String, FString& OutInfoMsg)
{
   bool bSuccess = FFileHelper::SaveStringToFile(String, *FilePath);
   OutInfoMsg = (!bSuccess) ? FString::Printf(TEXT("Check writing permissions and whether '%s' filePath is valid), *FilePath) : ...;
   return bSuccess;
}

The code above is modified version of UE5 C++ 1 - How To Read and Write Text Files with C++? tutorial.

Json files

JSON is an open standard file format and data interchange format that uses human-readable text to store and transmit data objects consisting of attribute–value pairs and arrays.

As so, there is a need to define the structure of the data we work with. It may be done either through the generic Json object FJsonObject or as a classic Struct.

Reading a json file from a disk and writing it on the disk

Although we have a .json file, it is still a file with a classic FString text-based format. As so, we can read and write its content same as in a case of any other (text) based file.

// Reading text content of a file from disk
FString JsonString = "";				
bSuccess = FFileHelper::LoadFileToString(JsonString, *FilePath);
// Writing text content to a file on a disk
bool bSuccess = FFileHelper::SaveStringToFile(JsonString, *FilePath);

In the code below, we will use modules Json (includes FJsonSerializer) and JsonUtilities (includes FJsonObjectConverter). As none of them is used by the project in default, both modules must be manually added into the .Build.cs project's file.

// project's .Build.cs file
PrivateDependencyModuleNames.AddRange
   (
   	new string[] 
	{ 
		// Default Modules
		"Core", 
		"CoreUObject", 
		"Engine", 

		// New Modules
		"Json",
		"JsonUtilities",
	}
);

Conversion of FString JsonString from and to FJsonObject

As there's FString JsonString variable now holding the data, there's a need to convert it from FString to the FJsonObject format. It may be done with a Deserialize function.

#include "Serialization/JsonSerializer.h" // Json module
TSharedPtr<FJsonObject> RetJsonObject;
bool bSuccess = JsonSerializer::Deserialize(TJsonReaderFactory<>::Create(JsonString), RetJsonObject);
#include "Serialization/JsonSerializer.h" // Json module
FString JsonString;
bool bOutSuccess = FJsonSerializer::Serialize(JsonObject.ToSharedRef(), TJsonWriterFactory<>::Create(&JsonString, 0));

Holding data in UStruct

As mentioned above, data may be kept either in the FJsonObject (we already have it in the code above) or UStruct. Using UStructis a bit simplier, as all is very clearly defined. The Struct may be defined like below:

USTRUCT(BlueprintType, Category = " ... ")
struct FExampleStruct : public FTableRowBase
{
	GENERATED_BODY()

// These variables are visible in both Blueprint and is in Json
public:
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = " ... ")
		FString MyString = "String value";
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = " ... ")
		bool MyBool = true;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = " ... ")
		float MyFloat = 123.456f;
	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = " ... ")
		int MyInt = 123;

// These variables are not visible in Blueprint, but are still visible in Json
public:
	UPROPERTY()
		FVector MyVector = { 1.0f, 2.0f, 3.0f };
	UPROPERTY()
		FRotator MyRotator = { 90.0f, 180.0f, 270.0f };
	UPROPERTY()
		FTransform MyTransform;

// This variable will not be in the json because it's not flagged as an UPROPERTY()
public:
	FString MyOtherString = "This variable will not be in the json";
};

Note: FTableRowBase inheritence is optional for using the data structure for json, but necessary for using it for data tables.

As the data are now of FJsonObject type, there is a need a conversion between FJsonObject and FExampleStruct (UStruct) format:

#include "JsonObjectConverter.h" // JsonUtilities
FExampleStruct RetExampleStruct;
bOutSuccess = FJsonObjectConverter::JsonObjectToUStruct<FExampleStruct>(JsonObject.ToSharedRef(), &RetRetExampleStruct);
#include "JsonObjectConverter.h" // JsonUtilities
TSharedPtr<FJsonObject> JsonObject = FJsonObjectConverter::UStructToJsonObject(RetExampleStruct);

Json Conclusion

Let join all the individual steps to one function for loading json data from disk and one for saving json data on disk.

Loading Json file to UStruct

/**
 * Open a json file, read its content and dump it into a structure
 * @param FilePath	The path of your json file: "C:/Temp/MyJson.json"
 * @param bOutSuccess	If the action was a success or not
 * @param OutInfoMsg	More information about the action's result
 *
 * @return The structure content of the json file
 */
UFUNCTION(BlueprintCallable, Category = "Json reader")
static FExampleStruct LoadJsonToStruct(FString FilePath, bool& bOutSuccess, FString& OutInfoMsg);
#include "Serialization/JsonSerializer.h"
#include "JsonObjectConverter.h"
FExampleStruct ExampleClass::LoadJsonToStruct(FString FilePath, bool& bOutSuccess, FString& OutInfoMsg)
{
   // Load file from disk
   FString JsonString = ExampleClass::LoadStringFromFile(FilePath, bOutSuccess, OutInfoMsg);
   if (!bOutSuccess) return FExampleStruct();
	
   // Convert file content to generic json
   TSharedPtr<FJsonObject> RetJsonObject;
   if (!FJsonSerializer::Deserialize(TJsonReaderFactory<>::Create(JsonString), RetJsonObject))
   {
      bOutSuccess = false;
      OutInfoMsg = FString::Printf(TEXT("Read Json Failed - Was not able to deserialize the json string. Is it the right format? - '%s'"), *JsonString);
      return FExampleStruct();
   }

   // Convert FJsonObject to desired FExampleStruct
   FExampleStruct RetExampleStruct;
   bOutSuccess = FJsonObjectConverter::JsonObjectToUStruct<FExampleStruct>(JsonObject.ToSharedRef(), &RetExampleStruct);
   if(!bOutSuccess){
      OutInfoMsg= FString::Printf(TEXT("Read Struct Json Failed - Was not able to convert the json object to your desired structure. Is it the right format / struct? - '%s'"), *JsonFilePath);
      return FExampleStruct();
   }
   OutInfoMsg = FString::Printf(TEXT("Read Struct Json Succeeded - '%s'"), *FilePath);
   return RetExampleStruct;
}

Saving UStruct to Json file

/**
 * Convert structure to a string, create a json file and dump the string in it
 *
 * @param FilePath	The path of your json file: "C:/Temp/MyJson.json"
 * @param Struct	The struct to want to write in the file
 * @param OutInfoMsg	More information about the action's result
 * @return If the action was a success or not
 */
UFUNCTION(BlueprintCallable, Category = "Json writer")
static bool WriteStructToJsonFile(FString FilePath, FExampleStruct Struct, FString& OutInfoMsg);
#include "Serialization/JsonSerializer.h"
#include "JsonObjectConverter.h"
bool ExampleClass::WriteStructToJsonFile(FString FilePath, FExampleStruct Struct, FString& OutInfoMsg)
{
   // convert struct to generic json object
   TSharedPtr<FJsonObject> JsonObject = FJsonObjectConverter::UStructToJsonObject(Struct);
   if (JsonObject == nullptr)
   {
      OutInfoMsg = FString::Printf(TEXT("Write Struct Json Failed - Was not able to convert the struct to a json object."));
      return false;
   }

   // convert generic json object to string
   FString JsonString;
   bool bSuccess = FJsonSerializer::Serialize(JsonObject.ToSharedRef(), TJsonWriterFactory<>::Create(&JsonString, 0);
   if(!bSuccess)
   {
      OutInfoMsg = FString::Printf(TEXT("Write Json Failed - Was not able to serialize the json to string. Is the JsonObject valid?"));
	  return false;
   }

   // write json to disk
   ExampleClass::WriteStringToFile(FilePath, JsonString, OutInfoMsg)
   if(ExampleClass::WriteStringToFile(FilePath, JsonString, OutInfoMsg)){
      OutInfoMsg = FString::Printf(TEXT("Write Json Succeeded - '%s'"), *FilePath);
	  return true;
   }
   return false;
}

The code above is modified version of UE5 C++ 2 - How To Read and Write Json Files with C++? tutorial.

Data Tables

Data table, as the name suggests, is a tabular data storage format. The table is structured and allows storing both simple and complex data structures. In Unreal Engine, these tables are represented as UDataTable class.

Creating a table can be done manually by right-clicking in the Content window → MiscellaneousData table or by importing a json/csv file either manually or through C++.

Data Table Properties

  • Enables data preview, similar to Microsoft Excel. Data values can be edited directly in the table. It's a format that everyone understands.
  • Each row in the Data Table can be seen as an individual item or record, just as it can be a series of records related to 1 item. However, what remains the same is the data structure of each row. In terms of ordinary variables, it would be an array of values of the same structure.
  • Data table is a single binary asset (all data is stored within a single file). From this, the following follows:
    • Easy import and export from JSON and CSV by simply dragging and dropping the file into Unreal Engine. This is a great feature, for example, in a pipeline where data is worked on in an external program (such as Microsoft Excel), and "finished" data is inserted into Unreal Engine.
    • Reimporting the same file replaces (and thus overwrites) the existing file, including any changes that may have been made in the table. In the case of pipelines working with data imports into Data Tables, we must ensure the so-called "single source of Authority" - meaning we have to modify the data in the source file (e.g., Excel) whenever we modify it in the Data Table or vice versa, only modify it in the source file (e.g., Excel) and then reimport the .json / .csv file into Unreal Engine.
    • Allows the work of only one user, as during reimports, individual users would overwrite each other's data in the table (if they don't work from a synchronized source file). The solution is to use CompositeDataTables.
  • Data structure is defined through UStruct.
    Access to structures (e.g., for level designers) can be restricted using (RowType="USTRUCT") for filtering data tables. This can limit human error (when a designer uses the wrong structure) and make data entry easier.
  • Does not support inheritance
  • Rows in the table are accessible using RowName
  • Rows can be individually referenced using the FDataTableRowHandle variable in both Blueprint and C++
  • Data Tables can be referenced with both hard and soft references. Consider setting references carefully - incorrect records have an extreme impact on performance.
  • Values in Data Tables can be updated in the editor (before running the application) as well as in real-time runtime
  • They support diffing - tracking made changes. We can view these changes by right-clicking on the Data Table and selecting "Source control" → "Diff against depot"

Composite Data Tables

Composite Data Table is a simple structure that takes records from individual Data Tables we designate and merges all records of these tables into a new Composite Data Table. The Composite Data Table itself then has the same properties as the Data Table, so we can work with it as well.

Composite Data Tables are created through "Miscellaneous → Composite Data Table"

Example of Usage:

For easier data management, we can use several Data Tables, each containing data for a specific category. This way, each table can be managed by a different designer - designers can work on data simultaneously, each dealing only with the Data Table related to their agenda.

Composite Data Table then automatically merges all these Data Tables into one. Whenever any designer makes a change in their Data Table, this change is automatically reflected in the Composite Data Table. The Composite Data Table can serve not only as a preview of all data from one place but also as the only table worked with in code and application runtime.

Creating Data Table Structure

  • In C++

    • Utilizes inheritance from parent FTableRowBase
    • The USTRUCT type is BlueprintType

    All other Struct settings is the same as for json struct.

  • In Blueprint

    Select "Content Drawer," then "Blueprint → Structure". In the "Structure" tab, define the structure, and in the "Default values" tab, set default values.

Inserting Data into Unreal Engine

  1. By Creation

    In the "Content Drawer," select "Miscellaneous → Data table" and choose the data table structure (see structure creation step). Then, expand the table file and manually populate it with data.

  2. By Import

    Data Tables can be created in Unreal Engine by dragging and dropping .json / .csv files into the "All/Content" window in the Content Drawer. In "Import As," select "DataTable," and for "Choose DataTable Row Type," select the structure reflecting the data of the table / imported file (the structure created in the previous step).

Working with Data Table(s) in Unreal Engine with C++ (Editor Based)

We work from a UBlueprintFunctionLibrary that is available in the Editor only.

Import Data Table into Unreal Engine

/**
* Editor Only - Will not work in packaged build.
 *
 * Import a data table from a json or csv file
 *
 * @param SourcePath    The path of the source file: "C:/Temp/MyJson.json"
 * @param DestinationPath   The path of the imported asset: "/Game/Folder/MyDataTable"
 * @param StructClass   The structure to use for this data table
 * @param bOutSuccess   If the action was a success or not
 * @param OutInfoMsg    More information about the action's result
 *
 * @return The imported data table
 */
UFUNCTION(BlueprintCallable, Category = "Import Export Data Table")
static class UDataTable* ImportDataTableFromJsonOrCsv(FString SourcePath, FString DestinationPath, UScriptStruct* StructClass, bool& bOutSuccess, FString& OutInfoMsg);
#include "Factories/ReimportDataTableFactory.h" // UnrealEd module (Editor Only)

UDataTable* UExampleClass::ImportDataTableFromJsonOrCsv(FString SourcePath, FString DestinationPath, UScriptStruct* StructClass, bool& bOutSuccess, FString& OutInfoMsg)
{
   // Create factory to import a Data Table
   UReimportDataTableFactory* DtFactory = NewObject<UReimportDataTableFactory>();
   DtFactory->AutomatedImportSettings.ImportType = ECSVImportType::ECSV_DataTable;
   DtFactory->AutomatedImportSettings.ImportRowStruct = StructClass;

   // Create import task
   UAssetImportTask* ImportTask = UExampleClass::CreateImportTask(SourcePath, DestinationPath, DtFactory, nullptr, bOutSuccess, OutInfoMsg);
   if (!bOutSuccess) return nullptr;

   // Import asset
   UObject* ImportedAsset = UExampleClass::ProcessImportTask(ImportTask, bOutSuccess, OutInfoMsg);
   if (!bOutSuccess) return nullptr;
	
   // Return imported asset
   bOutSuccess = true;
   OutInfoMsg = FString::Printf(TEXT("Import Data Table Succeeded - '%s'"), *DestinationPath);
   return Cast<UDataTable>(ImportedAsset);
}
PrivateDependencyModuleNames.AddRange
(
  new string[] 
  { 
    // Default Modules
    "Core", 
    "CoreUObject", 
    "Engine", 

    // New Modules - Editor Only
    "UnrealEd",
  }
);

Data tables allow to manually import only .csv files that have an unique value in the first column. To prevent duplicity warnings, there's possible to extend csv files for first column keeping the row number, see the code below:

// .h
/**
 * Extend Csv rows for a row number column
 * @param OriginalContents	Original csv consent
 * @param StartLine  Line Index from which to start
 * @param ModifiedContents	Modified Csv Consent
*/
UFUNCTION(BlueprintCallable)
static void ExtendCsvForLineNumber(TArray<FString>& OriginalContents, TArray<FString>& ModifiedContents, FString Separator = ",", int32 StartLine = 1);

// .cpp
void UImportAsset::ExtendCsvForLineNumber(TArray &OriginalContents, TArray &ModifiedContents, FString Separator, int32 StartLine)
{    
    int LineNumber = 1;
    for (const FString& Row : OriginalContents)
    {
        // Add row number + separator
        if(LineNumber >= StartLine) ModifiedContents.Add(FString::Printf(TEXT("%d%s%s"), LineNumber, *Separator, *Row));;
        LineNumber++;
    }    
}
// .h
/**
 * Transform Csv Consents to the Structured
 * @param OriginalContents	Original csv consent
 * @param StartLine		 	Line Index from which to start
 * @param ModifiedContents	Modified Csv Consent
*/
UFUNCTION(BlueprintCallable)
static void TransormCsvConsentToStructure(TArray<FString>& OriginalContents, TArray<FExampleStruct>& StructuredContents, FString Separator = ",", int32 StartLine = 1);

// .cpp
void UExampleClass::TransormCsvConsentToStructure(TArray<FString> &OriginalContents, TArray<FExampleStruct> &StructuredContents, FString Separator, int32 StartLine){
    int32 LineNumber = 1;
    int32 SRowNumber = 1;
    for (const FString& StringRow : OriginalContents)
    {
        if(LineNumber >= StartLine) {
            TArray<FString> stringArray;
            if(StringRow.ParseIntoArray(stringArray, *Separator, false) == 14){
                // assign csv values to the structure
                FExampleStruct Row;
                Row.guid = SRowNumber;
                Row.t = FCString::Atof(*stringArray[0]);
                Row.name = *stringArray[2];
                Row.x = FCString::Atof(*stringArray[4]);
                StructuredContents.Add(Row);
                SRowNumber++;
            }
        }
        LineNumber++;     
    }    
}

Export Data table from Unreal Engine

/**
 * Editor Only - Will not work in packaged build.
 *
 * Export a data table to a json or csv file
 *
 * @param FilePath  The path of the output file: "C:/Temp/MyJson.json"
 * @param DataTable The data table to export
 * @param OutInfoMsg    More information about the action's result
 *
 * @return Whether the action was a success or not
 */
UFUNCTION(BlueprintCallable, Category = "Import Export Data Table")
static bool ExportDataTableToJsonOrCsv(FString FilePath, class UDataTable* DataTable, FString& OutInfoMsg);
#include "Factories/ReimportDataTableFactory.h" // UnrealEd module (Editor Only)

bool UExampleClass::ExportDataTableToJsonOrCsv(FString FilePath, UDataTable* DataTable, FString& OutInfoMsg)
{	
  if (DataTable == nullptr)
  {
    OutInfoMsg = FString::Printf(TEXT("Export Data Table To Json Or Csv Failed - Data table is nullptr. FilePath: '%s'"), *FilePath);
    return false;
  }

  // Convert table to string
  FString TableString = (FilePath.Contains(".csv")) ? DataTable->GetTableAsCSV() : DataTable->GetTableAsJSON();

  // Write string to file, return success state
  return UExampleClass::WriteStringToFile(FilePath, TableString, OutInfoMsg);
}

Data Table Json (Unreal specific) file

When exporting a Json file from Unreal Engine, while it contains all the same data, it may have 2 output formats based on whether it use a struct inherited from FTableRowBase or not. When importing / exporting FTableRowBase inherited struct (e.g. importing .json file back to Data Table in Unreal after a change made in the file after its export from the Unreal Engine), there's possible to use something like the function below.

Read a series of struct based on a json file formatted like a data table

#include "Kismet/BlueprintFunctionLibrary.h" // Engine, Editor only
/**
 * Editor Only - Will not work in packaged build.
 *
 * Read a series of struct based on a json file formatted like a data table
 *
 * @param FilePath   The path of the source file: "C:/Temp/MyJson.json"
 * @param bOutSuccess   If the action was a success or not
 * @param OutInfoMsg    More information about the action's result
 *
 * @return The structs
 */
UFUNCTION(BlueprintCallable, Category = "...")
static TMap<FString, FExampleStruct> ReadStructFromJsonFile_DataTableFormat(FString FilePath, bool& bOutSuccess, FString& OutInfoMsg);
#include "Engine/DataTable.h" // Engine
TMap<FString, FExampleStruct> UExampleClass::ReadStructFromJsonFile_DataTableFormat(FString FilePath, bool& bOutSuccess, FString& OutInfoMsg)
{
	// Read file
	FString JsonString = UExampleClass::LoadStringFromFile(FilePath, bOutSuccess, OutInfoMsg);
	if (!bOutSuccess) return TMap<FString, FExampleStruct>();
	
	// Create data table and tell it which struct it's using
	UDataTable* Table = NewObject<UDataTable>();
	Table->RowStruct = FExampleStruct::StaticStruct();

	// Populate data table
	Table->CreateTableFromJSONString(JsonString);

	// Retrieve the rows
	TArray RowNames = Table->GetRowNames();

	// Populate the return map
	TMap RowsToStruct;

	for (FName RowName : RowNames)
	{
		FExampleStruct* Row = Table->FindRow<FExampleStruct>(RowName, nullptr);
		if (Row != nullptr) RowsToStruct.Add(RowName.ToString(), *Row);
	}

	// Return the rows
	bOutSuccess = true;
	OutInfoMsg = FString::Printf(TEXT("Read Data Table Json Succeeded - '%s'"), *FilePath);
	return RowsToStruct;
}

Write a series of struct to a json file formated like a data table

#include "Kismet/BlueprintFunctionLibrary.h" // Engine, Editor only
/**
 * Editor Only - Will not work in packaged build.
 *
 * Write a series of struct to a json file. Will be formatted like a data table
 *
 * @param FilePath			The path of the output file: "C:/Temp/MyJson.json"
 * @param RowsToStruct		The structs to write in the json
 * @param bOutSuccess		If the action was a success or not
 * @param OutInfoMsg	More information about the action's result
 */
UFUNCTION(BlueprintCallable, Category = " ... ")
static void WriteStructToJsonFile_DataTableFormat(FString FilePath, TMap<FString, FExampleStruct> RowsToStruct, FString& OutInfoMsg);
#include "Engine/DataTable.h" // Engine
void UExampleClass::WriteStructToJsonFile_DataTableFormat(FString FilePath, TMap<FString, FExampleStruct> RowsToStruct, FString& OutInfoMsg)
{
	// Convert all rows to string
	TArray<FString> RowNames;
	RowsToStruct.GetKeys(RowNames);

	// Create data table and tell it which struct it's using
	UDataTable* Table = NewObject<UDataTable>();
	Table->RowStruct = FExampleStruct::StaticStruct();

	// Add all rows to the data table
	for (FString RowName : RowNames)
	{
		Table->AddRow(FName(RowName), RowsToStruct[RowName]);
	}

	// Export to file, return success state
	return UExampleClass::ExportDataTableToJsonOrCsv(FilePath, Table, bOutSuccess, OutInfoMsg);
}

Get Data Table from disk

Request from Construction (ASomeClass::ASomeClass()) one of the following function:

UDataTable* USpawnAsset::GetSomeTable(FString TablePath)
{
  FString TablePath = FString::Printf(TEXT("/Game/DataTables/DT_table%d.DT_table%d"), I, I);
  static ConstructorHelpers::FObjectFinder<UDataTable> DataTableFinder(*TablePath);
  if (DataTableFinder.Succeeded())
  {
    return DataTableFinder.Object;
  } else {
    UE_LOG(LogTemp, Error, TEXT("DataTable asset not found! path: %s"), *TablePath);
    return nullptr;
  }	
}
UDataTable* USpawnAsset::GetSomeTable(FString TableName, FString TableDestination)
{
  FString DataTablePath = TableDestination+"/"+DataTablePathArr[0];
  UDataTable* TheTable = Cast<UDataTable>(StaticLoadObject(UDataTable::StaticClass(), nullptr, *DataTablePath));
  if(!TheTable) UE_LOG(LogTemp, Warning, TEXT("[ConfigurateOccupant] DataTable '%s' not found."), *TableName);
  return TheTable;
}

Reading values from Data Table

Assuming, there's a pointer to a UDataTable.

  • FYourStruct* Item = YourDataTable->FindRow<FYoursStruct>(RowName, "");
  • If there's not known the RowName or is a need to iterate all RowNames:
    TArray<FName> RowNames = YourDataTable->GetRowNames();
  • Total Number of rows can be get by int rowCount = TargetDatatable->GetRowNames().Num();