How to load a large text asset with minimum to no lag.

So I have these large text files that are over 1mb in size, and unity pretty much crashes when I try and load them instantly.

So I tried using IEnumerator to load it, this got rid of the lag early on, but as the Coroutine went on, it completely slows down the application and just crashes.

IEnumerator loadInText (TextAsset textToLoad) {
        txtText.text = "";
        if (selectedType == "Stories") {
            var arrayString = textToLoad.text.Split ('

');
foreach (var line in arrayString) {
txtText.text += line.ToString () + "
";
yield return new WaitForSeconds (0.0001f);
}
}
yield return null;
}

The 0.0001f delay is there because unity crashes without it.

This has been a huge pain to deal with, and it seems unity is having lots of trouble loading text.

Is there anyway to put this function on it’s own thread of some sort so it doesn’t effect the main thread? If that is possible then It would work well enough for a fix, but it would be better if the text file just loads instantly in a couple of seconds at least.

I think it maybe important to mention that I am using TextMeshPro for text, and that may take text longer to render?
I am also having my TextMeshPro inside a scroll view that auto sizes depending on the TextMeshPro , I do understand those also take up processing, but they are a mandatory component and are the only ones.

I am running this application on Mobile Android and it’s even slower then.
I am using Unity 2018.3

using System.Threading.Tasks;

static async Task<string> ReadTextFileInBackgroundThread ( string filePath )
{
	if( !System.IO.File.Exists(filePath) ) 
	{
	    	Debug.LogWarning($"This file path is invalid tho: '{filePath}'");
	    	return string.Empty;
	}
	// we're still on unity thread here
    return await Task.Run(
        () =>
        {
            // we're on worker thread, so exciting!
            return System.IO.File.ReadAllText(filePath);
        }
    );
    // back on unity thread
}

async void Start ()
{
    txtText.text = await ReadTextFileInBackgroundThread( @"c:\hentai\wishlist.txt" );
}

I recommend this asset for an easier setup process, and threading for UI and threading for not UI, Super easy to use.

I propose a solution which is more Unity-admissible :slight_smile: :

using System.IO;
using System.Threading;
using UnityEngine;

public class WaitForFileRead : CustomYieldInstruction
{
    private bool _fileRead = false;

    public override bool keepWaiting => _fileRead;

    public WaitForFileRead(string filePath, FileContents fileContents)
    {
        new Thread(() => {
            fileContents.Text = File.ReadAllText(filePath);
            _fileRead = true;
        }).Start();
    }
}

public class FileContents
{
    public string Text { get; set; }
}

You can use it this way in a coroutine:

private IEnumerator myCoroutine()
{
   FileContents fileContents = new FileContents();
   yield return new WaitForFileRead("myFilePath.txt", fileContents);
   // Here, fileContents.Text contains the content of your file.
   // It was retrieved without impacting your frame rate!
}

I’ll be honest, I’m not sure why there would be huge delays and crashes with a text file that’s only 1MB. I have a word list asset I use in many of my projects which is 1.5MB and it loads very quickly with minimal delay. This is the code I use:<pre>private void validateWordList() { if(this._Words == null) { TextAsset mytxtData = (TextAsset)Resources.Load(this.sourceFile); this._Words = mytxtData.text.Split(new char[] { ' ', '\r' }, System.StringSplitOptions.RemoveEmptyEntries); mytxtData = null; } }</pre>

No threading, no coroutines, no delays.

Though, looking at your original code, I would think its the fact its calling a yield return every single loop iteration. I propose a change to the text building loop which instead of delays every time its performs an addition to the built text, it performs its function, say… 200 times, and then calls for the delay.
Here’s a modification of the original code (fixing the yield returns):<code><pre>IEnumerator loadInText(TextAsset textToLoad) { txtText.text = ""; if(selectedType == "Stories") { var arrayString = textToLoad.text.Split(' '); int counter = 0; foreach(var line in arrayString) { txtText.text += line.ToString() + " "; counter++; if(counter == 200) { counter = 0; yield return null; } } } yield break; }</pre>

The reason I chose 200 is because its a loop count that would reach very quickly, and its large enough to split up the yield return null calls so they aren’t happening so fast.