Search Unity

Simple File Browser [Open Source]

Discussion in 'Assets and Asset Store' started by yasirkula, Nov 19, 2016.

  1. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
    Okay, in that case how do I get a "SAF-compatible" path from a known path? such as "/storage/emulated/0/X"? I don't need a user to select a directory, I already know what I want to use.
     
    Last edited: Nov 16, 2020
  2. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can't do that, at least I don't think so.
     
  3. EternalAmbiguity

    EternalAmbiguity

    Joined:
    Dec 27, 2014
    Posts:
    3,144
  4. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    99
    Thank you for this great asset, too!

    One small bug report: if I put illegal characters like << to a Save dialog and try to save, this exception is thrown:

    ArgumentException: Illegal characters in path.
    System.IO.Path.GetExtension (System.String path) (at <9577ac7a62ef43179789031239ba8798>:0)
    SimpleFileBrowser.FileBrowser.OnSubmitButtonClicked () (at Assets/SimpleFileBrowser/Scripts/FileBrowser.cs:987)
    UnityEngine.Events.InvokableCall.Invoke () (at <e5b75411c8cd4bfaa9e760be20206f29>:0)
    UnityEngine.Events.UnityEvent.Invoke () (at <e5b75411c8cd4bfaa9e760be20206f29>:0)
    UnityEngine.UI.Button.Press () (at C:/Program Files/Unity/Hub/Editor/2019.4.13f1/Editor/Data/Resources/PackageManager/BuiltInPackages/com.unity.ugui/Runtime/UI/Core/Button.cs:68)
    UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at C:/Program Files/Unity/Hub/Editor/2019.4.13f1/Editor/Data/Resources/PackageManager/BuiltInPackages/com.unity.ugui/Runtime/UI/Core/Button.cs:110)

    A similar exception is also thrown if you try to create a new folder with invalid characters in it. It also seems to be possible to create several folders but putting names as "foo/bar" but that can be considered a feature, too, unless there are some security issues.
     
  5. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Thank you for the feedback!

    At one point, I was planning to use the Path.GetInvalidPathChars function but then decided it wasn't really necessary since 1) exceptions like these prevent the file browser from being closed, which should hint the player that something is wrong and 2) this is a very rare case. But I guess I can turn the filename input field red when an exception is thrown to emphasize the issue.

    The "foo/bar" example might actually be an issue on Android 10, where Storage Access Framework is used. But I don't think that users would enter such a path :D
     
  6. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    99
    Yes that probably isn't a big issue for most. Turning the field red as in load window would be great, though. In my project, I am treating all unhandled exceptions as crashes (to not miss anything) so I will anyway need to do some workaround.

    One easy workaround I have sometimes used is to just to sanitize the names with something like this I copied from somewhere (not super-optimal and probably always creating some unnecessary memory allocations):
    Code (CSharp):
    1.        
    2.         public static string MakeValidFilename(string name, string replaceInvalidCharWith = "")
    3.         {
    4.             string invalidChars = Regex.Escape(new string(InvalidFilenameChars));
    5.             string invalidReStr = string.Format(@"[{0}]+", invalidChars); // Could and should be cached and reused
    6.             return Regex.Replace(name.Trim(), invalidReStr, replaceInvalidCharWith);
    7.             // TODO check and react if result empty?
    8.         }
     
    yasirkula likes this.
  7. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I've pushed an update to the GitHub repository. Filename input field now turns red when an invalid filename is encountered or filename contains path separator characters. Asset Store version is currently pending review.
     
    enderjs and Andefob like this.
  8. enderjs

    enderjs

    Joined:
    Nov 23, 2020
    Posts:
    4
    Hi Yasirkula. First I would like to thank you for sharing this awesome plugin and it helped me a lot.

    Currently, it seems the browser have two modes —— a 'Folder mode' and a 'File mode', I have also noticed you made a switch by setting the first value to 'true' or 'false' by calling the WaitForLoadDialog function.

    I'm wondering is it possible to combine these two modes, so the user could load both folder and files on a single dialog. I'm currently do the tweaking myself but I would like to ask you if it's already implemented or there is a reason behind not implementing it.
     
  9. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    There isn't a built-in method for this. I think it is a weird feature; I haven't seen this functionality in a native dialog myself nor did I ever need it, honestly.
     
  10. enderjs

    enderjs

    Joined:
    Nov 23, 2020
    Posts:
    4
    Thanks for the quick reply.

    Basically I need to my user to provide me with a path that could either be a directory or a single file, and I will do some file manipulation based on the path. Some users may only need to provide me with one file while others may need to provide me with a folder depending on the situation.

    Though I can definitely force users to put a single file into a folder before providing me with the path but it seems kind of awkward.

    Another way would be have two buttons , while one for "providing a folder", and the other for "providing a file". I think this way might work better.

    I will think of it. Thanks for your help!
     
    Last edited: Nov 23, 2020
  11. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You should have a single button for convenience. You can send me a PM if you get stuck at a point.
     
  12. DRCornelius

    DRCornelius

    Joined:
    Oct 31, 2018
    Posts:
    2
    This looks amazing and absolutely what I need.
    I think I have the Save Dialoge to show correctly but I cannot figure out how to save a file.
    Am I supposed to use this function?
    FileBrowserHelpers.WriteTextToFile(targetPath, text);
    If so how do I get the targetPath that has been selected within the file browser?

    EDIT: I am not sure if this makes sense as I have never worked with anything like this before.
    Could you please post an example of also saving a file in the docs?
    I did get it to work.

    There were a few things I had trouble with in getting it to work.
    I didn't realize FileBrowser.Result[0] is the path.
    If I used CreateFileInDirectory( string directoryPath, string filename )
    Is FileBrowser.Result[1] the filename?
    Or would I do some string manipulation on FileBrowser.Result[0] to separate the path and the file name?

    If I want to use this in conjunction with some of the GameData stuff from this Gave Dev Guide tutorial ( How to Build a Save System in Unity) would I use the WriteBytesToFile( string targetPath, byte[] bytes ). This tutorial uses [System.Serializable] and BinaryFormatter.Serialize(file, data);

    Could I use something like the following to just serialize the data and then use that with WriteBytesToFile( string targetPath, byte[] bytes ) ??

    From this link.
    https://gist.github.com/LorenzGit/2cd665b6b588a8bb75c1a53f4d6b240a

    public static void Main()
    {
    ////USING BINARY FORMATTER
    byte[] bytes = ObjectToByteArray( new MyObj() );
    Console.WriteLine( Convert.ToBase64String(bytes) );
    MyObj myObj = ByteArrayToObject(bytes) as MyObj;
    Console.WriteLine(myObj);
    /////////////////////
    }
    ////USING BINARY FORMATTER
    // Convert an object to a byte array
    public static byte[] ObjectToByteArray(Object obj)
    {
    BinaryFormatter bf = new BinaryFormatter();
    using (var ms = new MemoryStream())
    {
    bf.Serialize(ms, obj);
    return ms.ToArray();
    }
    }
    // Convert a byte array to an Object
    public static Object ByteArrayToObject(byte[] arrBytes)
    {
    using (var memStream = new MemoryStream())
    {
    var binForm = new BinaryFormatter();
    memStream.Write(arrBytes, 0, arrBytes.Length);
    memStream.Seek(0, SeekOrigin.Begin);
    var obj = binForm.Deserialize(memStream);
    return obj;
    }
    }
     
    Last edited: Nov 28, 2020
  13. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    FileBrowser.Result holds absolute paths of the selected file(s). If only a single file is selected, only 1 path will be returned (Result[0]). If multiple files are selected, multiple paths are returned (Result[1] etc). Unless you are using the coroutine functions of FileBrowser, you should use OnSuccess callback to retrieve the paths. Example code: https://github.com/yasirkula/UnitySimpleFileBrowser#example-code

    You don't have to use CreateFileInDirectory unless you've selected a folder rather than a file. Then, to create files inside that folder, you should use CreateFileInDirectory, yes. Simply pass Result[0] as directoryPath and enter the desired name of the file to filename. The function will return the created file's path that you can pass to WriteTextToFile. If you have selected a file, you can pass that path directly to WriteTextToFile/WriteBytesToFile. For BinaryFormatter, you can use the code you've posted to generate the byte[] array.
     
  14. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
  15. batvink

    batvink

    Joined:
    Sep 26, 2019
    Posts:
    61
    Hi,

    thanks for a great free asset.

    I have a problem regarding making the loading browser a modal process. When the box is shown, the code continues.
    Is there a way to make it modal and stop the current thread from proceeding?
     
  16. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Unity UI can only run on the main thread and main thread is where all other scripts are also executed, so it is unfortunately not possible. On standalone platforms, you can use native file dialogs to achieve this though.
     
    batvink likes this.
  17. joshstiemsma

    joshstiemsma

    Joined:
    Oct 18, 2013
    Posts:
    4
    Hey Yasirkula, Thanks for the great plugin!! very useful. I ran into an issue updating an app from the Quest 1 Oculus device to the Quest 2. I cannot get the browser to open to any location in the file system as well as none of the quickLink items succeed. It only says "pick folder" and that just crashes the application.

    All of these work on windows, I've made a script to try any known path I've found, and the app has confirmed to have External Read and Write permissions. Im assuming, as you've mentioned, this related to Storage Access Framework on androids but I cannot seem to get past this. Have you had anyone reach out to you about this or have you been presented with it before? Do you know any possible solutions?
     
  18. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
  19. daphifluffi

    daphifluffi

    Joined:
    Dec 19, 2020
    Posts:
    3
    Hi Yasirkula,

    I am trying to use the FileBrowser to save a .fbx file when I click on a button in my UI.
    I tried to do it like this but it seems that I am way off because the file does not really save. Thank you in advance!

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityFBXExporter;
    3. using SimpleFileBrowser;
    4.  
    5. void Start()
    6. {
    7. FileBrowser.SetDefaultFilter( ".fbx" );
    8. }
    9.  
    10. public void Convert()
    11. {
    12. string content = FBXExporter.MeshToString(objectToExport, null, true, true);
    13. FileBrowser.ShowSaveDialog(null , null, FileBrowser.PickMode.Files, false, "C:\\", "object.fbx", "Save As", "Save" );
    14.  
    15. if (FileBrowser.Success)
    16. {
    17. string targetPath = FileBrowser.Result[0];
    18. FileBrowserHelpers.WriteTextToFile(targetPath, content);
    19. }
    20. }
     
  20. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You should use the OnSuccess callback:
    Code (CSharp):
    1. FileBrowser.ShowSaveDialog( ( paths ) =>
    2. {
    3.     string targetPath = paths[0];
    4.     FileBrowserHelpers.WriteTextToFile(targetPath, content);
    5. }, null, FileBrowser.PickMode.Files, false, "C:\\", "object.fbx", "Save As", "Save" );
     
  21. daphifluffi

    daphifluffi

    Joined:
    Dec 19, 2020
    Posts:
    3
    Tested it on Standalone Export works great! Thank you very much :)
     
    yasirkula likes this.
  22. Marek_Bakalarczuk

    Marek_Bakalarczuk

    Joined:
    Dec 28, 2012
    Posts:
    114
    How can I get native keyboard to work on mobiles?
     
  23. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I use Unity's UI InputField without any modifications. I don't fully understand the keyboard issue you are having but if it is a bug, then it is caused by UI system itself. If it is an enhancement, then feel free to modify InputFields inside SimpleFileBrowserCanvas prefab.
     
    Marek_Bakalarczuk likes this.
  24. Marek_Bakalarczuk

    Marek_Bakalarczuk

    Joined:
    Dec 28, 2012
    Posts:
    114
    I'll try it. My issue is simple: when I want to provide a filename in iOS, InputField doesn't fire keyboard on screen. I'll give you a sign, when I fix it
     
  25. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    If you create a new InputField object in your scene and click it, does the keyboard show up?
     
  26. Marek_Bakalarczuk

    Marek_Bakalarczuk

    Joined:
    Dec 28, 2012
    Posts:
    114
    Yep
     
  27. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    That's strange. Please let me know if you pinpoint the issue.
     
  28. Marek_Bakalarczuk

    Marek_Bakalarczuk

    Joined:
    Dec 28, 2012
    Posts:
    114
    Working. I don't know what issue was. Just started to work after switching from 2019.3.5f1 to 2019.4.11LTS
     
    yasirkula likes this.
  29. igor90spv

    igor90spv

    Joined:
    Nov 10, 2020
    Posts:
    5
    Hi Yasirkula,

    if I open Simple File Browser before inserting pen drive it does not show the disk in the menu on the left. I must necessarily restart the game.
    As you can see in the attached image I don't have E: \ when the pen drive is inserted.

    How can i solve this problem?
     

    Attached Files:

    Last edited: Jan 7, 2021
  30. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I've addressed this issue with the latest release.
     
    Last edited: Jan 11, 2021
  31. igor90spv

    igor90spv

    Joined:
    Nov 10, 2020
    Posts:
    5
    Hi, would it be possible to remove the "show Hidden files" option?
     
    Last edited: Jan 11, 2021
  32. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Last edited: Jan 11, 2021
  33. igor90spv

    igor90spv

    Joined:
    Nov 10, 2020
    Posts:
    5
    Furthermore, Simple File Browser returns the following path C:/Users/ while C# C:\Users\

    Therefore the two paths appear different.

    Is there a way to sort this out and get both path directory with the same slash(/) symbol?
     
  34. igor90spv

    igor90spv

    Joined:
    Nov 10, 2020
    Posts:
    5



    I deleted what you see in the attached photo and deactivated ShowHiddenFilesToggle gameobject
     

    Attached Files:

  35. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    If you want to change \ to / in a string, you can call the following function:
    path = path.Replace('\\', '/');


    If you don't change the script as I've suggested, the toggle might reappear when you resize the file browser.
     
  36. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    @igor90spv Added
    FileBrowser.DisplayHiddenFilesToggle
    static property with the latest update.
     
    Last edited: Jan 14, 2021
  37. igor90spv

    igor90spv

    Joined:
    Nov 10, 2020
    Posts:
    5
    Thanks ;)
     
    yasirkula likes this.
  38. enderjs

    enderjs

    Joined:
    Nov 23, 2020
    Posts:
    4
    Hi again,

    Thanks for the features you implemented regarding selecting both files and folders, it helped a lot!

    I'm working with the Multitoggleselection part and there is one thing I'm having trouble with. When multitoogleselection is on, all the files and folders will have a checkbox in front of them—— even under the case where only files are supposed to be selected, folders will still have those checkboxes in front of them.

    From what I can see here, the appearance of the checkboxes is controlled by the Setselected function in the filebrowseritem.cs. I tried to change the code a bit , added a condition that only if the current 'item' is a file, this function will work accordingly. But it didn't seem to work properly.

    What I achieved is when the browser is first loaded, checkboxes before the folders are gone. But when I'm dragging the scroll bar downwards, the checkboxes reappear and persists before the folders.

    I'm wondering if there are other parts in the code that controls the appearance of those checkboxes, and how can I make sure checkboxes only appear in front of files when only files are allowed to be selected?
     
  39. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    enderjs likes this.
  40. enderjs

    enderjs

    Joined:
    Nov 23, 2020
    Posts:
    4
    Thanks a lot of the quick solution!
     
  41. waqasisme

    waqasisme

    Joined:
    Aug 13, 2020
    Posts:
    2
    Hello, is there a way to change the appearance of the file dialog that opens? I am also interested in having it open in maximized, so that it takes up all the space even on the phone :)
     
  42. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    To change the appearance, you need to modify SimpleFileBrowserCanvas prefab. To maximize the file browser, you can call
    windowTR.sizeDelta = new Vector2( 99999f, 99999f );
    inside FileBrowser.Show function.
     
  43. look001

    look001

    Joined:
    Mar 23, 2017
    Posts:
    111
    Thank you really much for the browser. I have a few question about the code.
    What is the difference between the helper functions (e.g.
    FileBrowserHelpers.FileExists) and the c# way (e.g. System.IO.File.Exists)?
    Also I am confused why android 10+ needs a SAF. Couldn't you just browse all files using the c# System.IO functions?
    Does android 10 not work with these function or is it using a native dialog instead of the nGui?
     
  44. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    SimpleFileBrowser doesn't use NGUI, it uses Unity's UI system. On Android 10+, the operating system itself forbids access to the filesystem, normal File functions will throw exceptions or simply fail. On these devices, the plugin uses Storage Access Framework to workaround this issue and Storage Access Framework paths can work with only FileBrowserHelpers functions.
     
  45. look001

    look001

    Joined:
    Mar 23, 2017
    Posts:
    111
    Is there an easy way to get the default path on android when the browser opens up using the helper functions? And is it possible to get the parent directory of a directory using the helper functions?
     
    Last edited: Feb 21, 2021
  46. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can call native Environment.getExternalStorageDirectory function via AndroidJavaClass. If it doesn't work on Android 11+, there may not be a method for root path because Storage Access Framework grants access to only the folders that user manually picks and hides actual file paths behind an abstraction layer.
     
  47. JermalJoseph

    JermalJoseph

    Joined:
    Apr 9, 2018
    Posts:
    12
    Really love the plugin bro! Its so helpful for the type of game I m creating. I was just wondering if there is a way to get the browser to scale to fit any potrait screen size.
     
  48. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    If file browser is larger than the screen size, it automatically shrinks to fit the screen but it doesn't automatically expand. For this, you can call
    windowTR.sizeDelta = new Vector2( 99999f, 99999f );
    inside FileBrowser.Show function.
     
  49. JermalJoseph

    JermalJoseph

    Joined:
    Apr 9, 2018
    Posts:
    12
    Thanks i already found a solution but in case it fails overtime i ll try your solution
     
    yasirkula likes this.
  50. JaG31

    JaG31

    Joined:
    Dec 6, 2020
    Posts:
    1
    I am trying to get this asset to work with SteamVR, but I cannot access Valve.VR from any of the simplefilebrowser scripts. Is there any way to change the load order of either SteamVR or this asset in order to be able to add a SteamVR interactable component to each quicklink at runtime?