How does unity use the file stream to read resources under streamingassets


Purpose: to read a section of bytes specified in the file under streamingassets

Known: the starting position in the file and the length to be read

1. Read under Android

1.1 FileStream of c# cannot be used directly, and reading failed

var buffer = new byte[size];
FileStream stream = File.OpenRead(path);
stream.Read(buffer , pos, size);

report errors:

IsolatedStorageException: Could not find a part of the path “/jar:file:/data/app/!/assets/xxx.pack”.

1.2 you can use unity native interface to interact with Android

Main process:


public class XXXPlugin extends UnityPlayerNativeActivity {
    protected AssetManager assetManager;
	protected void onCreate(Bundle savedInstanceState) {
		assetManager = getAssets();
	//Return byte array
	public byte[] LoadBytes(String path,int offset,int len)
         //It can be cached without opening it every time
         InputStream inputStream =;
         try {
                 byte buf[] = new byte[len];
                //Pay attention to the reliability of skip and read
                 return buf;
		catch (IOException e) {
				Log.v ("unity", e.getMessage());
		return null;

Pay attention to the reliability of skip and read. Each call may not return the correct length and may need to be called many times.

Refer to how does the skip method in InputStream work


            public static byte[] read_streamingpath_bytes(string path,IntPtr ptr, int pos, int size) 
                using (AndroidJavaClass cls = new AndroidJavaClass("com.XXX.XXXPlugin";) ) 
                   AndroidJavaObject  m_AndroidJavaObject = cls.GetStatic<AndroidJavaObject>("mainActivity");
                    byte[] s = m_AndroidJavaObject.Call<byte[]>("LoadBytes", path, pos, size);
                    return s;
                return null;

This method is to allocate memory in Java.

1.3 more flexible method: using JNI, you can transfer the pointer from c# to C++

Generate library libnativelib in Android studio So file, refer to nativereadbytes


#include "com_XXX_NativeHelper.h"
#include <android/asset_manager_jni.h>
#include <android/asset_manager.h>
#include <string>
#include <jni.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
static AAssetManager *assetManager = nullptr;
JNIEXPORT void JNICALL Java_com_XXX_NativeHelper_SetAssetManager
        (JNIEnv *env, jobject jobj, jobject jassetManager) {
    assetManager = AAssetManager_fromJava(env, jassetManager);
JNIEXPORT int32_t JNICALL ReadAssetsBytesWithOffset(uint32_t pathKey, char* fileName, unsigned char** result, int32_t offset, int32_t length){
    if(assetManager == nullptr){
        return -1;
    AAsset* asset = asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN);
    if(asset == nullptr){
        return -1;
    off_t size = AAsset_getLength(asset);
    if(size > 0){
        try {
            AAsset_seek(asset, offset, SEEK_SET);
            AAsset_read(asset, *result, length);
        }catch (std::bad_alloc){
            *result = nullptr;
            return -1;
    return (int32_t)length;
#ifdef __cplusplus


public class XXXPlugin extends UnityPlayerNativeActivity {
 protected void onCreate(Bundle savedInstanceState) {
  mainActivity = this;
        //Set assetmanager to be used in C + +
public class NativeHelper {
    public static native void SetAssetManager(AssetManager assetManager);


 public class ReadNativeByte
        public static extern int ReadAssetsBytesWithOffset(uint pathKey,string name, ref IntPtr ptr, int offset, int length);

2. Reading under IOS

It can be read directly in c# and streamasetting only has read permission. Use openread

byte[] bytes = new byte[len];
FileStream stream = File.OpenRead(path);
stream.Seek(offset, SeekOrigin.Begin);
stream.Read(bytes, 0, len);

Supplement: organize the storage paths of various read-write folders on the mobile platform in the unit, such as the file paths of various folders such as streamingassets on various platforms

1: Use fewer resources folders

//Resource unloading
     *  Resources. Unloadasset (obj): unloading non GameObject type resources will unload the loaded resources and their clones in memory.
        Destroy (obj): only used to unload clones of GameObject type resources.
        Destroy immediately (obj): unloading GameObject type resources will unload the loaded resources and their clones in memory. However, this method can only be used in non editing mode, otherwise an error will be reported and the prompt will be changed to destroy immediately (obj, true). However, using this function in editing mode will delete the original assets in the folder.


In the mobile terminal, it is only readable and cannot write data. It is mainly used to store binary files.

//The paths of these two folders under Android are the same 
    //Application.streamingAssetsPath = jar:file:///data/app/!/assets/  == "jar:file://"+Application.dataPath+"!assets/"
    //Application.dataPath+"!assets/" = /data/app/!assets/
    //Under IOS
    //Application.dataPath + "/Raw/" == @"file:///" + Application.streamingAssetsPath + "/"
    //Editor WIN 
    //@"file:///" + Application.streamingAssetsPath + "/"
    //"file:///" + Application.dataPath + "/StreamingAssets" + "/"
private string path = string.Empty;
    public string GetSAPath()
        //Android platform plus file name
        path =  Application.streamingAssetsPath + "/"
        path = @"file:///" + Application.streamingAssetsPath + "/";
       path =  @"file:///" + Application.streamingAssetsPath + "/";
        return path;


This directory is readable and writable. It is generally stored in local checkpoints, etc

This directory does not exist before packaging for direct use for archiving. It does not exist until the application is installed on the mobile phone.

The file is stored in the mobile phone sandbox because it cannot be stored directly,

1. Directly download and save to this location through the server, or download and update new resources through MD5 code comparison

2. If there is no server, it can only be read and written to the application indirectly through file stream Under the persistentdatapath file, and then through

Application. Persistent datapath to read the operation.

Note: files can be operated arbitrarily on PC / Mac, Android, iPad and iPhone. In addition, things in this directory on IOS can be backed up automatically by icloud.

Application.persistentDataPath + "/tempDic", "testXml"

Corresponding storage path

Windows store app:

application. Persistentdatapath points to% userprofile% \ appdata \ local \ packages \ < product name > \ localstate

ios:application. Persistentdatapath points to / var / mobile / containers / data / application / < guid > / documents

android:application. Persistent datapath points to the / storage / emulated / 0 / Android / data / < package name > / file on most devices (some old phones may point to the location on the SD card, if any). This path uses Android content. context. Getexternalfilesdir parsing


The operation of the file is the same as above, but this attribute is used to return a cache directory of temporary data (it will not be backed up and the cache will be cleared)

The above is my personal experience. I hope I can give you a reference, and I hope you can support developpaer. If there are mistakes or not fully considered, please don’t hesitate to comment.