Read a Unity TextAsset Line by Line

The C# line-by-line file reading you know is not possible with TextAsset

Cover image
by Tommy Leung on February 26th, 2020

If you are trying to read the contents of a Unity TextAsset in a more traditional C# line-by-line method then you'll notice that you can't.

You might have been fooled during development as you can use a StreamReader to read from the Resources folder but it won't work after you've built the game.

This is the case because asset storage differs for each platform Unity supports.

One solution is to store your file in StreamingAssets instead. Then you can use Application.streamingAssetsPath with the StreamReader code you already have.

Another much simpler approach is to simply split the contents of the TextAsset. This is not recommended for a huge file but if you are working with small files then this is fast and simple.

Split the String

You probably don't need a code example for this but I'll provide some lesser-known caveats to the common string splitting code you've come across.

// where data is a TextAsset
string text = data.text;

string[] lines = text.Split(System.Environment.NewLine.ToCharArray());

foreach (string line in lines)
{
	// do something with each line
	Debug.Log(line);
}

You'll want to use System.Environment.NewLine instead of \n to ensure better support across platforms.

But why am I using a ToCharArray()? Realistically, you should be fine with just this:

string[] lines = text.Split(char.Parse(System.Environment.NewLine));

// or..

string[] lines = text.Split(System.Environment.NewLine[0]);

Except I was in a programming competition once and my team would have won had I not run into a problem of formatting the result. 🤦‍♂️

The problem was that this particular operating system used \r\n and not \n as a newline. Notice that there are 2 characters there.

I have not come across this again. Standards are more unified in the modern world but I still keep this edge case in mind.

You might not need to if you know your target platforms. It is a bit more efficient as a single char than an array.

Bonus: Using StringBuilder

For a slightly more memory efficient version you can use StringBuilder so that there is only ever 1 parsed line in memory.

The Split implementation above loads the entire contents of the file into memory and then Split returns an array with the entire contents of the file as individual lines.

This means the entire file is in memory twice. If that's a problem then you can try this alternative:

using System.Text;

// where data is a TextAsset
string text = data.text;

StringBuilder builder = new StringBuilder();
char newLine = char.Parse(System.Environment.NewLine);
int size = text.Length;

for (int i = 0; i < size; ++i)
{
	char ch = text[i];
	if (ch == newLine)
	{
		// do something with each line
		Debug.Log(builder.ToString());
		builder.Clear();
		continue;
	}

	builder.Append(ch);
}

If you absolutely need to read a text file line-by-line then don't use a TextAsset reference or store it in Resources. Use StreamingAssets instead and read the file from there.

Otherwise just splitting the contents of your TextAsset by newlines should work just fine. 👌 For the in-between cases, you can try the StringBuilder approach. 😎

Don't miss out on future Unity techniques! Enter your email into the box below to subscribe.