Android Question Having a hard time saving to External SD Card

GuyBooth

Active Member
Licensed User
Longtime User
This used to be so easy ...
I have an app where I occasionally copy files from a NAS to a folder on an SD card. The following code used to work:
B4X:
sDestinationPath = "/storage/9C33-6BBD/tmm_music/Music_02"
' Copy file at top of lstMissingFiles list to the destination with .tmp extension
smbNas.DownloadFile(sSourcePath,lstMissingFiles.Get(0),sDestinationPath,lstMissingFiles.Get(0) & ".tmp")
Once this tmp file had been validated, I renamed it.
With targetSdkVersion="27" and Android v 7.0 this no longer works, and worse - it actually crashes the app, with the following error log (even though External File Permissions have been granted):
B4X:
Destination Path is /storage/9C33-6BBD/tmm_music/Music_02
Error occurred on line: 434 (TMM_DBService)
java.io.FileNotFoundException: /storage/9C33-6BBD/tmm_music/Music_02/PG_2805141929-03.mp3.tmp (Permission denied)
    at java.io.FileOutputStream.open(Native Method)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:221)
    at anywheresoftware.b4a.objects.streams.File.OpenOutput(File.java:373)
    at anywheresoftware.b4a.objects.SMB.DownloadFile(SMB.java:182)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runVoidMethod(Shell.java:755)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:345)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:249)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:139)
    at anywheresoftware.b4a.keywords.Common.CallSub4(Common.java:1058)
    at anywheresoftware.b4a.keywords.Common.CallSubNew(Common.java:1005)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:710)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:342)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:249)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:139)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:166)
    at anywheresoftware.b4a.shell.DebugResumableSub$RemoteResumableSub.resume(DebugResumableSub.java:19)
    at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:240)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:132)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:166)
    at anywheresoftware.b4a.keywords.Common$14.run(Common.java:1736)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6780)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
I can use one of the directories listed by the RP.GetAllSafeDirsExternal("") method but I don't want to do this if I can avoid it - many GB of external data get wiped out if I have to uninstall the app and reinstall it.
I have played with the https://www.b4x.com/android/forum/threads/90238 class that Erel created, and with it I can create a folder where I want it. The notes in the thread suggest that I should be able to copy a file to the folder, but I can't see how.
Am I missing something?
 
Last edited:

GuyBooth

Active Member
Licensed User
Longtime User
As DonManfred wrote you should use ExternalStorage. There is no other way.

1. Call es.FindFileOrCreate to create the file.
2. Open an OutputStream with OpenOutputStream.
3. Copy the file with File.Copy2.
4. Close the output stream.

OK - but how do I use File.Copy2 with smb?
My code currently uses smb.copyfile with source and destination urls and filenames.
How do I create a stream from an smb object?

(From what I understand from inman's last post in https://www.b4x.com/android/forum/threads/567739 I need an smb equivalent for:
inp = sctxt.RunMethodJO("getContentResolver", Null).RunMethod("openInputStream", Array(oldFile.RunMethod("getUri", Null)))
Is there such a thing? )
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…