{"id":13662160,"url":"https://github.com/ByronMayne/UnityIO","last_synced_at":"2025-04-25T06:31:48.365Z","repository":{"id":43623956,"uuid":"71658190","full_name":"ByronMayne/UnityIO","owner":"ByronMayne","description":"An easy to use API that allows you to manipulate files inside of Unity without the headache of using AssetDatabase.","archived":false,"fork":false,"pushed_at":"2017-06-13T01:40:40.000Z","size":4240,"stargazers_count":70,"open_issues_count":1,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-22T18:12:02.476Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ByronMayne.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-10-22T18:33:46.000Z","updated_at":"2025-02-02T10:32:58.000Z","dependencies_parsed_at":"2022-09-13T11:01:40.901Z","dependency_job_id":null,"html_url":"https://github.com/ByronMayne/UnityIO","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ByronMayne%2FUnityIO","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ByronMayne%2FUnityIO/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ByronMayne%2FUnityIO/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ByronMayne%2FUnityIO/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ByronMayne","download_url":"https://codeload.github.com/ByronMayne/UnityIO/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250767386,"owners_count":21483970,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T05:01:50.926Z","updated_at":"2025-04-25T06:31:48.357Z","avatar_url":"https://github.com/ByronMayne.png","language":"C#","funding_links":[],"categories":["C\\#","Game Development"],"sub_categories":["Unity Engine: Resources"],"readme":"[![Gitter Chat](https://img.shields.io/badge/Gitter-Join%20Chat-red.svg)](https://gitter.im/UnityIO/Lobby)\n[![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](https://github.com/ByronMayne/UnityIO/blob/master/LICENSE)\n\n\n\n\n# Unity IO\n\n### Description\nUnity IO is made to try to remove the pain of working with Unity's file system. For anyone who has done extended work has figured out Unity makes this a huge pain. All the functionality you need is spread across multiple classes including [FileUtil](https://docs.unity3d.com/ScriptReference/FileUtil.html), [AssetDatabase](https://docs.unity3d.com/ScriptReference/AssetDatabase.html), [Resources](https://docs.unity3d.com/ScriptReference/Resources.html), [File](https://msdn.microsoft.com/en-us/library/system.io.file(v=vs.110).aspx), [FileInfo](https://msdn.microsoft.com/en-us/library/system.io.fileinfo(v=vs.110).aspx), [Path](https://msdn.microsoft.com/en-us/library/system.io.path(v=vs.110).aspx), [Directory](https://msdn.microsoft.com/en-us/library/system.io.directory(v=vs.110).aspx), [Directory Info](https://msdn.microsoft.com/en-us/library/system.io.directoryinfo(v=vs.110).aspx), ect. \n\n### Goals\n\n * Simple to use API.\n * Support Unity's meta files.\n * Allow for complex chaining with conditional execution.\n * Allow of loading, creating, destroying of Unity Assets.\n\n\n\n## Directory Basics\nUnityIO works with the Unity asset path so all paths start from the ```Assets/``` folder. To start using UnityIO in your classes you must include the namespace ```UnityIO```\n\n### Creating a Directory\n``` csharp\n/// \u003csummary\u003e\n/// Creates a directory the root of our project\n/// \u003c/summary\u003e\npublic void CreatingRootDirectory()\n{\n    IO.Root.CreateDirectory(\"Favorite Animals\");\n}\n```\n```IO.Root``` is the ```/Assets``` folder at the root of your Unity project. In the example above we are asking UnityIO to create a new folder called Favorite Animals at ```Assets/Favorite Animals```. \n``` csharp\n/// \u003csummary\u003e\n/// A few more ways to create folders\n/// \u003c/summary\u003e\npublic void CreateNestedCatFolder()\n{\n    // Create in a chain.\n    var catsFolder1 = IO.Root.CreateDirectory(\"Favorite Animals\").CreateDirectory(\"Cats\");\n    \n    // Break it down into two parts.\n    var animals = IO.Root.CreateDirectory(\"Favorite Animals\");\n    var catsFolder2 = animals.CreateDirectory(\"Cats\");\n    \n    // Do it in one step.\n    var catsFolder3 = IO.Root.CreateDirectory(\"Favorite Animals/Cats\");\n    \n    // Do it in one step with the helper.\n    var catsFolder4 = IO.Root.CreateDirectory(\"Favorite Animals\" + IO.PATH_SPLITTER + \"Cats\");\n}\n```\nThis code is doing the same above but it will also create a subdirectory called Cats. When you want to create subdirectories you have a few ways to do it. It all really depends how you want to do it but they all have the same result. If the code were to run above only two folders would be created and all of the variables would point to the same one.\n\n#### Notes\n* The paths \u003cb\u003edo not end\u003c/b\u003e with a leading slash ```/```. Unity has a habit of switching this up but UnityIO will throw a planned exception letting you know. \n* All directories are split using the ```/``` character. You can use the constant ```IO.PATH_SPLITTER```.\n\n\n### Destroying a Directory\nWell it turns out all our hard work we did was for nothing! Turns out you hate cats, don't worry I get it you are a monster. I will not judge lets destroy that directory.\n```csharp\n/// \u003csummary\u003e\n/// Let's blow some things up\n/// \u003c/summary\u003e\npublic void Destroy()\n{\n    // Get our directory and nuke it\n    IO.Root[\"Favorite Animals\"].GetDirectory(\"Cats\").Delete();\n\n    // Delete our cats folder. \n    IO.Root.DeleteSubDirectory(\"Favorite Animals/Cats\");\n}\n```\nAs with creating folder there are more than way to do things. The first example we are just finding our cats directory and tell it to kill itself with the ```Delete()``` function. The second way we are starting from the root and it will look for  the subdirectory at the path we sent in. The ```DeleteSubDirectory(string name)``` just calls ```Delete()``` on the folder behind the scenes. \n\nTake that cats!\n\nYou might be asking what happens if you tell it to delete a directory that does not exist.\n\n```scharp\n/// \u003csummary\u003e\n/// This should do nothing.\n/// \u003c/summary\u003e\npublic void DeleteSomethingNotReal()\n{\n    IO.Root[\"Favorite Animals\"].GetDirectory(\"Dogs\").Delete(); // Does not exist\n}\n```\nIn this case you well get an ```System.IO.DirectoryNotFoundException``` since you are trying to delete something that is not there. This can be super helpful but what if you only want to delete it if it does exist? \n```csharp\n/// \u003csummary\u003e\n/// We should play it safe.\n/// \u003c/summary\u003e\npublic void ValidateBeforeDelete()\n{\n    var favoriteAnimals = IO.Root[\"Favorite Animals\"];\n\n    if(favoriteAnimals.SubDirectoryExists(\"Dogs\"))\n    {\n        favoriteAnimals.DeleteSubDirectory(\"Dogs\");\n    }\n}\n```\nAbove you can see we are checking to see if it exists before deleting it. This way we will not get an exception which is awesome. However this can become annoying to check every element has to be checked along the way. The other more usable way to do this would be to use a conditional. \n```scharp\n/// \u003csummary\u003e\n/// We should play it safe and make it easy\n/// \u003c/summary\u003e\npublic void EasyValidateBeforeDelete()\n{\n    IO.Root[\"Favorite Animals\"].IfDirectoryExists(\"Dogs\").Delete();\n}\n```\n\"Wait what does ```IfDirectoryExists()``` do?\" Well I am glad you asked. One of the really cool features of UnityIO is conditionals. In this case if the directory exists the function ```Delete()``` will be called on the Dogs directory. If it does not exist the function will take no effect. \n```csharp\n/// \u003csummary\u003e\n/// Look at the length of that things!\n/// \u003c/summary\u003e\npublic void ILikeChains()\n{\n    IO.Root[\"Favorite Animals\"].IfDirectoryExists(\"Dogs\").IfDirectoryExists(\"With Four Legs\").IfDirectoryExists(\"Who stink\").Delete();\n}\n```\nIn this case only the first folder exists so the first conditional will return a NullFile class which has all the same functions but none of them have any effect. So that way your code will execute only as far as it can get. You don't have to worry about null checking since the code can't break if a file is missing. You have the power to chain as many of these as you want. \n ``` csharp\n/// \u003csummary\u003e\n/// Find, Create, and Destroy\n/// \u003c/summary\u003e\npublic void CreateAndDestroy()\n{\n    IO.Root[\"Favorite Animals\"].IfDirectoryExists(\"Dogs\").CreateDirectory(\"Delete Me\").Delete(); \n}\n ```\n\n#### Notes\n* You can delete your whole project with ```IO.Root.Delete()```. I don't suggest you do that. \n\n### Renaming a Directory\nSometimes there are cases where you want to rename you directory. To do this is pretty simple.\n```csharp\n/// \u003csummary\u003e\n/// Pick any name that is valid\n/// \u003c/summary\u003e\npublic void RenameDirectory()\n{\n    IO.Root[\"My Dir\"].Rename(\"Super Dir\");\n}\n```\nThis is all you have to do just make sure you don't include any ```/``` in your name as they are already preserved. If a directory already exists with that name this function will throw an ```DirectoryAlreadyExistsException()```, so make sure you check before you try to create one.\n\n### Duplicate a Directory\nAs with moving duplicate is just as easy.\n```CSHARP\npublic void DuplicateADirectory()\n{\n    var cheeseDrive = IO.Root[\"Types of Cheese\"];\n    // Creates a copy\n    cheeseDrive.Duplicate();\n    // Creates a copy with a set name\n    cheeseDrive.Duplicate(\"Other Types of Cheese\");\n}\n```\nThe ```cheeseDrive.Duplicate()``` function will create a new copy of the cheeseDrive and all it's contents. It will then rename that drive with a number on the end to make it unique. If you want more control you can just use the overloaded function to pick a valid name. If the name is already taken you well get an exception. \n## File Basics\n\nAs with working with directories working with files is just as easy. UnityIO does it's best to try to make things as painless as possible. \n\n### Anatomy a File\nUnityIO has two interfaces that are used when dealing with files. The first one is ```IFile``` and ```IFiles```. Ifiles is simple an extension of ```IList\u003cIFile\u003e``` with some extended functionality that I will cover later. IFile is the one you will be dealing with the most. IFile is implemented by ```File.cs``` and ```NullFile.cs```.\n### Getting a File\nTo get a file does not require to much work. In the example below we go to the directory we want and ask for all the files in there.\n``` csharp\n// Normally we just use var for the return types but these examples we are using\n// the interface types to make it more clear so we have to include the following.\nusing UnityIO.Interfaces;\n\n/// \u003csummary\u003e\n/// A simple example of getting all files from a folder called resources \n/// at 'Assets/Resources'\n/// \u003c/summary\u003e\npublic void GetResourceFiles()\n{\n    // Get our directory\n    IDirectory resourcesDirectory = IO.Root[\"Resources\"];\n    // Get all files.\n    IFiles files = resourcesDirectory.GetFiles(); \n}\n```\nThe code above looks for the directory ```Assets/Resources``` and returns all files that are in there. This code returns us back an ```IFiles``` which we can then just loop over to grab each file one by one. \n```csharp\n// Get our directory\nIDirectory resourcesDirectory = IO.Root[\"Resources\"];\n// Get all files.\nIFiles files = resourcesDirectory.GetFiles(); \n// iterate over our files and print their names\nfor(int i = 0; i \u003c files.Count; i++)\n{\n    Debug.Log(files[i].Name);\n}\n```\nAbove we are using our IFiles and printing the names to the UnityEngine.Debug console. Lets say we wanted\nto also get all files recursively we can do that too.\n```csharp\npublic void GetFilesRecursively()\n{\n    // Get our directory\n    IDirectory resourcesDirectory = IO.Root[\"Resources\"];\n    // Get all files recursively\n    IFiles files = resourcesDirectory.GetFiles(recursive:true);\n}\n```\n\n#### Searching for files\nSometimes we also might want to only select files if they match a name. UnityIO under the hood uses System.IO to find files\nso it has the ability to use two unique wild cards. ```*```(asterisk) means Zero or more characters in that position. ```?``` (question mark) means Zero or one character in that position.\nThis search can not use Unity's tags like ```t:```, ```l:```, or ```ref:```.  \n\nBelow are a few examples of some search functions.\n```csharp\n// Returns every asset with 'Player' in it's name. \nvar playerFiles = IO.Root.GetFiles(\"*Player*\");\n```\n``` csharp\n// Get everything named with 'Player' and '.anim' extension\nvar playerAnimations = IO.Root.GetFiles(\"*Player*.anim\");\n```\n```csharp\n// get everything named 'Player' with one extra char maybe an 's'\nvar playerChar = IO.Root.GetFiles(\"Player?\");\n```\n\n```GetFiles()``` has a few different overrides that lets you combine both the search filter and the recursive bool.\n\nNotes:\n * At one point I might add Regex searches to this feature but I am not sure if that is overkill. Let me know with feedback if you would like that feature. \n * You might notice that you don't have the open to filter by Unity types. This was done so the code does not have to be rigid. I just did not want to have to write a huge case statement for all valid Unity types an extensions that match.\n * When you call ```GetFiles``` the assets themselves have not been loaded into memory we are only working with the paths.\n\n### Deleting a File\nOnce you have your file you might just want to be able to delete it. \n```csharp\n/// \u003csummary\u003e\n/// Grabs all the files in the root directory and deletes them. \n/// \u003c/summary\u003e\npublic void DeleteAFile()\n{\n    // Get all our files. \n    var files = IO.Root.GetFiles();\n    // Loop over them all and delete them\n    for (int i = 0; i \u003c files.Count; i++)\n    {\n        // Delete the file.\n        files[i].Delete();\n    }\n}\n```\nThis is great but lets say you want to delete a file only if it exists. Well just like the IDirectory class IFile has the option to only do tasks if a condition is met.\n```csharp\n/// Only delete our file if it exists. \nIO.Root.IfFileExists(\"DeleteMe.txt\").Delete(); \n```\nAs expected this will only delete the file if it happens to exist on disk and otherwise have no effect. \n\nNotes:\n* All deletion uses AssetDatabase so the meta files are cleaned up too. \n* The files get deleted synchronously so if you check if it exists in the next line of code it will be cleared.  \n* \n### Renaming a File\nSometimes you just want to change the file you are working with to do that try the following code. \n\n``` csharp\n// Get the file we want to use.\nIFile fileToRename = IO.Root.GetFiles(\"DeleteMe.txt\").FirstOrDefault();\n// Rename it\nfileToRename.Rename(\"DontDeleteMe.txt\");\n```\nYou might also notice that we used the function ```FirstOrDefault``` this is a function on ```IFiles``` the returns the first file in the list or our null file (which just takes no actions. Read about it below). One thing you should take note of is ```Rename()``` is for renaming and not moving files, use ```Move()``` for that or an exception will be thrown.\n### Moving a File\nMoving a file is the same as renaming but you can move the file outside it's current directory. \n```csharp\n// Get the file we want to use.\nIFile fileToMove = IO.Root.GetFiles(\"DeleteMe.txt\").FirstOrDefault();\n// Move it\nfileToRename.Move(IO.Root[\"Resources\"].Path);\n```\nThis will take the ```Assets/DeleteMe.txt``` and move it too ```Assets/Resources/DeleteMe.txt```. If a file already exists in that directory it will be given a unique name by append incrementing numbers to the end.\n\n### Utility\nThere are a few helper functions that come bundled with UnityIO that can be quite useful.\n\n#### Root\n```csharp\nIO.Root\n```\nUsed in many of the example above this is a shorthand to allow you to grab the root of the current Unity project you are working in. \n\n#### Convert Paths\nUnityIO uses all local Unity asset paths under the hood ie. ```Assets/blah/blah.png``` but if you are going to be interacting with any of C#'s System.IO libraries you will need the full system path. You can get this in a few ways.\n``` csharp\n// Gets the full system path of a file instance\nstring fileSystemPath = IFile.systemPath;\n\n// Gets the full system path of a directory instance\nstring directorySystemPath = IDirectory.systemPath;\n```\nThis is very useful if you already have created instances for ```IFiles``` and ```IDirectories``` but if you just have a raw path to convert this is not useful. To convert raw paths you can use the following.\n```csharp\npublic void GetSystemPath(string assetPath)\n{\n    // Convert our asset path to a system path \n    return IO.AssetPathToSystemPath(assetPath); \n}\n```\nor the reverse\n\n```csharp\npublic void GetAssetPath(string systemPath)\n{\n    // Convert our system path to our asset path. \n    return IO.SystemToAssetPath(systemPath); \n}\n```\nBoth of these can be used without creating any new classes. Each of these functions checks it's input to verify if it's valid before trying to convert them. If the input is not valid an exception will be thrown so it's best to make sure you are not sending in null or empty strings. \n\n## Meta\n\nHandcrafted by Byron Mayne [[twitter](https://twitter.com/byMayne) \u0026bull; [github](https://github.com/ByronMayne)]\n\nReleased under the [MIT License](http://www.opensource.org/licenses/mit-license.php).\n\nIf you have any feedback or suggestions for UnityIO feel free to contact me. \n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FByronMayne%2FUnityIO","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FByronMayne%2FUnityIO","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FByronMayne%2FUnityIO/lists"}