Android Question Append text with ExternalStorage class

Wosl

Member
Dear All,

I'm using ExternalStorage https://www.b4x.com/android/forum/threads/externalstorage-access-sd-cards-and-usb-sticks.90238/ to store text data on my external device (SD card). This works as expected, when a new file is created and the content is written to it. But how can I append text to an existing file?

Wosl

Here is my sample code:
[CODE lang="b4x" title="Write data to external device with ExternalStorage class"]#Region Project Attributes
#ApplicationLabel: SDCard
#VersionCode: 1
#VersionName:
'SupportedOrientations possible values: unspecified, landscape or portrait.
#SupportedOrientations: portrait
#CanInstallToExternalStorage: False
#End Region
#Region Activity Attributes
#FullScreen: False
#IncludeTitle: True
#End Region
#AdditionalJar: androidx.legacy:legacy-support-core-utils
Sub Process_Globals
Public Storage As ExternalStorage
End Sub
Sub Globals
End Sub
Sub Activity_Create(FirstTime As Boolean)
' Create a file on external device in preselected folder
' Output text to it
' Second Step: append additional text
Private cCSV As String, cFileDir As String = "TestDir", cFileCSV As String = "Test.csv"
Private cStoragePath As ExternalFile, extFile As ExternalFile, storedFile As ExternalFile
Private DestinationFile As ExternalFile
Private outputstream As OutputStream, inputstream As InputStream

' Storage initialization for external device
Storage.Initialize (Me, "Storage")

' Wait until external system is available and call user prompt if not
Storage.SelectDir(True)
Wait For Storage_ExternalFolderAvailable

' Output file to external storage
cStoragePath = Storage.Root
extFile = Storage.FindDirOrCreate(cStoragePath, cFileDir)

' Find a file in selected folder and delete it if existing
storedFile = Storage.FindFile(extFile,cFileCSV)
If storedFile.IsInitialized = True Then
Storage.DeleteFile(storedFile)
End If

' Copy a string to inputstream
cCSV = "Header1;Header2" & CRLF & "Value11;Value12" & CRLF & "Value21;Value22"
inputstream = StringToInputStream (cCSV)

' Allocate a new file on external device
DestinationFile = Storage.CreateNewFile(extFile,cFileCSV)
outputstream = Storage.OpenOutputStream(DestinationFile)

' Copy new file to external device
File.Copy2(inputstream,outputstream)

' Close streams
outputstream.Close
inputstream.Close
Log ("File '" & cFileCSV & "' created in folder '" & cFileDir & "'")
Log ("Content of 'cCSV' written to File '" & cFileCSV & "'")

' Second step: add text to file
cCSV = "Value31;Value32"
'----------> append data to existing file ????
' Close app
Activity.Finish
ExitApplication
End Sub
Sub StringToInputStream (s As String) As InputStream
' Copy string to inputstream
Dim In As InputStream
Dim data() As Byte = s.GetBytes("UTF8")
In.InitializeFromBytesArray(data, 0, data.Length)
Return In
End Sub [/CODE]
 
Thank you Erel,

perfect world - it works.

Here is the full code in order to help other B4X users managing data on external devices.

[CODE lang="b4x" title="Append data to a file on external device using ExternalStorage class"]#Region Project Attributes
#ApplicationLabel: SDCard File Management
#VersionCode: 1
#VersionName:
'SupportedOrientations possible values: unspecified, landscape or portrait.
#SupportedOrientations: portrait
#CanInstallToExternalStorage: False
#End Region
#Region Activity Attributes
#FullScreen: False
#IncludeTitle: True
#End Region
#AdditionalJar: androidx.legacy:legacy-support-core-utils
Sub Process_Globals
Public Storage As ExternalStorage
End Sub
Sub Globals
End Sub
Sub Activity_Create(FirstTime As Boolean)
'##########################################################
' Append data to a file on external device using ExternalStorage class
' - Create a file on external device in preselected folder (here root)
' - Output some text to it
' - Append additional text to this file
'##########################################################
Private cCSV As String, cFileDir As String = "TestDir", cFileCSV As String = "TestData.csv"
Private cStoragePath As ExternalFile, extFile As ExternalFile, storedFile As ExternalFile
Private DestinationFile As ExternalFile
Private outputstream As OutputStream, inputstream As InputStream

'##########################################################
' Initialization and test basic file operations
'##########################################################

' Storage initialization for external device
Storage.Initialize (Me, "Storage")

' Wait until external system is available and call user prompt if not
Storage.SelectDir(True)
Wait For Storage_ExternalFolderAvailable

' Find a file on external storage or create it
cStoragePath = Storage.Root
extFile = Storage.FindDirOrCreate(cStoragePath, cFileDir)

' Find a file in selected folder and delete it if existing
storedFile = Storage.FindFile(extFile,cFileCSV)
If storedFile.IsInitialized = True Then
Storage.DeleteFile(storedFile)
End If

'##########################################################
' Write data first time to external device
'##########################################################

' Copy a string to inputstream
cCSV = "Header1;Header2" & CRLF & "Value11;Value12" & CRLF & "Value21;Value22"
inputstream = StringToInputStream (cCSV)

' Allocate a new file on external device
DestinationFile = Storage.CreateNewFile(extFile,cFileCSV)
outputstream = Storage.OpenOutputStream(DestinationFile)

' Copy new file to external device
File.Copy2(inputstream,outputstream)

' Close streams
outputstream.Close
inputstream.Close

Log ("File '" & cFileCSV & "' created in folder '" & cFileDir & "'")
Log ("Content of 'cCSV' written to File '" & cFileCSV & "'")

'##########################################################
' Append data to already existing file on external device
'##########################################################

' Copy a string to inputstream
cCSV = CRLF & "Value31;Value32"
inputstream = StringToInputStream (cCSV)

' Open file on external device in append modus
outputstream = OpenOutputStreamAppend(DestinationFile)

' Copy data to external device
File.Copy2(inputstream,outputstream)

' Close streams
outputstream.Close
inputstream.Close

Log ("Content of updated 'cCSV' appended to file '" & cFileCSV & "' in folder '" & cFileDir & "'")

' Close app
Log ("Done")

Activity.Finish
ExitApplication
End Sub
Sub StringToInputStream (s As String) As InputStream
' Copy string to inputstream
Dim In As InputStream
Dim data() As Byte = s.GetBytes("UTF8")
In.InitializeFromBytesArray(data, 0, data.Length)
Return In
End Sub
Public Sub OpenOutputStreamAppend (EF As ExternalFile) As OutputStream
' Open outputstream in append modus
Dim ctxt As JavaObject
ctxt.InitializeContext
Return ctxt.RunMethodJO("getContentResolver", Null).RunMethod("openOutputStream", Array(EF.Native.RunMethod("getUri", Null), "wa"))
End Sub[/CODE]

This sample code writes a new file with text data in the user selected directory on the external device. In a second step additional text will be appended to the now existing file. When you check the file with any file explorer, you'll see the expected content. I'll apply this code to store some large files (CSV formatted) in an app independent place on my external storage. If anybody has a better way to achieve this target, please let me know.

I hope that this code snippet will help other users to manage external files.

Let me add a wish, please. It would be useful if the append mode (3rd parameter) will be added to the ExternalStorage class similar to

[CODE lang="b4x" title="OpenOutput"]File.OpenOutput(cDir, cFileName, True)[/CODE]

Best Regards and finally many thankx to Erel again
Wolf
 
Upvote 0
Back
Top