I am trying to write data to a CSV file in a separate thread. The use case is like this: when a game is running, some data needs to be written to CSV file row-by-row or line-by-line.
I found that FAsyncWriter can be used for the same. But I am not seeing the file being generated.
Here is the code for .h file:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include <Misc/OutputDeviceFile.h>
#include "CsvFileWriter.generated.h"
/**
* Class that provides methods to write data to a CSV file
*/
UCLASS(BlueprintType)
class MY_API UCsvFileWriter : public UObject
{
GENERATED_BODY()
UCsvFileWriter();
UFUNCTION(BlueprintCallable, Category = "Csv Writer")
bool OpenFile(const FString& filename);
UFUNCTION(BlueprintCallable, Category = "Csv Writer")
bool WriteLine(const FString& line);
UFUNCTION(BlueprintCallable, Category = "Csv Writer")
void CloseFile();
private:
bool m_is_opened = false;
TUniquePtr<FArchive> m_archive_ptr;
TUniquePtr<FAsyncWriter> m_async_writer;
};
and here is the code for .cpp file:
#include "CsvFileWriter.h"
#include <HAL/FileManagerGeneric.h>
UCsvFileWriter::UCsvFileWriter()
{}
bool UCsvFileWriter::OpenFile(const FString& filename)
{
if (filename.IsEmpty())
{
UE_LOG(LogTemp, Error, L"Invalid filename - empty");
return false;
}
if (!filename.EndsWith(".csv"))
{
UE_LOG(LogTemp, Error, L"Invalid filename - extension is not .csv");
return false;
}
FFileManagerGeneric file_manager;
m_archive_ptr = TUniquePtr<FArchive>(file_manager.CreateFileWriter(*filename));
if (m_archive_ptr == nullptr)
{
UE_LOG(LogTemp, Error, L"Couldn't open file");
return false;
}
m_async_writer = MakeUnique<FAsyncWriter>(*m_archive_ptr);
m_is_opened = true;
return true;
}
bool UCsvFileWriter::WriteLine(const FString& line_)
{
if (!m_is_opened)
{
UE_LOG(LogTemp, Error, L"File isn't already opened, please call OpenFile() first");
return false;
}
FString line = line_.TrimStartAndEnd();
if (line.IsEmpty())
{
UE_LOG(LogTemp, Error, L"Attempt to write an empty line");
return false;
}
line.AppendChar('\n');
auto& char_array = line.GetCharArray();
UE_LOG(LogTemp, Display, L"%s %d", char_array.GetData(), char_array.Num());
m_async_writer->Serialize(char_array.GetData(), char_array.Num());
return true;
}
void UCsvFileWriter::CloseFile()
{
if (!m_is_opened)
{
return;
}
m_async_writer->Flush();
m_async_writer->Stop();
m_archive_ptr->Close();
m_is_opened = false;
}
This is how I use it in blueprint:
Can anyone help me to find what am I doing wrong?