Android Question writeb4xobject position?

kostefar

Active Member
Licensed User
Longtime User
Dear All,

The position parameter for this command will get an existing file overwritten with new data if set to 0, but if I could set it to EOF, it would work as append instead, right?
How would I do this?


Thanks
 

kostefar

Active Member
Licensed User
Longtime User
Yes.
B4X:
raf.WriteB4XObject(o, raf.Size)

Now at the stage where I´m testing this, and I can´t get it to work. The loop splits a JSON array, and appends each new item to the end of the file with the corresponding threadid.

B4X:
        For d = 0 To (l.Size - 1)
                                m = l.Get (d)
                        tmpthreadid = m.Get ("threadid")
                              
                         
                               
                                RAF.Initialize2(File.DirDefaultExternal & "/" & usernametmp & "/messages/" , tmpthreadid, False,False)
                               
                                RAF.WriteB4XObject(l.Get (d),RAF.size)
                                DoEvents
                                Log ("incomging " & l.Get (d))
                                Log ("file      " & RAF.ReadB4XObject(0))
                               
                            Next

But as you can see, all that it does is writing from the beginning each time writeb4xobject is executed, and there´s no logic in what it (over)writes with:

- message 1
- message 2
- message 2
- message 2
- message 1

B4X:
incomging {timestamp=2016-12-21 14:43:04, message=ABC, sender=ll, username=, threadid=92337321312222016034304, msgtype=}
file      {timestamp=2016-12-21 14:43:04, message=ABC, sender=ll, username=, threadid=92337321312222016034304, msgtype=}
incomging {timestamp=2016-12-21 14:43:04, message=ABC, sender=ll, username=, threadid=32629016712222016034323, msgtype=}
file      {timestamp=2016-12-21 14:43:04, message=ABC, sender=ll, username=, threadid=32629016712222016034323, msgtype=}
incomging {timestamp=2016-12-21 14:43:23, message=DEF, sender=kk, username=, threadid=32629016712222016034323, msgtype=}
file      {timestamp=2016-12-21 14:43:04, message=ABC, sender=ll, username=, threadid=32629016712222016034323, msgtype=}
incomging {timestamp=2016-12-21 14:43:47, message=GHI, sender=ll, username=, threadid=32629016712222016034323, msgtype=}
file      {timestamp=2016-12-21 14:43:04, message=ABC, sender=ll, username=, threadid=32629016712222016034323, msgtype=}
incomging {timestamp=2016-12-21 14:44:05, message=JKL, sender=kk, username=, threadid=92337321312222016034304, msgtype=}
file      {timestamp=2016-12-21 14:43:04, message=ABC, sender=ll, username=, threadid=92337321312222016034304, msgtype=}

Am I doing something wrong, or ..?

Thanks in advance!
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
You are reading the same (first) object from the file each time with 'RAF.ReadB4XObject(0))'.

As Erel has suggested elsewhere on a similar topic, you would be better to save all the items to a Map, then save the Map (Unless the file is going to be very large).

Something like:

B4X:
Dim TempMap As Map
    TempMap.Initialize

    Dim d As int
    For d = 0 To (l.Size - 1)
            m = l.Get (d)
            tmpthreadid = m.Get ("threadid")
       
            TempMap.Put(d,l.Get(d))
         
            Log ("incomging " & l.Get (d))
            Log ("file      " & TempMap.Get(d))
         
            RAF.Initialize2(File.DirDefaultExternal & "/" & usernametmp & "/messages/" , tmpthreadid, False,False)
            'Write the whole map at once
            RAF.WriteB4XObject(TempMap,0)
        
        Next

        'Then to read it back     
     
        'Read the map
        Dim TempMap As M = RAF.ReadB4XObject(0)
        Dim Line As String
        For Each K As Int In TempMap.Keys
            Line = TempMap.Get(K)
            Log(Line)
        Next
 
Upvote 0

kostefar

Active Member
Licensed User
Longtime User
You are reading the same (first) object from the file each time with 'RAF.ReadB4XObject(0))'.

As Erel has suggested elsewhere on a similar topic, you would be better to save all the items to a Map, then save the Map (Unless the file is going to be very large).

Something like:

B4X:
Dim TempMap As Map
    TempMap.Initialize

    Dim d As int
    For d = 0 To (l.Size - 1)
            m = l.Get (d)
            tmpthreadid = m.Get ("threadid")
     
            TempMap.Put(d,l.Get(d))
       
            Log ("incomging " & l.Get (d))
            Log ("file      " & TempMap.Get(d))
       
            RAF.Initialize2(File.DirDefaultExternal & "/" & usernametmp & "/messages/" , tmpthreadid, False,False)
            'Write the whole map at once
            RAF.WriteB4XObject(TempMap,0)
      
        Next

        'Then to read it back   
   
        'Read the map
        Dim TempMap As M = RAF.ReadB4XObject(0)
        Dim Line As String
        For Each K As Int In TempMap.Keys
            Line = TempMap.Get(K)
            Log(Line)
        Next

Seems like I´ve misunderstood how readb4xobject works then.. I thought that the "0" indicated the position in the file, and that it would show all objects in the file when doing this. So I assume that the position value tells which object number to read, so I instead tried to put this
B4X:
Log ("file      " & RAF.ReadB4XObject(2))
after the loop, just to test if it will simply show me the 3rd object then. But now I get an error message
B4X:
java.io.IOException
, so I´m pretty lost now. Your code gives me an error, btw:
B4X:
B4A version: 6.50
Parsing code.    Error
Error parsing program.
Error description: Unknown type: m
Are you missing a library reference?
Occurred on line: 406 (Main)
Dim tempmap As M = RAF.ReadB4XObject(0)

I want to avoid writing the data over and over again, the way that you suggest it. Why? Because it´s ment to be added to data that´s already there, so if I should do that, I´d have to first load all the existing data into a list, add the new incoming data, and then rewrite everything. It seems like an ineffecient way to perform this, and I´m also thinking about that for the sake of the sdcards health, the less you need to write to it, the better.

I may have a look at the keyvaluestore solution, but I´d like to first understand what I´m doing wrong here.

Thanks a mill for your reply!
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
The position in the file is the byte position, if you want to read a particular item, you will need to store the indexes, which is why the Map solution is better. Each object is in a separate map index.

I know my code wont run as is, your code had the variable m in it, I don't know what type of variable that is, so I just quoted it.

In fact, if it's already a map, you don't need to create the temp map.
 
Upvote 0

kostefar

Active Member
Licensed User
Longtime User
The position in the file is the byte position, if you want to read a particular item, you will need to store the indexes, which is why the Map solution is better. Each object is in a separate map index.

I know my code wont run as is, your code had the variable m in it, I don't know what type of variable that is, so I just quoted it.

In fact, if it's already a map, you don't need to create the temp map.

Thanks, and yes m is indeed a map so your code should run I suppose? And about position: That´s also what I thought, that position is the byte position. But why would I get an error then when I try to read what then turns out to be the byte at position 2? Is that because I need to read from a position where an object starts and not in the middle of it?
If I do it your way, I overwrite all the data all the time with existing data and incoming data, because I start from position 0, and as I said: That´s creating unnecessary write cycles not only in the app, but also on the sdcard which is known to not last forever. That´s why I wanted to use raf.size in the first place.

I hope I´ve misunderstood something here.
 
Upvote 0

stevel05

Expert
Licensed User
Longtime User
But why would I get an error then when I try to read what then turns out to be the byte at position 2?

I think you answered this in your next question, you can't start in the middle of an object. It would be incomplete if it did succeed.

Is that because I need to read from a position where an object starts and not in the middle of it?

Yes

If it's a write once, read serially set of data, then using the RAF file in the simplest way will work fine. But unless you keep an index of the start of each record, you won't be able to jump to a specific record.

If there is that much data, and it has any importance, perhaps you should be looking to store it somewhere other than an SD card anyway.
 
Upvote 0

kostefar

Active Member
Licensed User
Longtime User
I think you answered this in your next question, you can't start in the middle of an object. It would be incomplete if it did succeed.



Yes

If it's a write once, read serially set of data, then using the RAF file in the simplest way will work fine. But unless you keep an index of the start of each record, you won't be able to jump to a specific record.

If there is that much data, and it has any importance, perhaps you should be looking to store it somewhere other than an SD card anyway.

Ok, I see what you´re saying here, what a shame it it can´t be done that way. But ok, I´ll keep all messages from every thread inside one file, and parse through them upon reading. Maybe it won´t have any impact on the speed afterall, and maybe I should consider internal memory instead although I know how that can be very easy to max out on some phones. Do you know which compression type is used by b4xobject, or what it´s similar to in effeciency?

Thanks for your answers!
 
Upvote 0

kostefar

Active Member
Licensed User
Longtime User
Hold on, now that I get the logic, it´s not a problem for me doing what I want to do:

Do While (RAF.CurrentPosition < RAF.Size )
Log ( RAF.Readb4xObject(RAF.CurrentPosition))

Loop

And I get each item, that were written with raf.size. Just what I needed!
 
Upvote 0
Top