Menu

File I/O in Unity3D

This code will do the trick and works on PC, Mac, iOS and Android:

       string fileName = "";
#if UNITY_IPHONE			
	string fileNameBase = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf('/'));
	fileName = fileNameBase.Substring(0, fileNameBase.LastIndexOf('/')) + "/Documents/" + FILE_NAME;
#elif UNITY_ANDROID
	fileName = Application.persistentDataPath + "/" + FILE_NAME ;
#else
	fileName = Application.dataPath + "/" + FILE_NAME;
#endif

fileWriter = File.CreateText(fileName);
fileWriter.WriteLine("Hello world");
fileWriter.Close();

[edit]

Since Unity 3.3, it is no longer necessary to use platform-specific code for simple file I/O. Use Application.persistentDataPath to do the trick.

This code would replace the code above:

	string fileName = Application.persistentDataPath + "/" + FILE_NAME;
	fileWriter = File.CreateText(fileName);
	fileWriter.WriteLine("Hello world");
	fileWriter.Close();

Thanks, erique, for pointing this out on the Unity forum.

[/edit]

44 thoughts on “File I/O in Unity3D”

  1. Krodil says:

    Hi,
    Thnx for the input.
    How would you actually make this work?
    Lets say I want to print positions of an object every 0.5 second into a txt file?

  2. Krodil, something like this should do the trick:

    // class members
    float timeUntilNextPositionWrite = 0.0f;
    const float TIME_BETWEEN_POSITION_WRITES = 0.5f;
    StreamWriter fileWriter = null;
    
    // before you want to start writing (the code working for Unity3.3; for older versions see above)
    string fileName = Application.persistentDataPath + "/" + FILE_NAME;
    fileWriter = File.CreateText(fileName);
    	
    // in the Update method
    timeUntilNextPositionWrite -= Time.deltaTime;
    if (timeUntilNextPositionWrite < 0.0f)
    {
        fileWriter.WriteLine("" + transform.position.x);
        fileWriter.WriteLine("" + transform.position.y);
        fileWriter.WriteLine("" + transform.position.z);
        timeUntilNextPositionWrite += TIME_BETWEEN_POSITION_WRITES;
    }
    
    // when you are done writing
    fileWriter.Close();
    

    Note that I’m writing the x, y and z coordinates separately. Basically, the way you write out data to a file is entirely up to you. If you want a more convenient way saving data you can use the PlayerPrefs class (or PreviewLabs.PlayerPrefs if you’re targeting iOS or android) in conjunction with ArrayPrefs.

  3. Pat says:

    Hey i have saved an image to persistentdatapath. How to I retrieve that image?

  4. Hi Pat, you’ll have to use the WWW class for this:

    new WWW("file://" + Application.persistentDataPath + "/myImage.jpg");
    
  5. hippocoder says:

    Hi,

    A great blog. No wonder you guys prototype fast. Simple clear way to do it for ios.

    I do have one question though, the above relates to strings. Would it be possible to load/save ints, booleans and floats using this method, or is it limited to strings?

    Thanks 🙂

  6. Hi Hippocoder. Sure you can also save other data types. If you want to save in a human-readable text format, you have to cast these types to string when writing, and the other way around when reading. This should be okay for most uses. Please note that certain data types may be converted to strings differently depending on the language settings of the computer your game is running on. As far as I know, this only occurs for stand-alone games on mac and PC. To take care of it, you can override the language settings using the following line of code:

    System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
    

    If you don’t care about reading / editing your saved data in a text editor, then you can also save your ints, booleans etc. in binary format. For this you could use methods as File.Create() and FileStream.Write().

  7. Captnemo says:

    Hey Bernard,

    Thx for help, when I save / load on ipad I get a massive freeze is there a way to load while continuing animating the onscreen objects?

    Cheers,
    Tim

  8. Hi Captnemo. You can use the WWW class in combination with local file URLs to avoid freezing your game. The line of code to create the WWW object is mentioned a bit higher in the comments, in a reply to Pat. You can use the isDone property every frame to know when the loading has finished, or use the yield statement as explained in the Unity documentation. The frame rate may drop a bit while loading; if this is an issue you can change the threadPriority value to a lower priority.

  9. r618 says:

    hey there, nice blogpost
    just small correction

    Path.Combine( Application.persistentDataPath, FILE_NAME);

    should/might be used when creating filesystem path 🙂

  10. niks says:

    hello all,

    i am new in unity. and i want to create local database for iphone in unity3D game.
    i had tried a lot with different blogs but no one work for iphone.
    i am able to do that for MAC.(i am using Sqlite DataBase Browser for this)

    can any one tell me the way to create/read/write Local database…

    1. I’ve sent you a mail, to avoid going off topic too far.

      If all you’re looking for is a convenient way of storing data and don’t really need to store it in a relational way, I’d reccomend to use the PreviewLabs.PlayerPrefs class, which will give you an easy-to-use and fast hashmap type of storage system. It’s available for free at http://www.previewlabs.com/writing-playerprefs-fast/.

  11. niks says:

    hello Bernard

    Thanks for the quick reply..

    i just want to create a local database to read and write dynamic data.

    and i am querious to know how we can do this in unity.

    1. You could try siaqodb (there’s a version specifically for Unity3D, but it requires using LINQ instead of SQL to write queries).

  12. Franck says:

    Hi Bernard
    Great thread

    It is strange that there is no documentation about file I/O in unity scripting reference.

    How do you save a http://www.texture to persistentDataPath ?

  13. Franck says:

    Actually I want to cache downloaded images, in stead of re downloading them each time I start unity. Do you know an equivalent way as http://WWW.LoadFromCacheOrDownload that only works with an AssetBundle and not with images.

  14. Hi Franck. You can use File.WriteAllBytes to write the bytes from a WWW object to a file.
    As the saved file won’t be in your Resources folder, you’ll have to use the WWW object again in combination with a local file URL in order to load the file back into memory for later use (using a local file URL is explained higher in the comments).

    Let’s say you created an object ‘loadingImageWWW’. In your Update, you’ll be checking whether the download has completed, and if so, store the downloaded bytes in a file:

    	
    if (loadingImageWWW.isDone)
    {
          File.WriteAllBytes(Application.persistentDataPath + "/myTextureFile.png", loadingImageWWW.bytes);				
    }
    

    Note that this can be done with any type of file.

  15. Franck says:

    Hi Bernard, Thanks
    I wonder how could I check if the file exists or not on the persistentDataPath?
    (ex if file exist load from DataPath, else load from internet and write to DataPath)

    How can I clear the cache (ex : del *.jpg) ?

  16. Actually, you can use the .NET APIs for all file handling. Most is in the System.IO namespace, mainly in the File class.

    For instance, to check if a file exists, you can use File.Exists.

    Alternatively, you could use Unity’s PlayerPrefs class (or our improved version of it) to remember that the file has been saved.

  17. Franck says:

    does Application.persistentDataPath and File I/O work with unity web player ?

  18. Franck says:

    I got the following error :

    BCE0019: ‘bytes’ is not a member of ‘UnityEngine.Texture2D’.

    Did I miss Something ?

  19. The ‘bytes’ array is a member of the WWW class

    As far as I know, it’s not possible to write files using the web player without a special per-title Unity license. Small amounts of data can be saved using Unity’s PlayerPrefs class.

    I know Flash supports using a limited amount of local storage; perhaps this will be available for the upcoming Flash export option in Unity (due in a few weeks or months).

  20. Franck says:

    Ok I’m using the ios version for now
    the images are well saved in the persistentDataPath

    but I got this error loading them :
    You are trying to load data from a www stream which had the following error when downloading.
    malformed

    var fileName : String = Application.persistentDataPath + “/ico_” + AppTextureLoading.AppId[nb] + “.jpg”;
    var www : WWW;

    if (File.Exists(fileName))
    {
    www = new WWW(fileName);
    yield www;
    }
    if (www.isDone)
    {
    var tex = http://www.texture; // ERROR HERE
    }

    It’s strange, because sometime, one or two textures are well loaded, but almost no.

  21. Franck says:

    oups forgoten to add “file://”

    www = new WWW(“file://”+fileName);

    Worked perfectly

    Thanks

  22. Franck says:

    Hi Bernard I found a way to delete all the files:
    I just have to create a “Cache” directory and save my files there using :
    Directory.CreateDirectory(Application.persistentDataPath +”/Cache”);

    And to delete all the files:

    var IconsFiles = Directory.GetFiles(Application.persistentDataPath +”/Cache”);
    for (var iconsFiles in IconsFiles)
    {
    File.Delete(iconsFiles);
    }
    Directory.Delete(Application.persistentDataPath +”/Cache”);

  23. Ralph says:

    On Android, I get:

    Exception!System.IO.IsolatedStorage.IsolatedStorageException: Could not find a part of the path “/mnt/asec/com.xxx.yyy/pkg.apk/zzz.txt”

    Every time I try to write to the filesystem. Is there some weird permissions setting somewhere for Android that doesn’t exist on iOS? This code works fine on iOS and the Editor.

  24. Daz says:

    Im looking for something like this for my app on android. I’m trying to create two scenes (One for writing to textfile and the other to read). The “write” scene will be used to add a user defined text to each of my prefabs. So, on this scene will be a list of the prefabs, and a text form to edit each one.

    The second scene “Read” will call each prefab and show the user defined text (from the “write” scene.

    Obviously i don’t want a ton of text files to read from…so how can i get it to read individual strings in the text file?

    1. Hi Daz,

      To avoid a lot of work, I suggest to use the PlayerPrefs class. This is a built in class of the Unity Engine, but we made an optimized version of it, especially interesting for Android. It’s freely available – see http://www.previewlabs.com/writing-playerprefs-fast/

      In your example, you would use a different key for each of the values you want to store.

  25. DaveA says:

    Having a devil of a time with saving files on Android. I Debug.Log where it thinks it will save:

    Debug.Log (“Saving to:”+Application..persistentDataPath+”/myfile.png”);

    and it fail to save it, my log says:

    Saving to:/data/data/com.mycomp.myapp/files/myfile.png

    then

    Failed to open file at path: /data/data/com.mycomp.myapp/data/data/com.mycomp.myapp/files/myfile.png

    which is REALLY messed up.

  26. Waz says:

    I also get /data/data/com.mycomp.myapp/data/data/com.mycomp.myapp/files/myfile.png

    Looks like a Unity bug. Report it to Unity.

  27. Waz says:

    Hmm, no, problem for me was that Application.CaptureScreenshot on Android will not accept an absolute path, effectively prepending Application.persistentDataPath to whatever you pass to it.

  28. NMD says:

    Hi, I realize this is old but I have a question. Say I have preexisting txt or bin data files. I do not save to them while on the iOS device but I read from them. Where in unity to I place them exactly? Do I need to put the txt files in Resources and load them with Resources.load? PS> using text assets is not a good option for me. Thanks!

  29. NMD: You’ll need to place the files in the folder you see if you do a "Debug.Log(Application.persistentDatapath);".

    If you’re running your game in the Unity editor on Windows, it’s should be in the following folder:
    C:Users<your user name>AppData

    If you’re running your game in the editor on OS X, it’s somewhere in ~/Library/Caches/<Company Name>/<Product Name as configured in the Unity project>. The ‘~’ stands for your home folder.

    Note that these folders are usually hidden folders, so if you’re using Explorer (Windows) or Finder (OS X) to access these, you need enable viewing hidden folders.

  30. shayan says:

    hi
    i wand to read an acces database on android then i copy my data base files in AssetsStreamingAssets folder (when i export my APK file and i open my file with winrar ican see it in my apk file)
    an i try to read it with this kind of path :
    MyFinalpath= Application.persistentDataPath+ “/Database1.mdb”;

    but it does not work i can not see my filed in my installed apk on my tablet what should i do?
    (i can see result when i play on pc)
    my codes :

    //////////////////

    using UnityEngine;
    using System.Collections;
    using System;
    using System.IO;
    using System.Data;
    using System.Data.Odbc;

    public class ACCESSREADER : MonoBehaviour {
    public DataTable dtYourData;
    // public static String MyFinalpath=Application.streamingAssetsPath ;
    public static String MyFinalpath ;
    // Use this for initialization
    void Start () {

    MyFinalpath= Application.persistentDataPath + “/Database1.mdb”;
    Debug.Log(MyFinalpath);
    // Access 2007 format
    // readMDB(Application.dataPath + “/Database2.accdb”);
    // readMDB(MyFinalpath+”/Database2.accdb”);

    // Access 2003 format
    readMDB(MyFinalpath);

    }

    // Update is called once per frame
    void Update () {

    }

    // set this to internal so that we can hook into it from other parts of the program
    internal void readMDB( string filetoread)
    {
    string con = “Driver={Microsoft Access Driver (*.mdb, *.accdb)}; DBQ=”+filetoread;
    Debug.Log(con);
    string yourQuery = “SELECT * FROM PlayersQuery”;
    // our odbc connector
    OdbcConnection oCon = new OdbcConnection(con);
    // our command object
    OdbcCommand oCmd = new OdbcCommand(yourQuery, oCon);
    // table to hold the data
    dtYourData = new DataTable(“YourData”);
    try
    {
    // open the connection
    oCon.Open();
    // lets use a datareader to fill that table!
    OdbcDataReader rData = oCmd.ExecuteReader();
    // now lets blast that into the table by sheer man power!
    dtYourData.Load(rData);
    // close that reader!
    rData.Close();
    // close your connection to the database query!
    oCon.Close();
    // wow look at us go now! we are on a roll!!!!!
    // lets now see if our table has the data in it, shall we?
    }
    catch (Exception ex)
    {
    Debug.Log(ex.ToString());
    }
    finally
    {
    if (oCon.State != ConnectionState.Closed)
    oCon.Close();
    oCon.Dispose();
    }
    if(dtYourData.Rows.Count > 0)
    {
    // do something with the data here
    // but how do I do this you ask??? good question!
    for (int i = 0; i < dtYourData.Rows.Count; i++)
    {
    // for giggles, lets see the column name then the data for that column!
    Debug.Log(dtYourData.Columns[0].ColumnName + " : " + dtYourData.Rows[i][dtYourData.Columns[0].ColumnName].ToString() +
    " | " + dtYourData.Columns[1].ColumnName + " : " + dtYourData.Rows[i][dtYourData.Columns[1].ColumnName].ToString() +
    " | " + dtYourData.Columns[2].ColumnName + " : " + dtYourData.Rows[i][dtYourData.Columns[2].ColumnName].ToString() +
    " | " + dtYourData.Columns[3].ColumnName + " : " + dtYourData.Rows[i][dtYourData.Columns[3].ColumnName].ToString()
    );
    }
    }
    }
    }

  31. Vicky says:

    Will the code above work for screen shots? We want to do a simple screenshot to the iOS/Android camera roll. Thank you!

  32. Jannes Plyson says:

    @Shayan:
    On Android, the assets inside the StreamingAssets folder are compressed and added to the apk file. You can’t access these files directly, you can only load them trough a WWW call.
    I see the accessDriver expect a path to a file so this will not work together with the WWW object. I think you will first have to copy the file from the StreamingAssets folder to a file in the Application.persistentDataPath folder. This should only happen once. You can then connect to the copy. Here is an example on how this could be done.

    public class ACCESSREADER : MonoBehaviour {
    
    	private string fileName = "database1.mdb";
    	private WWW copyWWW = null;
    	private string databasePath = "";
    	private bool canReadDB = false;
    
    	void Start () {
    		databasePath = System.IO.Path.Combine(Application.persistentDataPath,fileName);
    		canReadDB = true;
    		if(!System.IO.File.Exists(databasePath)){
    			copyWWW = new WWW(System.IO.Path.Combine(Application.streamingAssetsPath,fileName));
    			canReadDB = false;
    		}
    		readMDB(MyFinalpath);
    	}
    	// Update is called once per frame
    	void Update () {
    		if(copyWWW != null && copyWWW.isDone){
    			System.IO.File.WriteAllBytes(databasePath,copyWWW.bytes);
    			canReadDB = true;
    		}
    	}
    
    	public void ReadMDB(){
    		if(!canReadDB){
    			Debug.Log ("DB file not ready yet");
    			return;
    		}
    		string con = "Driver={Microsoft Access Driver (*.mdb, *.accdb)}; DBQ="+databasePath;
    		...
    	}
    }
    
  33. Jannes Plyson says:

    @Vicky
    You will need a native plugin to save images into the iOS/Android camera roll.
    We have used the etcetera plugins from Prime31 to accomplish this in our projects.

  34. Jeremy181801 says:

    Hey I’m making a Android camera application and I’m having some trouble saving the image to the SD card. I’m quite new to coding but I’m using Unity which makes it a lot easier. When I test the application inside Unity the saving works fine but I had to make a file called “SnapShots”. So how do I save an image to my android sd card without having to create a file on the android device manually (and having the android gallery automatically pick it up and put it in the gallery)

    Heres my C# Code:

    using UnityEngine;
    using System.Collections;
    using System;
    public class WebCameraScript : MonoBehaviour {
    	public string deviceName;
    	WebCamTexture wct;
    	public string path = "";
    	void Start ()
     {
    	 WebCamDevice[] devices = WebCamTexture.devices;
    		deviceName = devices[0].name;
    		wct = new WebCamTexture(deviceName, 400, 300,12);
    		renderer.material.mainTexture = wct;
    		wct.Play();
    		}
    	void OnGUI()
    	{
    		if (GUI.Button(new Rect(10,70, 50, 30), "Click"))
    			TakeSnapshot();
    	 }
    	string fileName(int width, int height){
    		return string.Format("screen_{0}x{1}_{2}.png",width, height,
    		                       System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"));
    		}
    	void TakeSnapshot()
    	{
    		Texture2D snap = new Texture2D(wct.width,wct.height);
    		snap.SetPixels(wct.GetPixels());
    		snap.Apply();
    		byte[] bytes = snap.EncodeToPNG();
    		string filename = fileName(Convert.ToInt32(snap.width),Convert.ToInt32(snap.height));
    		path = Application.dataPath + "/Snapshots/" + filename;
    		System.IO.File.WriteAllBytes(path,bytes);
    		}
    	}
    
  35. Jannes Plyson says:

    Hi Jeremy,
    If you have troubles with saving files because the parent directories don’t exist, you can try the solution suggested at:
    http://stackoverflow.com/questions/2955402/how-do-i-create-directory-if-doesnt-exist-to-create-file

  36. Jeremy181801 says:

    Thank you! Ill post another comment letting you know how it goes! 😀

  37. Darren says:

    Hello. I am looking to create a fairly substantial dialog-tree system for my games, which will be very dialog heavy. My intentions are to deploy to iOS, Android, Windows Phone, and Windows. I am not sure what solution would best server my purposes. My feeling is that JSON or XML files would work best, but I do not know if this causes any problems for mobile platforms. Or would the PlayerPrefs solution mentioned above be a feasible solution for this? Or something else?

  38. mohit says:

    hi,
    I work on a project, in which i will download audio file from server on persistent data path and
    its download well and work on android but not is IOS, please help me lo play audio file.

    /* load audio file */
    IEnumerator LoadAudioFile(string fileName) {
    WWW www = null;
    AudioClip myAudioClip = null;
    string path = Application.persistentDataPath + “/Audio/”+fileName;
    www = new WWW(“file://”+path);
    myAudioClip = http://www.audioClip;
    while (!myAudioClip.isReadyToPlay)
    yield return www;
    tempClip = http://www.GetAudioClip(false);
    StartCoroutine (PlayEffect());
    }
    and ios debug log is:- Path= file:///var/mobile/Applications/5D0EA96C-31C6-4351-AAE7-23A0B2AC85AE/Documents/Audio/compound_389.wav

    please help me asap.

  39. Arvydas says:

    hi 🙂 im using ur playerprefs in JS script, everything works prettymuch well, only problem is im making scoore and saving it as integer, then in other ui obj im geting that int and setting that ui text render it… but i get 0 vallue allways, with old playerprefs it was working, i had put import PreviewLabs.PlayerPrefs; in top of every file using playerprefs and allso start each line with PreviewLabs.PlayerPrefs… :/ what is the prblem, i read coments and found that someone had this problem to but no sollution

  40. Gino Farisano says:

    Thank you 🙂

Leave a comment

Your email address will not be published. Required fields are marked *