Android Question Read a file from Sd card

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
Hi to All
after resolving the access to external sd Card, I went inside another problem, namely how to read the file. It seems a very stupid question, of course. As a matter of fact, once you have an ExternalFile object you can use it for an InputStream etc. This works. But you must have a valid ExternalFile. I did the following test, in which I get the ExternalFile by a FindFile function. Everything works, as I said. Now, if in the folder we have few files, probably a FindFile is fast, but if we have thousands of files? The obvious idea is, knowing exactly the name of the file to read, to use an ExternalFile object, initialize it, assign to it the name of the file and use it, as before. What I see is that this mechanism doesn't work and, "curiously" the debugger returns that the object is not initialized. See the code for understanding better what I mean. the only documentation on this subject is Erel's ExternalStorage lib example. Unluckily in no place I find an explicit initialization of The ExternalFile object. They are all managed as List objects, returned by functions and so on. The app below has a layout with only a Button1. Best regards.
B4X:
#Region  Project Attributes 
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName: 
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes 
    #FullScreen: False
    #IncludeTitle: True
#End Region

#AdditionalJar: androidx.legacy:legacy-support-core-utils ' <<< this is crucial

Sub Process_Globals
    Private Storage As ExternalStorage
End Sub

Sub Globals

End Sub

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        Storage.Initialize (Me, "Storage")
    End If
    Activity.LoadLayout("layout")
End Sub

Sub Button1_Click ' << the only action
    
    Storage.SelectDir(True)

    Wait For Storage_ExternalFolderAvailable

    Sleep(1000) ' maybe useless

    Log(Storage.Root.Name) ' shows correctly the folder previously selected
    
    Dim Name="xxxx.def" As String ' file to read

    Dim EZ As ExternalFile
    Dim I1,I2 As InputStream
    
    EZ=Storage.FindFile(Storage.Root,Name)
     
    I1=Storage.OpenInputStream(EZ) ' till here OK
    
    Dim EF As ExternalFile ' now the problem
    
    EF.Initialize ' this seems not enough
    
    EF.IsFolder=False
    EF.Name=Name

    I2=Storage.OpenInputStream(EF) ' Error:  java.lang.RuntimeException: Object should first be initialized (JavaObject).
        
End Sub
 

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
Unluckily not. I am using the ExternalStorage library. The problem is that i don't see any way to initialize an ExternalFile other than using FindFile. As I wrote, this is impossible when the folder contains a lot of files, because it takes much time to do the operation. I already realized that this topic is rather rare and probably I cannot use external storage for my aims. Thank you anyway.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
You could try running ListFiles once when you start the app and save the List of ExternalFiles it returns. It is probably then faster to search the List for an ExternalFile object with the required Name parameter. This should be quick compared to FindFile. You could then make it much quicker by building a Map with the names as keys and the ExternalFiles from the List as values.
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
You could try running ListFiles once when you start the app and save the List of ExternalFiles it returns. It is probably then faster to search the List for an ExternalFile object with the required Name parameter. This should be quick compared to FindFile. You could then make it much quicker by building a Map with the names as keys and the ExternalFiles from the List as values.
Hi. Thanks. I also had such an idea, but files are thousands. Moreover the App itself needs a lot of memory, so perhaps this is not practical. Not excluded that I'll give it a try. I had another idea but yet not tested. Use a global ExternalFIle object. Do just once the FindFile with one of the files. After, just change the name and read the other files. Thanks again.
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
Do just once the FindFile with one of the files. After, just change the name and read the other files
That won't work. ExternalFile has a Native parameter and that is the important bit. It holds a Java DocumentFile instance which is what references the actual file on the SD Card. Just changing the name won't work. It is finding that DocumentFile instance for a file that takes the time in ListFiles and FindFile.

I wouldn't worry about thousands of files, ExternalFile objects are very lightweight.
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
That won't work. ExternalFile has a Native parameter and that is the important bit. It holds a Java DocumentFile instance which is what references the actual file on the SD Card. Just changing the name won't work. It is finding that DocumentFile instance for a file that takes the time in ListFiles and FindFile.

I wouldn't worry about thousands of files, ExternalFile objects are very lightweight.
Ok. Thanks for your precious advices..
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
Andrew: You added much value to B4A, at least for my work. Actually I don't know why you did this. I hope you have had your benefits. Just my appreciation, not actually a real value..
 
Upvote 0

GiovanniPolese

Well-Known Member
Licensed User
Longtime User
Try with:
B4X:
EZ=Storage.FindFile(Storage.Root.Name, Name)
Hi. Thank you. I know this, because, moreover, it is the only way to get a valid ExternalFile object, open it and read it. The problem is that this function takes, for example, 30 sec or more to find a file in a directory with 5000 files. So, if you have to read 10 files .. etc. What I was underlying is the fact that, even knowing the name of the file, you cannot open and read a file on Sd, as you do in other directories of the Tablet. This is the point, not how to get just a file ..
 
Upvote 0
Top