Android Question File.Copy2Async with ExternalStorage is very slow and blocks the app (isn't responding)

brunnlechner

Member
Licensed User
Longtime User
I want to copy files from DirInternal to external using File.Copy2Async and ExternalStorage.
It works, but is very slow and blocks the app (isn't responding Close App - Wait).
Inserting Sleep(50) doesn't improve anything.

File.Copy2Async + ExternalStorage:
    Dim Storage As ExternalStorage
    Dim LFile As ExternalFile
    Dim Lfolder As ExternalFile
    Dim In As InputStream
    Dim out As OutputStream
    Storage.Initialize (Me, "Storage")
    Lfolder=Storage.Root

    For Each f As String In File.ListFiles(File.DirInternal & "/temp")
            Dim n As Long = DateTime.Now
            In = File.OpenInput(File.DirInternal & "/temp", f)
            LFile=storage.FindFile(Lfolder,f)
           Log((DateTime.Now - n)) '4131ms
            If LFile.Length > 0 Then Storage.DeleteFile(LFile) 'without deleting sometimes corrupt files are created
            LFile=Storage.FindFileOrCreate(Lfolder,f)
            Log((DateTime.Now - n)) '7979ms
            out=Storage.OpenOutputstream(LFile)
            Wait For (File.Copy2Async(In, out)) Complete (Success As Boolean)'5:8101ms
            Log((DateTime.Now - n)) '8116
            File.Delete(File.DirInternal & "/temp", f)
            Log ("f: "&f)
            out.close
    Next

Thanks very much
Franz Brunnlechner
 
Last edited:

Filippo

Expert
Licensed User
Longtime User
I want to copy files from DirInternal to external using File.Copy2Async and ExternalStorage.
It works, but is very slow and blocks the app (isn't responding Close App - Wait).
Inserting Sleep(50) doesn't improve anything.

File.Copy2Async + ExternalStorage:
    Dim Storage As ExternalStorage
    Dim LFile As ExternalFile
    Dim Lfolder As ExternalFile
    Dim In As InputStream
    Dim out As OutputStream
    Storage.Initialize (Me, "Storage")
    Lfolder=Storage.Root

    For Each f As String In File.ListFiles(File.DirInternal & "/temp")
            In = File.OpenInput(File.DirInternal & "/temp", f)
            LFile=storage.FindFile(Lfolder,f)
            If LFile.Length > 0 Then Storage.DeleteFile(LFile) 'without deleting sometimes corrupt files are created
            LFile=Storage.FindFileOrCreate(Lfolder,f)
            out=Storage.OpenOutputstream(LFile)
            Wait For (File.Copy2Async(In, out)) Complete (Success As Boolean)
            File.Delete(File.DirInternal & "/temp", f)
            Log ("f: "&f)
            out.close
    Next

Thanks very much
Franz Brunnlechner
The first thing I notice is the closing word "In", I wouldn't use that as a variable.
 
Upvote 0

brunnlechner

Member
Licensed User
Longtime User
Most of the time required "Storage.FindFileOrCreate" or "Storage.FindFile" - '4131ms

The Storage.Root contains 35 files
 
Upvote 0

brunnlechner

Member
Licensed User
Longtime User
Hello Erel,
Most of the time required "Storage.FindFileOrCreate" or "Storage.FindFile" - '4131ms
i changed the code, so "storage.FindFile" comes only once

LFile=Storage.CreateNewFile(Lfolder,f):
            In = File.OpenInput(File.DirInternal & "/temp", f)
            LFile=storage.FindFile(Lfolder,f)
            If LFile.Length > 0 Then Storage.DeleteFile(LFile) 'without deleting sometimes corrupt files are created
            LFile=Storage.CreateNewFile(Lfolder,f)
            out=Storage.OpenOutputstream(LFile)
            Wait For (File.Copy2Async(In, out)) Complete (Success As Boolean)
 
Upvote 0

agraham

Expert
Licensed User
Longtime User
The slow item is FindFile (it is used by FindFileOrCreate) but if you look in the ExternalStorage code this is an Android native method so there is nothing you can do to speed it up. The only thing that would help would be to run it on a separate thread.

Perhaps you are using a slow device with a slow SD card as well?
 
Upvote 0

Filippo

Expert
Licensed User
Longtime User
If I were you, I would do it like this:
1) create a list "lstext" of all files in external storage
2) in the "For Each" loop check if the file exists in the list "lstext", if yes, delete it.
3) create a new file in external storage with the native function, not the "FindFileOrCreate" function.
4) now you can copy the file
 
Upvote 0

brunnlechner

Member
Licensed User
Longtime User
This is my current solution:

B4X:
Sub copy
    Dim Inp As InputStream
    Dim out As OutputStream
    Dim externalfilelist As List
    Dim Lfolder As ExternalFile
    Lfolder=Storage.Root
    externalfilelist.Initialize
    ListFiles (Lfolder) 'create a list "lstext" of all files in external storage
    For Each f As String In File.ListFiles(File.DirInternal & "/temp")
        If File.Exists(File.DirInternal & "/temp", f) Then
                Inp = File.OpenInput(File.DirInternal & "/temp", f)
                Dim test As Int = externFileListTest(f) 'check if the file exists in the list
                If test > -1 Then Storage.DeleteFile(externalfilelist.Get(test)) 'if the file exists in the list, delete it.
                out= Storage.OpenOutputstream(Storage.CreateNewFile(Lfolder,f))
                Wait For (File.Copy2Async(Inp, out)) Complete (Success As Boolean)
                File.Delete(File.DirInternal & "/temp", f)
                out.close
        End If
    Next
End Sub

Public Sub ListFiles (Folder As ExternalFile)
    Dim files() As Object = Folder.Native.RunMethod("listFiles", Null)
    For Each o As Object In files
        Dim f As JavaObject = o
        externalfilelist.Add(DocumentFileToExternalFile(f))
    Next
End Sub

Private Sub DocumentFileToExternalFile (DocumentFile As JavaObject) As ExternalFile
    Dim ef As ExternalFile
    If DocumentFile.IsInitialized = False Then
        Return ef
    End If
    ef.Initialize
    ef.Name = DocumentFile.RunMethod("getName", Null)
'    ef.Length = DocumentFile.RunMethod("length", Null)
'    ef.IsFolder = DocumentFile.RunMethod("isDirectory", Null)
    ef.Native = DocumentFile
'    ef.LastModified = DocumentFile.RunMethod("lastModified", Null)
    Return ef
End Sub

Sub externFileListTest(text As String) As Int
    Dim Test As ExternalFile
    For i = 0 To externalfilelist.Size - 1
        Test = externalfilelist.Get(i)
        If Test.Name = text Then
            Return(i)
        End If
    Next
    Return(-1)
End Sub
 
Upvote 0
Top