How can I write to text files?

I’m working on a custom, artist-editable UI solution to replace Slate on our project, and as part of that, I need to write to text files (since we edit our UI layouts at runtime, and AFAIK there’s no way to make permanent changes to the level objects in the editor from the game).

Right now we’re using FPlatformFileManager for this, like so:

	FString filename = FrameName;
	filename += TEXT( ".uix" );

	IFileHandle * pFile = FPlatformFileManager::Get().GetPlatformFile().OpenWrite( *filename );

This ends up writing the file to UnrealEngine/Engine/Binaries, which probably isn’t where we want it – we’d rather it be in Config or somewhere like that.

Related questions:

  • Should we be using FPlatformFileManager for this?
  • If not, what’s the best way to do it?
  • If so, how best to specify the file folder for placement?
  • Alternatively, is there a way to modify .ini files at runtime?

#CoreMisc.h

__

I thus make your entire project super happy fun with this one .h file !!!


Read all the functions here!!!

CoreMisc.h

/**
	 * Parses a string into tokens, separating switches (beginning with - or /) from
	 * other parameters
	 *
	 * @param	CmdLine		the string to parse
	 * @param	Tokens		[out] filled with all parameters found in the string
	 * @param	Switches	[out] filled with all switches found in the string
	 */
	static void Parse(const TCHAR* CmdLine, TArray<FString>& Tokens, TArray<FString>& Switches);

/**
	 * Load a text file to an FString.
	 * Supports all combination of ANSI/Unicode files and platforms.
	 * @param Result string representation of the loaded file
	 * @param Filename name of the file to load
	 * @param VerifyFlags flags controlling the hash verification behavior ( see EHashOptions )
	 */
	static bool LoadFileToString( FString& Result, const TCHAR* Filename, uint32 VerifyFlags=0 );

/**
	 * Write the FString to a file.
	 * Supports all combination of ANSI/Unicode files and platforms.
	 */
	static bool SaveStringToFile( const FString& String, const TCHAR* Filename, EEncodingOptions::Type EncodingOptions=EEncodingOptions::AutoDetect, IFileManager* FileManager=&IFileManager::Get() );

/**
	 *	Load the given ANSI text file to an array of strings - one FString per line of the file.
	 *	Intended for use in simple text parsing actions
	 *
	 *	@param	InFilename			The text file to read, full path
	 *	@param	InFileManager		The filemanager to use - NULL will use &IFileManager::Get()
	 *	@param	OutStrings			The array of FStrings to fill in
	 *
	 *	@return	bool				true if successful, false if not
	 */
	static bool LoadANSITextFileToStrings(const TCHAR* InFilename, IFileManager* InFileManager, TArray<FString>& OutStrings);

#Save Text Files Anywhere You Want

You can save a text file anywhere you want !


You can also load and PARSE a string!!!

This parsing should make your entire goal great fun :slight_smile:


#FileHelper

You need to preface the above functions with FFileHelper::

#New Method of File Management

My code below is old

see my tutorial here for the new File Management functions

GFileManager no longer exists

Wiki link

#My Function For You

bool UVictoryBPFunctionLibrary::SaveStringTextToFile(
	FString SaveDirectory, 
	FString FileName, 
	FString SaveText,
	bool AllowOverWriting
){
	//GFileManager?
	if (!GFileManager) return false;
 
	//Dir Exists?
	if ( !GFileManager->DirectoryExists( *SaveDirectory))
	{
		//create directory if it not exist
		GFileManager->MakeDirectory( *SaveDirectory);
 
		//still could not make directory?
		if (!GFileManager->DirectoryExists( *SaveDirectory))
		{
			//Could not make the specified directory
			return false;
			//~~~~~~~~~~~~~~~~~~~~~~
		}
	}
 
	//get complete file path
	SaveDirectory += "\\";
	SaveDirectory += FileName;
 
	//No over-writing?
	if (!AllowOverWriting)
	{
		//Check if file exists already
		if (GFileManager->GetFileAgeSeconds( * SaveDirectory) > 0) 
		{
			//no overwriting
			return false;
		}
	}
 
	return FFileHelper::SaveStringToFile(SaveText, * SaveDirectory);
}

#LoadStringFromTextFile

/**
	 * Load a text file to an FString.
	 * Supports all combination of ANSI/Unicode files and platforms.
	 * @param Result string representation of the loaded file
	 * @param Filename name of the file to load
	 * @param VerifyFlags flags controlling the hash verification behavior ( see EHashOptions )
	 */
	static bool LoadFileToString( FString& Result, const TCHAR* Filename, uint32 VerifyFlags=0 );

Awesome. Thanks, Rama!

Blargh … It still writes it to Engine/Binaries (actually, Engine/Binaries/Win64 this time).

Any idea how to fix this? I could try using “…\OurGameName\Config” but it’s in a different folder for everyone on our team … and the end user isn’t (presumably) going to have an Engine/Binaries folder.

Any ideas?

what is the string that you are using as your filename?

You could just type it out and you’d be fine!

FString Filename = “E:/MyProjectDir/Textfiles/Test1.txt”;

How are you generating the filename string?

please post code

Are you saying that even if you specify the entire path, it is going somewhere else? that is something I’ve never experienced :slight_smile:

1 Like

No, specifying an absolute path wouldn’t work, since all of our developers have the project in different folders on their hard drives.

The path needs to be relative to the PROJECT root, not the engine. How to figure out the root path for our actual game?

Thanks, Rama!! :slight_smile:

#Paths.h

All of the functions you could ever want for this are in Paths.h

Used with FPaths::

#Example1

/**
	 * Returns the base directory of the current game by looking at the global
	 * GGameName variable. This is usually a subdirectory of the installation
	 * root directory and can be overridden on the command line to allow self
	 * contained mod support.
	 *
	 * @return base directory
	 */
	static FString GameDir();

#Example 2

FPaths::GameDir() + FString("MyTestStrings/Test1.txt");

Enjoy!

Rama

1 Like

see my edited comment above in case you missed specific examples!

:slight_smile:

what if the absolute path was a network drive? Hard to get to a network drive from the project directory.