B4J Question Convert a plain path string into a Java understandable String

rgarnett1955

Active Member
Licensed User
Longtime User
Hi,

I am trying to rename a file. I know the ntfs name of the string and the ntfs filename, but when I try to rename the file the command fails returns false.

Rename a file:
'======================================================================================================
Sub renameTo(Folder As String, FileName As String, NewFileName As String) As Object
    Dim fileJO As JavaObject
    fileJO.InitializeNewInstance("java.io.File", Array(File.Combine(Folder, FileName)))

    Dim newFileJO As JavaObject
    newFileJO.InitializeNewInstance("java.io.File", Array(File.Combine(Folder, NewFileName)))
    
    Return fileJO.RunMethod("renameTo", Array(newFileJO))
End Sub


'======================================================================================================
Sub btnClearRecentList_Click
    Dim jmf As MF_File
    Dim dataDir             = "G:\B4J\fileEntryClass\Files"
    Dim dbRecentFilename     = "RecentFilesDB.db"
    Dim backupFileName      = "RecentFilesDB_2020_09_14_13_04_27.db"

    result = renameTo(dataDir, dbRecentFilename, backupFileName)  '**** Fails ****
End Sub

It's obvious that the Java code doesn't like the format of the path and file names. I know you can convert a java type file object to the "canonical" pathname/filename, but how do you do the reverse so that the java code gets what it wants.

I want to use the "normal" ntfs filenames as there's too much smoke and mirrors in Java. You never know where its putting things or why. if you don't jnow where things are you can't be sure you are backing them up.

I know I could copy the file to the filename I want, but that's inefficient, OK for small files but not for large files and/or many at a time.

How can I do what I want?

best regards
Rob
 

rgarnett1955

Active Member
Licensed User
Longtime User
Hi Erel

Man you could be right about that.

The problem could be that the file I am renaming is a database file which I open using sqLite viz:

Open sqLite DB:
sqlRecent.InitializeSQLite(path, dbName, False)

I do this at the initialisation of my class as a store for recently used files.

However as far as I know there is no sqLite. Close command. I thought that the file handle was closed when all transactions are completed, but maybe not. It depends how the Java Gurus have implemented the Virtual File System for the sqLite C Code.

Here is a snippet of the VFS I wrote for my embedded system, is is the file close wrapper which interfaces between the sqLite amalgamation and the fatfs system:

VFS File Close command:
/*
**********************************************************************************
** Close a file.
*/
static int vfsClose(sqlite3_file *pFile)
{
    int rc;
    FRESULT result;     
 
    vfsFile *p = (vfsFile*)pFile;
  rc = vfsFlushBuffer(p);
  sqlite3_free(p->aBuffer);
  result = f_close(&p->fd);
    
    #if DEBUG_VFS == 1
    SEGGER_RTT_printf(0,RTT_CTRL_TEXT_BRIGHT_GREEN"File Close File Handle = %x   Result = %d   RC = %x\n",  &p->fd, result, rc);
    #endif       
    
  return rc;
}

It could be that our friends at Oracle or who write the drivers may not have implemented this part of the VFS.

The other issue I have is that renaming the db file alone doesn't do the full thing because the journals will need to be renamed to. If I could get the Pragma checkpoint command to work this wouldn't be an issue.

The renaming problem occurs even when I don't write a transaction to the database after opening the app.

I was using the renaming method to avoid having to copy all of the transactions. The idea is that if the user want's to clear the recent files list, it is done by renaming the original and creating an empty new one. That way if the user accidentally clears the list they can get the old one back.

I will have a poke around and see what I can come up with.

Best regards
Rob
 
Upvote 0

rgarnett1955

Active Member
Licensed User
Longtime User
Hi Erel,

It turns out there is a close command.

It looks like I have had another seniors moment.

I will give it a whorl.

Best regards
Rob
 
Upvote 0

rgarnett1955

Active Member
Licensed User
Longtime User
Hi Erel,

Guess what closing the db file fixed it.

I will now try using the close to get over my checkpoint problem.

Best regards
Rob
 
Upvote 0

rgarnett1955

Active Member
Licensed User
Longtime User
Hi Erel,

I tested the checkpoint command with a db.Close then open and it works sort of. It does transfer from WAL to main db file and it does truncate WAL to zero bytes. All Good

However it's supposed to return three columns:

The wal_checkpoint pragma returns a single row with three integer columns. The first column is usually 0 but will be 1 if a RESTART or FULL or TRUNCATE checkpoint was blocked from completing, for example because another thread or process was actively using the database. In other words, the first column is 0 if the equivalent call to sqlite3_wal_checkpoint_v2() would have returned SQLITE_OK or 1 if the equivalent call would have returned SQLITE_BUSY. The second column is the number of modified pages that have been written to the write-ahead log file. The third column is the number of pages in the write-ahead log file that have been successfully moved back into the database file at the conclusion of the checkpoint. The second and third column are -1 if there is no write-ahead log, for example if this pragma is invoked on a database connection that is not in WAL mode.

However if you try the following:

Checkpoint code:
    If doFullCheckPoint Then
        sqlRecent.Close
        sqlRecent.InitializeSQLite(path, dbName, False)
        
        Dim res As ResultSet

        qryStr = "PRAGMA wal_checkpoint(TRUNCATE);"
        Try
            'sqlRecent.ExecNonQuery(qryStr)   '*** Works but no return ***
            res = sqlRecent.ExecQuery(qryStr) '*** Fails with error below ***
        Catch
            Log(LastException)
            If logOn Then Log("Checkpoint TRUNCATE = Failed")
            Return False
        End Try

        If logOn Then Log("Checkpoint TRUNCATE = OK")
    End If

Error when using query that returns data [res = sqlRecent.ExecQuery(qryStr)] :
Waiting for debugger to connect...
Program started.
DB Integrity = OK
Set Journal Mode = WAL Mode = OK
DB Checkpoint Value Setting = OK
DB Integrity = OK
Error occurred on line: 935
java.sql.SQLException: query does not return results
    at org.sqlite.PrepStmt.executeQuery(PrepStmt.java:72)
    at anywheresoftware.b4j.objects.SQL.ExecQuery2(SQL.java:372)
    at anywheresoftware.b4j.objects.SQL.ExecQuery(SQL.java:353)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:632)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:234)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at jdk.internal.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:91)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.debug.Debug.delegate(Debug.java:64)
    at b4j.example.fileget._checkrecentfilesdb(fileget.java:2129)
    at b4j.example.fileget._dbrecentcloseandcheckpoint(fileget.java:310)
    at b4j.example.main._mainform_closed(main.java:225)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:632)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at jdk.internal.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:91)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.BA$1.run(BA.java:216)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)

In any event I have now got it working as I wanted so the fact it doesn't work quite right is not a deal breake, but more of a pain because no doubt someone else will go through all of this agony.

best regards
Rob
 
Upvote 0
Top