Unity file storage and reading and writing

I recently made a small project and encountered a problem. It felt classic, so I wanted to write it down, hoping to help others. The error of the
problem is this.....
I/Unity ( 8298): NullReferenceException: Object reference not set to an instance
of an object
I/Unity ( 8298): at Heathwork.Update () [0x00000] in <filename unknown>:0
Heathwork is a script component mounted on the gameobject, and it has always been tested on Unity OK, but it doesn't work on the phone. I
keep reporting this error. After a lot of inquiries, I found out that it turned out that I used a configuration file on Unity and put it under /assets/data
. I can't read this file. I used this file in the start of Heathwork, so Heathwork was not instantiated successfully,
so the instance that did not reference the object to the object will be reported during update. So I went to check the packaging mechanism of unity, and summarize
here the resource packaging process of 1.unity (5.x)
1.1 The only API
calls buildpipeline.BuildAssetBundles, the engine will automatically batch package according to the assetbundleName
property of the resource, and automatically build Dependencies between bundles and resources
1.2 Packaging
rules An abName can be set at the bottom of the resource inspector interface, and each abName (including road strength) corresponds to one
Bundle, that is, resources with the same abName will be placed in a Bundle. If the resources come with different abNames
, a dependency will be established with them to avoid redundancy and
support incremental publishing, that is, when the content of the resource is changed and re-released When packaging, bundles with unchanged content are automatically skipped.
1.3 Newly packaged options
Under 5.x, three options are enabled by default (completeAssets, used to ensure the completeness of the resource list, collectDependencies
, used to collect dependencies of resources, DeterministicAssetBundle, used to maintain fixed ids for resources)
ForceRebuildAssetBundle
is used for To force all AssetBundle files to be reprinted;
IgnoreTypeTreeChanges
is used to judge whether to ignore the changes of TypeTree when AssetBundle is updated;
AppendHashToAssetBundleName
is used to add the Hash value after the AssetBundle file name, turn on this option, you can directly judge the contents of which Bundles by the file name It has been updated
(under 4.x, it is generally necessary to judge by comparing the binary and other methods, but in some cases, even if the content remains unchanged and repackaged, the binary of the Bundle will change).

1.4 Manifest file
In the folder generated after packaging, each bundle will correspond to a manifest file, which records some information of the bundle,
but this type of manifest is only used in incremental packaging; at the same time, the root directory will also Generate a manifest file with the same name and its corresponding Bundle file,
Through this Bundle, an AssetbundleManifest object can be obtained at runtime, and all Bundles and their respective dependent Bundles can be obtained through the interface provided by this object.

1.5 Variant parameters
At the bottom of the resource's Inspector interface, in addition to specifying abName, you can also specify Variant behind it. When packaging, Variant will be added as a
suffix after the bundle name. In Bundles with the same abName and different variants, the resources must be in one-to-one correspondence, and their IDs in the Bundle are also the same,
so that they can replace each other.
https://blog.uwa4d.com/archives/ABtopic_2.html
2. File structure under the Unity project
2.1 GUID and fileID (local ID)
   Unity will create a meta file for each resource imported into the Assets directory, in the file The GUID is recorded, and the GUID is used to record the reference relationship between resources.
There is also fileID (local ID), which is used to identify the resource inside the resource. Dependencies between resources are determined by GUID; dependencies within resources are determined by fileID.
2.2 MonoScripts
        A MonoScripts contain three strings: library name, class name, and namespace.
When building a project, Unity collects the individual script files in the Assets folder and compiles them to form a Mono library. Unity compiles the languages ​​in the Assets directory separately, and the same goes for the scripts in the Assets/Plugins directory. C# scripts outside the Plugin subdirectory will be placed in Assembly-CSharp.dll. The Plugin and its subdirectories scripts are placed in Assembly-CSharp-firstpass.all.
These libraries are referenced by MonoScripts and loaded when the program is first started.

2.3 Assets
is the resource folder under the unity editor. All the resources during unity editing will be placed in this folder.
You can use AssetDatabase.LoadAssetAtPath("Assets/x.txt"); to get the resource object
ps: only It is used under the editor. When the project is packaged, it cannot work in the game. The parameter is the full path of the file containing Assets
and
assets under the file suffix Assets need to be saved in special folders or resources that will be referenced by scenes that will be entered into the store. The rest of the resources will not be put into the package,
2.4 Resources
resources are loaded into
        a special folder under Assets, the resources in this folder will be put into the package when the project is packaged, and objects can be obtained through the following methods:
Resources .Load("fileName");

Note: The parameters in the function are relative to the file path and name in the Resource directory, excluding the suffix. The Assets directory can have any path and number of Resources folders. At runtime, the file paths under Resources will be merged.
Example: Assets/Resources/test.txt and Assets/TestFloder/Resources/test.png will be regarded as the same resource when they are loaded using Resource.Load("test"), and only the first object matching the name will be returned . If you use Resource.Load("test"), it will return text.txt;
if there are resources with the same path and name under Resources, you can only get the first object that meets the search conditions using the above method. Use the following methods to get all Eligible objects:
Object[] assets = Resources.LoadAll("fileName");
TextAsset[] assets = Resources.LoadAll("fileName");
After the project is packaged, the resources in the Resource folder will be encrypted and compressed , there will be no Resource folder in the packaged program, so it is impossible to access and update resources through the path,
which means that the package cannot be changed.
2.5 StreamingAssets
Overview The
        StreamingAssets folder is a streaming media folder, and the resources in this folder will not pass through Compressed and encrypted, packaged into the game package intact. When the game is installed, the assets in the StreamAssets file will be moved to the corresponding folder according to the platform. The StreamingAssets folder is read-only on Android and IOS platforms.
    You can use the following function to get the StreamingAssets folder path on different platforms:
Application.streamingAssetsPath
    Please refer to the equivalent path of the StreamingAssets folder on the following platforms. Application.dataPath is the program installation path. The path under the Android platform is special, please pay attention to the prefix of this path, which is unnecessary in some resource reading methods (AssetBundle.LoadFromFile, see below)
Application.dataPath+"/StreamingAssets"//Windows OR MacOS
Application.dataPath+ "/Raw" //IOS
"jar:file://"+Application.dataPath+"!/assets/" //Android
can have read and write permissions in pc and mac, but the mobile terminal only supports read operations
ps: also You can directly create other folders under Assets and they will also be entered into the project and accessed using application.datapath, but there is no access permission
on the mobile side! ! ! !

2.6 AssetBundle
overview
        AssetBundles let you stream additional assets via the WWW class and instantiate them at runtime. AssetBundles are created via BuildPipeline.BuildAssetBundle.
AssetBundle is a file storage format supported by Unity, and it is also the official recommended way of resource storage and update by Unity. Assets can be compressed, packaged in groups, loaded dynamically, and updated hot.
But AssetBundle cannot hot-update Unity scripts because it needs to be compiled at package time.
Its location is just when you click on a perfab. The bottom one in the inspector is the assetBundle.
Summary:
1.Resources The package will be entered, but it will be encrypted and cannot be changed. It can store some fixed configuration files through
Resources .Load("fileName"); Or use textAsset to drag into the script and use
2. Put files directly in Assets and
use application.dataPath+"fileName" to read but this is not accessible on the mobile side
3. StreamingAssets
are in the project After creating this folder in ,
you can use Application.streamingAssetsPath to read files or Application.dataPath to read
Application.dataPath If you use it, you must distinguish the platform path
#if UNITY_ANDROID //Android 
string filepath= "jar:file:/ /" + Application.dataPath + "!/assets/"+"Filename"; 
#elif UNITY_IPHONE //iPhone 
string filepath=Application.dataPath + "/Raw/"+"Filename"; 
#elif UNITY_STANDALONE_WIN || UNITY_EDITOR //windows platform and web platform 
string filepath = "file://" + Application.dataPath + "/StreamingAssets/"+"Filename"; 
#end
The experimental result is that only www can read IO Unable to read the content on the mobile phone
4. Use Application.persistentDataPath to operate the file (recommended)
This file is stored in the mobile phone sandbox and cannot be found in the project.
After downloading the file from the server on the mobile terminal, save it in this file and compare it with md5 Download and update new resources
If there is no server, it can be read locally in the form of a file stream and then written to Application.persistentDataPath, and
then read and operate the file ps through Application.persistentDataPath
: Any file operation can be performed on the mobile terminal, and IOS will be icloud backup

5.Application.temporaryCachePath
operates in the same way as Application.persistentDataPath but cannot be backed up by icloud


The above are all theoretical parts.
void Start () {
		text = (TextAsset)Resources.Load ("test2");
		testtxt = text.text;
		this.gameObject.GetComponent<Text> ().text = testtxt;
	}

	testtxt = text.text;
		this.gameObject.GetComponent<Text> ().text = testtxt;

public TextAsset text;
	public string testtxt;
	// Use this for initialization
	void Start () {

		//string path = Application.streamingAssetsPath+"/test3.txt";
		//Or use the following filepath is also possible
		#if UNITY_ANDROID //Android  
			string filepath= "jar:file://" + Application.dataPath + "!/assets/"+"/test3.txt";  
		#elif UNITY_IPHONE  //iPhone  
			string filepath=Application.dataPath + "/Raw/"+"/test3.txt";  
		#elif UNITY_STANDALONE_WIN || UNITY_EDITOR //windows platform and web platform  
			string filepath = "file://" + Application.dataPath + "/StreamingAssets/"+"/test3.txt";  
		#endif

		testtxt = Loadfile(filepath);
		this.gameObject.GetComponent<Text> ().text = testtxt+"  "+filepath;
	}
	
	// Update is called once per frame
	void Update () {
		
	}
	public string Loadfile(string path){
		StreamReader sr = null;
		try{
			sr = File.OpenText(path);

		}catch(Exception e){
			return null;

		}
		string line;
		//The character segmentation will not be done, you can use sr.ReadLine();
		line = sr.ReadToEnd ();
		sr.Close ();
		sr.Dispose ();
		return line;
	}


public TextAsset text;
	public string testtxt;
	// Use this for initialization
	void Start () {
		#if UNITY_ANDROID //Android  
			string path = Application.streamingAssetsPath+"/test4.txt";
		#elif UNITY_STANDALONE_WIN || UNITY_EDITOR //windows platform and web platform  
			string path ="file://"+ Application.streamingAssetsPath+"/test4.txt";
		#endif

		StartCoroutine (readwww (path));
	}
	
	// Update is called once per frame
	void Update () {
		
	}
	IEnumerator readwww(string path){
		//Debug.Log (path);
		WWW www = new WWW (path);
		yield return www;
		testtxt = www.text;
		//Debug.Log ("!!!"+testtxt);
		this.gameObject.GetComponent<Text> ().text = testtxt+path;
	}
	public string Loadfile(string path){
		StreamReader sr = null;
		try{
			sr = File.OpenText(path);

		}catch(Exception e){
			return null;

		}
		string line;
		//The character segmentation will not be done, you can use sr.ReadLine();
		line = sr.ReadToEnd ();
		sr.Close ();
		sr.Dispose ();
		return line;
	}

public TextAsset text;
	public string testtxt;
	// Use this for initialization
	void Start () {
		string txt = "Test phone sandbox read and write";
		string path = Application.persistentDataPath+"/test5.txt";
		write (path, txt);
		testtxt = Loadfile (path);
		this.gameObject.GetComponent<Text> ().text = testtxt+path;
	}
	
	// Update is called once per frame
	void Update () {
		
	}
	public void write(string path,string text){
		StreamWriter sr = null;
		FileInfo file = new FileInfo (path);
		if (!file.Exists) {
			sr = file.CreateText ();
		}else{
			sr = file.AppendText ();
		}
		sr.Write (text);
		sr.Close ();
		sr.Dispose ();
	}
	public string Loadfile(string path){
		StreamReader sr = null;
		try{
			sr = File.OpenText(path);

		}catch(Exception e){
			return null;

		}
		string line;
		//The character segmentation will not be done, you can use sr.ReadLine();
		line = sr.ReadToEnd ();
		sr.Close ();
		sr.Dispose ();
		return line;
	}

Here are the results of the core code in the five modes after running. The
second picture is the result of running on the mobile phone.
I also uploaded the project file. If you are interested, you can download it.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326224932&siteId=291194637