Search Unity

[RELEASED] File Management: Easy way to save and read files.

Discussion in 'Assets and Asset Store' started by jemonsuarez, Jul 29, 2016.

  1. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Requires Unity 5.3.5 or higher.
    File Management: The easiest way to save and read files for Unity.

    Are you trying to build your project for a new platform and your actual code is not saving files correctly?
    Do you have compatibility issues between plug-ins?
    Are you using some plug-ins that has known problems on store approvals?
    Do you need a fast file management tool for your cross-platform application?
    Are your “save” solutions hard to manage and put to work?

    So this is for you, the File Management asset uses only a few scripts to let you read and write files on almost every platform supported by Unity engine.
    File Management doesn’t make use of plug-ins, neither specific compilation requirements or settings, just import, code, and deploy.
    FileManagement is designed to simplify the developer’s life, no need to read extensive and complex documentation.
    If you are using PlayerPref, so you already know how to use FileManagement, then you can learn all its extended functionality.

    Advantages:
    - Full source code available.
    - No plug-ins needed: ensures stability for your other plug-ins, completely avoids conflicts and ensures on-line store approval.
    - Just switch platform and deploy, no further configurations needed at all.
    - Includes a functional File browser for all supported platforms.
    - Includes a complete INI File parser/manager for all supported platforms.
    - Includes Open WAV Parser fully integrated.
    - Unified API (no specific interfaces), compatible with mobile, standalone and web platforms.
    - Unifies PersistentData and StreamingAssets folders as a single drive allowing override files (so there is always a default one).
    - Lists StreamingAssets content and sub-directories on Android and WebGL.
    - WebGL: No server-side code needed, FileManagement accesses the StreamingAssets fodler (StreamingAssets is read-only on all platforms).
    - Fast and lightweight.
    - PlayerPrefs are not used at all, this is the perfect replacement (even WebGL).
    - Just rename PlayerPrefs with FileManagement in your actual code and you are done.
    - Every save call actually writes to disk, no need of PlayerPrefs.Save() functionality, there is no risk of data loss.
    - Built-in XOR or AES encryption (AES not supported in Windows Store/Phone).
    - Save and read any C# type, through useful unified interfaces.
    - Save and read encrypted binary data easily.
    - Full documentation and easy to understand examples.
    - Designed to be coded easily, not very advanced coding skills needed.
    - Thread-safe design for most methods.
    - Basic binary serialisation tools. You can also use your own serialisation solution and save with FileManagement (even XML, JSON, INI, CSV, etc.).

    Supported platforms are:
    - WebGL.
    - Windows.
    - Mac OSX.
    - Linux.
    - ios (Xcode project).
    - Android.
    - Windows Store (Visual Studio 2019 project).
    (Right click and "save as..." on each link to download the test applications)

    If you need any extra information or functionality please don’t hesitate on contacting me:
    jmonsuarez@gmail.com

    Please check the Documentation
     
    Last edited: Feb 7, 2021
    cl9-2 likes this.
  2. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Version 1.1 now includes encryption for images and sprites (You can read and write encrypted image files).

    Code (CSharp):
    1. FileManagement.SaveJpgTexture(rImage.texture, "capture.jpg", 75, true);
    Also includes the AES encryption method for almost all platforms (not available for Windows Phone platforms).

    (Please add @jemonsuarez to your message)
     
    Last edited: Sep 20, 2016
  3. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    I am deciding on File IO assets and am researching the various solutions. Yours looks interesting and fairly simple to use. I need to load .csv and fbx files at runtime by the User from their choice of directory location. I also need to save .txt, .xml and .csv files and probably a few jpeg or png files to or from disk at the Users choice as well as the tweaked Unity scene at the persistentDataPath. Can you speak to the capabilities of your asset in regards to general file IO?
     
  4. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi, thanks for asking for the product.
    Regarding the CSV file format, it's comma separated, so you can read it using this:
    Code (CSharp):
    1. // Read strings separated by ';':
    2. FileManagement.ReadArray<string>("file.csv", ';');
    3.  
    4. // Read floats separated by 'TAB':
    5. FileManagement.ReadArray<float>("file.csv");
    This will return an array of strings or floats depending on the conversion you requested (all C# types included, and some Unity types too, please check documentation).

    To save a CSV file you need this:
    Code (CSharp):
    1. string[] myValues = { "one", "two", "three", "four", "five" };
    2. // This will save the array as a 'TAB' separated CSV file:
    3. FileManagement.SaveArray("array.csv", myValues);
    Please note that FileManagement saves arrays in the same format as CSV files using the 'TAB' character as default separator.
     
  5. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Regarding FBX files, you can read the file content as a byte array or a string to be processed, but FileManagement doesn't imports 3D models at run-time.
    I will add the suggestion to the TODO list!
     
  6. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    You can pick any "accessible" file and read it using the FIleBrowser prefab included within the package (Same files may have the access denied by the operative system).
    You have also the basic tools to manage files as in any OS window.
    Please try the new version of the FileBrowser in this FileManagement WebGL build to see it's capabilities.
     
  7. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Regarding TXT and XML files you can use this:
    Code (CSharp):
    1. string content = "Hi, this is the file content";
    2. // Saves the string as a TXT file:
    3. FileManagement.SaveFile("MyFile.txt", content);
    Please note that FIleManagement isnot a XML parser, you must use your own solution depending on your needs. Most XML interpreters returns strings, so you can integrate them easily.
    To read backa file you use:
    Code (CSharp):
    1. string content = FileManagement.ReadFile<string>("MyFile.txt");
    There are also some useful options as encryption, StreamingAssets access and absolute path (data is stored into PersistentData by default).
     
  8. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    OK.. I like the web demo as it does alot of what I need with file types and reloading. I am a bit confused by the File Browser setup. Does the User need to know the initial path and type that in for the browser to navigate to that directory. If so, I have alot of quasi-computer illiterates in the core consumers of the application I am building who will balk at the idea of typing in a directory path..including the folks who hired me to build this for them. I also threw an exception by clicking the icon that seemed to be the save to clipboard button that locked up the webGL player. It would be awesome if you could load and parse fbx models. I have purchased another solution but it is Windows only and still needs a file browser to get to the fbx file location for loading.
     
  9. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    You can read and save images easily, here some examples.
    Import a JPG file:
    Code (CSharp):
    1. Texture2D texture = FileManagement.ImportTexture("image.jpg");
    Import a PNG file:
    Texture2D texture = FileManagement.ImportTexture("image.png");
    You can also import as Sprites as follows:
    Code (CSharp):
    1. Sprite sprite = FileManagement.ImportSprite("image.png");
    You can save texture down to disk in JPG and PNG formats.
    Code (CSharp):
    1. // Save JPG images:
    2. FileManagement.SaveJpgTexture("texture.jpg", renderer.material.mainTexture);  // From texture
    3. FileManagement.SaveJpgTexture("texture.jpg", gameObject.GetComponent<Sprite>().texture);  // From Sprite
    4.  
    5. // Save PNG images:
    6. FileManagement.SavePngTexture("texture.png", renderer.material.mainTexture);  // From texture
    7. FileManagement.SavePngTexture("texture.png", sprite.texture);  // From Sprite
    8.  
     
  10. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    I have a complex .csv parser written with Regex that should handle most any version of a .csv that a CAD system would generate as a schedule.csv. Some are comma delimited, some are tab or | bar delimited. It is a bonus your will write one in a format i can reload. This is handy for my end of saving configs and reloading them.
     
  11. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Can the User store files anywhere they wish and can they navigate there through the browser or do they have to supply the directory path themselves by typing or copy pasting it in? The persistentDataPath will be handy for in-game needs but for saving project notes and comments from other collaborators they may wish to save it to their project folder or anywhere really.
     
  12. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    You don't need to know the file path to be written by the user, those fields are there to let you try the functionality.
    That means you can chose a path to be shown by default and also you can select a path to restrict the access, if needed.

    You can also restrict the access to the PersistentData + StreamingAssets folder. FileManagement shows both as a single drive. FileBrowser will alert you if you try to modify a read only file (from StreamingAssets).

    About the crash you experienced, that's a bug. It happens when you copy and paste a file in the same location, it is fixed in upcoming 1.3 version (not yet released). Sorry.
     
  13. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    You can select the separator of your choice, but the code doesn't detects the separator automatically (I don't even know if that is possible).
    This is the method declaration:
    Code (CSharp):
    1. public static T[] ReadArray<T>(string name, char separator = (char)0x09, bool enc = false, bool checkSA = true, bool fullPath = false)
    So you can set your preferred separator in the second argument, as ';', or '|'.
     
  14. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Guess I won't give them that option:) They won't need it anyways..but get it fixed:) I think I am sold as the other dev is not answering. Funny how support works like that when most of us working folk are under the gun to produce yesterday.
     
  15. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Sure thing, you can set the FileBrowser as "Save" mode, and the user will be prompted to write its own file name and chose the save path at will. Please note that writing files may be not allowed by the operative system in some cases.
    You can set the FileBrowser as "Unrestricted" allowing the user access the drive without restrictions (In Android this feature is awesome).
     
  16. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Thanks for your interest, and don't hesitate on contacting me for more information or help using this package.
    Best luck with your project!
     
  17. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Getting used to it this morning. I have a question. You have a nice method to grba a screencapture and save it. I will be using this for the architectural model that will be loaded..but I need to be able to take a photo with a phone camera of the building site in the real world and save it. Can this be wrenched into your plugin and if so how and where?
     
  18. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi, the camera can be captured in two ways but that depends on your application.
    The screen capture method captures everything on the screen at a given moment, so it will capture the camera and your UI too.
    If you have already connected the camera to a texture, you can save a capture with FileManagement.SavePngTexture() or FileManagement.SaveJpgTexture() using your webcam texture as the source:
    Code (CSharp):
    1. FileManagement.SavePngTexture("capture.png",  gameObject.GetComponent<Renderer>().material.mainTexture);
    You may need to WaitForEndOfFrame before taking the picture.
    Please let me know if that worked.
    You can contact me through email at jmonsuarez@gmail.com.
    Best regards.
     
  19. jprocha101

    jprocha101

    Joined:
    Apr 8, 2015
    Posts:
    134
    Hi @jemonsuarez,

    Are we able to save an AudioClip?

    I have an MP3 I am downloading from AWS S3. It streams in as an array of bytes and I am converting it to an Audio Clip then wish to save for later use.

    Thanks!
     
  20. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi, thanks for asking.
    I think in a few ways you can achieve that:

    1 - If you are receiving an mp3 file as a byte array, you can save it to disk like this:
    Code (CSharp):
    1. FileManagement.SaveRawFile("AudioFile.mp3", audioArray);
    Just make sure you have the full audio content into
    Code (CSharp):
    1. byte[] audioArray
    , or the result will be a corrupted file.

    2 - If you already have an AudioClip with audio in it, you can save the audio array as follows:
    Code (CSharp):
    1.         // Save audio samples:
    2.         AudioSource aud = GetComponent<AudioSource>();
    3.         float[] samples = new float[aud.clip.samples * aud.clip.channels];
    4.         aud.clip.GetData(samples, 0);
    5.         FileManagement.SaveArray("AudioData.samples", samples);
    6.  
    Then read it back like this:
    Code (CSharp):
    1.         // Load audio samples:
    2.         AudioSource aud = GetComponent<AudioSource>();
    3.         float[] samples = FileManagement.ReadArray<float>("AudioData.samples");
    4.         aud.clip.SetData(samples, 0);
    5.  
    This will save the uncompressed audio and may result in a very huge file size.

    3 - If you are streaming a byte array with the audio data, you can save every received chunk to a single file. The "problem" is that data will not be available until streaming ends, and maybe you'll have to delete some headers or footers from the received file chunk.
    So you must execute this in every "receive" event (that depends on your own implementation):
    Code (CSharp):
    1. FileManagement.AddRawData("AudioFile.mp3", fileChunk);
    Just make sure you are receiving a valid file chunk in
    Code (CSharp):
    1. byte[] fileChunk
    or the result will be a corrupted mp3 file (or wav, or ogg, or txt, etc.)

    Please let me know if that is what you need.
    Best regards.
     
  21. jprocha101

    jprocha101

    Joined:
    Apr 8, 2015
    Posts:
    134
    Thank you, @jemonsuarez. This is exactly what I need. Purchased! Will leave a review in a couple of days.
     
  22. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    If you need any help getting started with the package please don't hesitate on contacting me.
    Best luck with your project!!
     
  23. jprocha101

    jprocha101

    Joined:
    Apr 8, 2015
    Posts:
    134
    @jemonsuarez I am receiving these errors when running on android device and attempting to ImportAudio. This works in editor. I am also able to use an android device file explorer app to go to the directory and play the mp3 on device.

    Any thoughts?

    upload_2017-4-20_15-48-15.png
     
  24. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Last edited: Apr 21, 2017
    jprocha101 likes this.
  25. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    I have two questions. What form of scripting do i use to get the FileBrowser to show a list of all logical drives when first opening. The second is how do i filter the files to show only those using our custom extension '.vim'?
     
  26. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @ippdev, the option of filtering that you are asking is already implemented in the upcoming version 1.5. Please send me an email to jmonsuarez@gmail.com to send you the new package.
    About the logic drives listing, there are cross platform issues due to it is supported on standalone builds only (that's the reason why is not included as default).
    You have the FileManagement.ListLogicDrives() method to get them if you want to implement it yourself, or you can request me by email (we can discuss the way you want it to work) and I will be back tomorrow with the solution.
    You have also the new overloaded methods FileManagement.ReadArray() and FileManagement.ReadList() accepting an array of strings as separator for CSV files.
    Best regards.
     
  27. EmeralLotus

    EmeralLotus

    Joined:
    Aug 10, 2012
    Posts:
    1,462
    Nice asset.
    On WebGL, what is the limit of the Indexed Database. Also where is is being saved?
     
  28. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @rocki, in most browsers the limit is up to 1GB (shared between all tabs), but that depends entirely on the browser that you are using.
    Data is being saved into the browser cache, not cookies, and will be deleted when browser data is cleared. This index DB is not controlled by FileManagement, it just uses it to read/write.
    Hope it helps.
    All the best.
     
  29. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    @jemonsuarez I have a large text file I want the user to browse to a directory to store where they can access it later for printing or review etc.. I am not quite getting how to do that by bringing up the FileBrowser instead of just saving to a default location. I have the fileName and fileTextContent and want to allow the user to navigate through the FileBrowser to store it at a location of their convenience.
     
  30. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @ippdev, I've seen that the default name for the destination file is not working correctly, so I'm updating it for you right now.

    To save a file you just have to set the FileBrowser as "save" mode, and it will return the selected save path, then you save by code using that user provided path (it may request overwrite some existing file).
    That's explained in documentation, but if you need help setting up the FileBrowser please don`t hesitate on asking me (Send me an email please at jmonsuarez@gmail.com).

    Please note that saving may be forbidden in some folders if the application doesn't have the right access permissions (specially on SD card for Android builds).

    I will reply you back with the update for the default name (I hope today), and will update in the store asap.
    Best regards and thanks for contacting me.
     
  31. stevenatunity

    stevenatunity

    Joined:
    Apr 17, 2015
    Posts:
    114
    Hi, is it possible to have a look at the latest documentation as I consider a purchase :)
     
  32. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
  33. stevenatunity

    stevenatunity

    Joined:
    Apr 17, 2015
    Posts:
    114
  34. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @ippdev the update (1.6b1) is ready and implements a new parameter for FileBrowser settings. This new parameter allows to set a default item name which will be selected automatically (its use is not mandatory) in "normal" mode and also sets the default save name in "save" mode.

    The way you create a FileBrowser is as follows:
    Code (CSharp):
    1.     public GameObject fileBrowser; // Drag the FileBrowser prefab here (in the editor).
    2.     // Create a FileBrowser window:
    3.     public void OpenFileBrowser()
    4.     {
    5.         GameObject browserInstance = GameObject.Instantiate(fileBrowser);
    6.      
    7.         // Chose one of both of this setting examples:
    8.         // For NORMAL mode withount any other option than the callback:
    9.         browserInstance.GetComponent<FileBrowser>().SetBrowserWindow(OnPathSelected);
    10.         // For SAVE mode with callback, no special ini path, relative to PersistentData, "File" selection mode, no fixed path and "MyNewFile.txt" as default name:
    11.         browserInstance.GetComponent<FileBrowser>().SetBrowserWindow(OnPathSelected, "", false, "F", true, "", "MyNewFile.txt");
    12.  
    13.         // Add file extension filters (optional):
    14.         string[] filter = { ".wav", ".mp3", ".ogg" };
    15.         browserInstance.GetComponent<FileBrowser>().SetBrowserWindowFilter(filter);
    16.     }
    17.     // You should use this function signature in order to receive properly:
    18.     void OnPathSelected(string path)
    19.     {
    20.         // Do something with the returned path.
    21.     }
    22.  
    Please send me an email (naming this issue) to share with you this new version.
    Best regards.
     
    Last edited: Jul 28, 2017
  35. luma2057

    luma2057

    Joined:
    Apr 26, 2015
    Posts:
    1
    Hi, Do I need to do anything 'extra' to handle UTF-8 characters?
    I'm using .ReadFile to load lines from a .csv. (The files worked ok with StreamWriter, so I don't think they are 'corrupted'). I then .split the lines into an array. But, there are issues. Thanks
    Code (CSharp):
    1.  
    2. string[] lines = FileManagement.ReadFile<string>(levelDataFileName, false).Split(new string[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
    3.      
     
  36. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @luma3001, thanks for using FileManagement.
    There is nothing extra to do using UTF8 since the string parser doesn't makes any extra encoding. It saves and reads in binary interpreting chars as bytes.
    If you have a file saved with another system and encoding, then you may need to encode the string into your system default, the ReadRawFile method let's you read the file as a byte array and then let's you restore the string using StringBuilder or the method you prefer (depending on your platform).
    If that doesn't helps please sendme a sample file at jmonsuarez@gmail.com to give you a better support.
    Best regards.
     
  37. Skquark

    Skquark

    Joined:
    Jun 16, 2016
    Posts:
    3
    Just bought the component, was just what I needed since I'm building for Hololens, which didn't support the standard file save/open dialog window I was using, so got it customized and rigged up nicely as a tagalong world canvas. Few questions I have though.. Do you know if Hololens supports full path navigation? Is there a way to get the full path permissions within the editor preview (tells me "[FileManagement.ListLogicDrives] Not supported in this platform." in console)? Would there be a way to access MS OneDrive as a Logical Drive source?
    I also really wanted to use this to save and load my custom class object array list to a binary file, but the docs only give very simple examples for single variables or a single array. Without getting into too much detail, I have an array of board objects with an array of note objects inside. They're made of all the standard supported types, but could also include Texture2D and AudioClips, as well as reference links to other objects in the same array. It may not be easy, but is there a way to use this to save the class data and load it, or do I need to find a different "Save Game" component that can serialize a complete MonoBehaviour class list with the structure intact? Thanks a lot, looks great after customizing the prefab up.. I might even convert the ui from flat canvas to fancy 3d, that'd be fun.

    Wanted to contribute a small needed addition to the prefab script. A simple thing it was missing is changing the title of the filebrowser from script. Added these lines to FileBrowser.cs:
    Line 40:
    Text caption;
    public string Title { get { return caption.text; } set { caption.text = value; } }

    Line 89:
    caption = browserUI.Find("Caption").GetComponent<Text>();

    Then when opening browser, it's just:
    browserInstance.GetComponent<FileBrowser>().Title = "Open an Image File ...";

    Easy mod, felt like a piece most people would use for any implementation. Thought I'd save you the effort to say thanks..
     
    Last edited: Aug 20, 2017
  38. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @Skquark , sorry for the delay.
    Hololens is under the Windows Store platform, so it should have the same limitations as Windows Phone platform, or XBox, I'm not really sure if you can navigate freely as standalone platforms allow to.
    There are some experimental methods for serialisation, but they are not supported under Windows Store Apps, I'm investigating how to implement some cross platform solution (That means read serialised objects generated from different platforms). Right now everything is converted and parsed from strings, excepting binary files, so this cross platform compatibility is granted.
    Accessing cloud drives requires some special treatment, and also I'm trying to add all widely supported functionalities, so it can grant the "Write once, deploy anywhere" philosophy.
    Serialising UnityEngine objects can be hard to achieve, since they are not enabled to be serialised by default.
    I can recommend to save your complex items in some xml or json or your-own format, writing down the list of objects/components you need to attach to some GameObject. Then you add all the requested components when the file is loaded.
    I didn't find any really complete solution to achieve that, so I think you should implement exactly what you need.
    By the way I'm working in the upcoming version that will include the feature of saving a AudioClip to a WAV file and vice-versa. Very useful. I'm also working in some improvements in the FileBrowser to allow it to be attached to some 3D world object, just as the Doom3 control consoles does (Very interesting).
    Thanks a lot for the feedback, I will include the modification you suggested in the new version.
    Best regards.
     
  39. doq

    doq

    Joined:
    Aug 17, 2015
    Posts:
    121
    @jemonsuarez
    Can you add an option to GetFileName to exclude the extension? Or add another method like GetFileNameWithoutExtension?

    Actually my real issue is when FileManagement.ImportAudio returns the AudioClip, can you set the clip's name property to the filename without the extension?

    Thanks!
     
  40. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @doq thanks for your feedback, I will add your suggestion for sure in upcoming version (1.6).
    Best regards.
     
    doq likes this.
  41. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @doq, I've received a thread post but when I came to see it, there were no more post.
    Was you able to fixed that weird issue? Please send me an email to jmonsuarez@gmail.com if you need any help.
    Best regards.
     
  42. doq

    doq

    Joined:
    Aug 17, 2015
    Posts:
    121
    Hi @jemonsuarez,

    Yeah I figured out what was wrong. I deleted the post to escape my embarrassment. :) I was trying to load a cached "music analysis" file for an mp3 on device but forgot I had a flag to delete and reprocess the mp3.

    Initially, when I was trying to load the mp3 I was seeing "Access denied" while using the FileBrowser to access the directories. I had to flip the Player Settings > Other Settings > Configuration > Write Permission > External (SDCard) setting to get access to the sdcard. So I thought my missing music analysis file had a small chance of being related to the "weird" permission issue.

    In a prior thread post you mentioned setting the FileBrowser in "Unrestricted" mode, I couldn't find anything in the docs or API about it, which partially contributed to my confusion. I'm still not sure what's that about but mentioning the External (SDCard) setting for Android to access the user's files in the docs somewhere would be nice.

    Edit: Haha, I just saw in the docs you mentioned the setting. *shrug*
     
    Last edited: Dec 7, 2017
  43. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi @doq, I'm glad you found the solution.
    As you mentioned the SD card issue is listed in the "Known issues" list.
    The "Unrestricted" feature makes reference to the "fullPath" flag, allowing navigate outside the PersistentData path (and StreamingAssets).
    Maybe I should mention the SD card issue somehere else in the documetation.
    Best luck with your project!!!
     
  44. doq

    doq

    Joined:
    Aug 17, 2015
    Posts:
    121
    Yeah, not having familiarity with the issue of getting "Access denied" while on Android, I tried googling for an answer and didn't find a direct solution, just clues. Plus I had the confounding issue with my own code. So honestly, I'm not sure if updating the pdf would help much since it isn't searchable by google. But now that I've posted, things might be easier to figure out for the next person who runs into the issue.

    Btw, I when using the FileBrowser on Android I'm wondering why the root path shows multiple subdirectories. In the attached image, the root path shows:

    • /mnt/knox
    • /mnt/know/default/know-emulated
    etc.

    I think it would be confusing to present this to the end user. Ideally, just /mnt would be shown, since that's not even an option. I have to enter "/mnt/knox" see "Access denied" then go up one folder before I can get to /mnt/sdcard.

    I guess one option I'll have to implement is a scan of the device for music files and implement my own version of a file browser in production.
     

    Attached Files:

  45. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Well, as you said, it may look confusing, but the true is that not every Android device has the same path to the SD card, so maybe you can search the right path before opening the FileBrowser to pass it as a parameter, so the browser will show this folder first.
    I know there is a way to get the SD card path from Android, but I'm not very familiar with native code so I keep working on it.
    Thanks a lot for the feedback.
     
  46. doq

    doq

    Joined:
    Aug 17, 2015
    Posts:
    121
    Thanks for the tip. I've written a native plugin for Android before. Looks like you need to make a call to Environment.getExternalStorageDirectory
     
  47. doq

    doq

    Joined:
    Aug 17, 2015
    Posts:
    121
    Writing a plugin to get path was overkill. Instead I made some calls with AndroidJavaObject to get the info I needed.

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3.  
    4. public class Environment : MonoBehaviour
    5. {
    6.     public void GetExternalStorageCalls()
    7.     {
    8.         Debug.Log("Trying to get environment");
    9.         if (Application.platform == RuntimePlatform.Android)
    10.         {
    11.             AndroidJavaObject env = new AndroidJavaObject("android.os.Environment");
    12.             string storageState = env.CallStatic<string>("getExternalStorageState");
    13.             Debug.Log($"getExternalStorageState - {storageState}");
    14.             if (storageState == env.GetStatic<string>("MEDIA_MOUNTED"))
    15.             {
    16.                 var filepath = env.CallStatic<AndroidJavaObject>("getExternalStorageDirectory").Call<string>("getAbsolutePath");
    17.                 Debug.Log($"external storage filepath {filepath}");
    18.  
    19.                 var dirMusic = env.GetStatic<string>("DIRECTORY_MUSIC");
    20.                 Debug.Log($"DIRECTORY_MUSIC \"{dirMusic}\"");
    21.  
    22.                 var musicFile = env.CallStatic<AndroidJavaObject>("getExternalStoragePublicDirectory", dirMusic);
    23.                 var musicdir = musicFile.Call<String>("getAbsolutePath");
    24.                 Debug.Log($"music directory \"{musicdir}\"");
    25.  
    26.                 var files = musicFile.Call<string[]>("list");
    27.  
    28.                 Debug.Log("<b>music directory listing<b>");
    29.                 for (var i = 0; i < files.Length; ++i)
    30.                 {
    31.                     Debug.Log($"{files}");
    32.                 }
    33.             }
    34.         }
    35.     }
    36. }
     
    Last edited: Dec 9, 2017
  48. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Oh that's really awesome!! I'll give a try and include in the asset to help others.
    Thanks a lot, you are great.
     
    doq likes this.
  49. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    If I saved an image using FileManagement PlayerPrefs substitute and need to use a full filePath to it to send to the server what do I use? An example...
    Code (CSharp):
    1. Path filePath = "/ParentFolder/PersistentData/MyImage.jpg";
     
  50. jemonsuarez

    jemonsuarez

    Joined:
    Sep 24, 2012
    Posts:
    151
    Hi, all relative paths are into "PersistentDataPath" so, if understand correctly your question, the way to do it should be:
    Code (CSharp):
    1. string path = FileManagement.Combine(Application.persistentDataPath, "MyImage.jpg");
    Please let me know if that's ok.
    Best regards.