B4J Code Snippet [DBF] Read/Write DBF file using jDBF

The example above works but the characters are not displaying correctly. With some trial-and-error, I finally get it works like the Test.java

TestRead:
'Non-UI application (console / server application)
#Region Project Attributes
    #CommandLineArgs:
    #MergeLibraries: True
    #AdditionalJar: jdbf-1.2.jar
#End Region

Sub Process_Globals

End Sub

Sub AppStart (Args() As String)
    ' Set charset to GBK
    Dim CSet As JavaObject
    CSet.InitializeStatic("java.nio.charset.Charset")
    Dim cs As Object = CSet.RunMethod("forName", Array As String("GBK"))
 
    ' Initialize DBF Reader
    Dim dbfReader As JavaObject
    dbfReader.InitializeNewInstance ("com.hexiong.jdbf.DBFReader", Array As Object ("book2.dbf")) ' D:\Development\B4J\DBF\Objects\

    ' Get field name
    Dim FieldsName As String
    Dim FieldsCount As Object = dbfReader.RunMethod("getFieldCount", Null)
    For i = 0 To FieldsCount - 1
        Dim Fld As JavaObject = dbfReader.RunMethod("getField", Array As Object(i))
        Dim Nam As String = Fld.RunMethod("getName", Null)
        FieldsName = FieldsName & $"${Nam}  |  "$
    Next
    Log(FieldsName)
 
    ' Read fields
    Do While dbfReader.RunMethod("hasNextRecord", Null)
        Dim res() As Object = dbfReader.RunMethod("nextRecord", Array As Object(cs))
        Dim row As String
        For Each Field In res
            row = row & $"${Field}  |  "$
        Next
        Log(row & CRLF)
    Loop
 
    ' Close the dbf file
    dbfReader.RunMethod ("close", Null)
End Sub

TestWrite:
'Non-UI application (console / server application)
#Region Project Attributes
    #CommandLineArgs:
    #MergeLibraries: True
    #AdditionalJar: jdbf-1.2.jar
#End Region

Sub Process_Globals

End Sub

Sub AppStart (Args() As String)
    TestWrite
End Sub

Sub TestRead
    ' Initialize DBF Reader
    Dim dbfReader As JavaObject
    dbfReader.InitializeNewInstance("com.hexiong.jdbf.DBFReader", Array As Object ("testwrite.dbf"))

    ' Get field name
    Dim FieldsName As String
    Dim FieldsCount As Object = dbfReader.RunMethod("getFieldCount", Null)
    For i = 0 To FieldsCount - 1
        Dim Fld As JavaObject = dbfReader.RunMethod("getField", Array As Object(i))
        Dim Nam As String = Fld.RunMethod("getName", Null)
        FieldsName = FieldsName & $"${Nam}  |  "$
    Next
    Log(FieldsName)
 
    ' Read fields
    i = 0
    Do While dbfReader.RunMethod("hasNextRecord", Null)
        Dim res() As Object = dbfReader.RunMethod("nextRecord", Null)
        Dim row As String
        For Each Field In res
            row = row & $"${Field}  |  "$
        Next
        Log(row & CRLF)
        i = i + 1
    Loop
    Log("Total Count: " & i)
 
    ' Close the dbf file
    dbfReader.RunMethod("close", Null)
End Sub

Sub TestWrite
    ' Initialize JDB Fields
    Dim t1 As Char = "C"
    Dim t2 As Char = "N"
    Dim t3 As Char = "F"
    Dim t4 As Char = "D"
 
    Dim JDBField As JavaObject
    Dim col1 As JavaObject = JDBField.InitializeNewInstance("com.hexiong.jdbf.JDBField", Array("ID", t1, 8, 0))
    Dim JDBField As JavaObject
    Dim col2 As JavaObject = JDBField.InitializeNewInstance("com.hexiong.jdbf.JDBField", Array("Name", t1, 254, 0))
    Dim JDBField As JavaObject
    Dim col3 As JavaObject = JDBField.InitializeNewInstance("com.hexiong.jdbf.JDBField", Array("TestN", t2, 20, 0))
    Dim JDBField As JavaObject
    Dim col4 As JavaObject = JDBField.InitializeNewInstance("com.hexiong.jdbf.JDBField", Array("TestF", t3, 20, 6))
    Dim JDBField As JavaObject
    Dim col5 As JavaObject = JDBField.InitializeNewInstance("com.hexiong.jdbf.JDBField", Array("TestD", t4, 8, 0))
 
    Dim JDBFields As JavaObject
    Dim fields() As Object = JDBFields.InitializeArray("com.hexiong.jdbf.JDBField", Array(col1, col2, col3, col4, col5))
 
    ' Initialize DBF Writer
    Dim dbfWriter As JavaObject
    dbfWriter.InitializeNewInstance("com.hexiong.jdbf.DBFWriter", Array As Object ("testwrite.dbf", fields))

    Dim row1 As Object = Array("1", "hexiong ", 500, 500.123, CurrentDate)
    Dim row2 As Object = Array("2", " hefang ", 600, 600.234, CurrentDate)
    Dim row3 As Object = Array("3", "hexi01234567890123456789012345678901234567890123456789" & _
    "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" & _
    "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", 600, 600.234, CurrentDate)
    Dim row4 As Object = Array("4", "heqiang", 700, 700.456, CurrentDate)

    Dim records() As Object
    records = Array As Object(row1, row2, row3, row4)
    For i = 0 To records.Length - 1
        dbfWriter.RunMethod("addRecord", Array(records(i)))
    Next
 
    ' Close the dbf file
    dbfWriter.RunMethod("close", Null)
 
    Log("testwrite.dbf write finished.......")
    TestRead
End Sub

Sub CurrentDate As Object
    Dim jo As JavaObject
    jo.InitializeNewInstance("java.util.Date", Null)
    'Log(jo)
    Return jo
End Sub

jDBF is available for free download here: https://code.google.com/archive/p/jdbf/downloads

Updates:
Reupload to GitHub as version 1.3 https://github.com/pyhoon/jdbf
version: 1.4
- Fix trim of String field
- Fix logical value with blank space as False
version: 1.5
- Fix error when not trim on number field
version: 1.6
- Fix error when not trim on date field

Modified source code attached jdbf.zip (IntelliJ IDEA project)
 

Attachments

  • DBF.zip
    1.8 KB · Views: 260
  • book2.zip
    3.9 KB · Views: 257
  • jdbf-1.3.jar
    13.6 KB · Views: 248
Last edited:

AnandGupta

Expert
Licensed User
Longtime User
Another point, how to close the opened dbf after read ?
Now it stays shared opened.

Got it.
 
Last edited:

AnandGupta

Expert
Licensed User
Longtime User
Hi @aeric

I have another problem which I could not fix. See if you can give me a hand here.

Our clients enter string data with some leading spaces so that it shows above in sorted list.
Now jDBF trims all spaces both left and right, so I get the data without any leading spaces.
The right trim is Ok for me, but left trim is problem, as I need to show the list as it shows in my XBase++ application.

I changed " INVESTMENTS" value to have 2 leading spaces, in book2.dbf (attached),
You can see the logs as in screen shots attached, also below text

B4X:
11
B  |  I  |  03  |  CURRENT LIABILITIES & PROVISIONS  |  02  |  Provisions  |  03  |  02  |    |    |  false  |    |  
12
B  |  O  |  04  |  FIXED ASSETS  |    |    |  01  |    |    |    |  false  |    |  
13
B  |  O  |  04  |  FIXED ASSETS  |  01  |  Net Block  |  01  |  01  |    |    |  false  |    |  
14
B  |  O  |  04  |  FIXED ASSETS  |  02  |  Capital Work In Progress  |  01  |  02  |    |    |  false  |    |  
15
B  |  O  |  05  |  INVESTMENTS  |    |    |  02  |    |    |    |  false  |    |  
16
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |    |    |  03  |  01  |    |    |  false  |    |  
17
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  01  |  Inventories  |  03  |  02  |    |    |  false  |    |  
18
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  02  |  Sundry Debtors  |  03  |  03  |    |    |  false  |    |  
19
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  03  |  Cash & Bank Balances  |  03  |  04  |    |    |  false  |    |  
20
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  04  |  Other Current Assets  |  03  |  05  |    |    |  false  |    |  
21
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  05  |  Loans & Advances  |  03  |  06  |    |    |  false  |    |

The "INVESTMENTS" do not have the leading spaces.

I studied the java code of the jDBF source but do not understand how to fix / change it, as I have limited Java knowledge.
I hope you can guide me here.
 

Attachments

  • book2.zip
    854 bytes · Views: 146
  • ba2.png
    ba2.png
    21.6 KB · Views: 144
  • ba1.png
    ba1.png
    26.8 KB · Views: 142

aeric

Expert
Licensed User
Longtime User
Hi @aeric

I have another problem which I could not fix. See if you can give me a hand here.

Our clients enter string data with some leading spaces so that it shows above in sorted list.
Now jDBF trims all spaces both left and right, so I get the data without any leading spaces.
The right trim is Ok for me, but left trim is problem, as I need to show the list as it shows in my XBase++ application.

I changed " INVESTMENTS" value to have 2 leading spaces, in book2.dbf (attached),
You can see the logs as in screen shots attached, also below text

B4X:
11
B  |  I  |  03  |  CURRENT LIABILITIES & PROVISIONS  |  02  |  Provisions  |  03  |  02  |    |    |  false  |    | 
12
B  |  O  |  04  |  FIXED ASSETS  |    |    |  01  |    |    |    |  false  |    | 
13
B  |  O  |  04  |  FIXED ASSETS  |  01  |  Net Block  |  01  |  01  |    |    |  false  |    | 
14
B  |  O  |  04  |  FIXED ASSETS  |  02  |  Capital Work In Progress  |  01  |  02  |    |    |  false  |    | 
15
B  |  O  |  05  |  INVESTMENTS  |    |    |  02  |    |    |    |  false  |    | 
16
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |    |    |  03  |  01  |    |    |  false  |    | 
17
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  01  |  Inventories  |  03  |  02  |    |    |  false  |    | 
18
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  02  |  Sundry Debtors  |  03  |  03  |    |    |  false  |    | 
19
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  03  |  Cash & Bank Balances  |  03  |  04  |    |    |  false  |    | 
20
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  04  |  Other Current Assets  |  03  |  05  |    |    |  false  |    | 
21
B  |  O  |  06  |  CURRENT ASSETS, LOANS & ADVANCES  |  05  |  Loans & Advances  |  03  |  06  |    |    |  false  |    |

The "INVESTMENTS" do not have the leading spaces.

I studied the java code of the jDBF source but do not understand how to fix / change it, as I have limited Java knowledge.
I hope you can guide me here.
I think I found the Java code that trim the String. I try to recompile the library again.
 

AnandGupta

Expert
Licensed User
Longtime User
Yes! Now both leading and trailing spaces are printing.
Thanks a lot. 🙏

The trim() code is in line #225 of JDBField.java
Ahh..I also see it now :) after your direction.

Can I compile the sources ? Say if I want to play with it more. I do not know how to do it.
 

aeric

Expert
Licensed User
Longtime User
Yes! Now both leading and trailing spaces are printing.
Thanks a lot. 🙏


Ahh..I also see it now :) after your direction.

Can I compile the sources ? Say if I want to play with it more. I do not know how to do it.
Yes, you can recompile the source on your own.
I use IntelliJ and Build artifact to output the jar file. I will upload my modified version later.
 

AnandGupta

Expert
Licensed User
Longtime User
Now with 1.4 jar I am getting below error in one of my dbf, (it is Ok in 1.3)
B4X:
>CLASS<  |  >CDES<  |  >TAG<  |  >TYPE<  |  >ORDER<  |  >ASSNO<  |  >TFTYPE<  |  >CHAPTER<  |  >CTSH<  |  >S_CAT<  |  >STATE_ID<  |  >CATEGORY<  |  >YS_ACEDNS<  |  >Y_AMIT<  |  
main._appstart (java line: 87)
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
    at b4j.example.main._appstart(main.java:87)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:109)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:96)
    at b4j.example.main.main(main.java:28)
Caused by: com.hexiong.jdbf.JDBFException: For input string: "  1"
    at com.hexiong.jdbf.JDBField.parse(JDBField.java:251)
    at com.hexiong.jdbf.DBFReader.nextRecord(DBFReader.java:249)
    ... 13 more

I have attached the dbf, named as book2. I do not think removal of .trim() is causing it, but you can understand the java error.
 

Attachments

  • book2.zip
    3.5 KB · Views: 152

aeric

Expert
Licensed User
Longtime User
Caused by: com.hexiong.jdbf.JDBFException: For input string: " 1"
Yes, it is caused by removal of trim().
Need to know which row and field type to fix it.

Edit: Found the bug. Uploaded jdbf-1.5.jar in post #1.

JDBField.java:
    public Object parse(String s) throws JDBFException {
        // s = s.trim();
        if (type == 'N' || type == 'F') {
            s = s.trim(); // <-- Moved to here
            if (s.equals("")) {
                s = "0";
            }
            try {
                if (getDecimalCount() == 0) {
                    return new Long(s);
                } else {
                    return new Double(s);
                }
            } catch (NumberFormatException numberformatexception) {
                throw new JDBFException(numberformatexception);
            }
        }
 
Last edited:

OliverA

Expert
Licensed User
Longtime User
The problem is that Java’s trim is an all or nothing trim when it comes to removing white spaces from the front AND rear of a string. DBF expects only the removal of trailing spaces. Here is a link to a solution to the issue (and it depends on Java version used to compile the library).

 

AnandGupta

Expert
Licensed User
Longtime User
Now we also need to .trim() date as if blank it gives below error, (I now learnt how to check the error, from your hints :) )
B4X:
>CNAME<  |  >CADD1<  |  >BLEN<  |  >TLEN<  |  >DT1<  |  >DT2<  |  >INDIVIDUAL<  |  >PRET<  |  >SRET<  |  
main._appstart (java line: 87)
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
    at b4j.example.main._appstart(main.java:87)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:109)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:96)
    at b4j.example.main.main(main.java:28)
Caused by: com.hexiong.jdbf.JDBFException: java.text.ParseException: Unparseable date: "        " value=[        ]
    at com.hexiong.jdbf.JDBField.parse(JDBField.java:269)
    at com.hexiong.jdbf.DBFReader.nextRecord(DBFReader.java:249)
    ... 13 more

Attached 'book2.dbf' modified with blank date.
 

Attachments

  • BOOK2.ZIP
    286 bytes · Views: 136

AnandGupta

Expert
Licensed User
Longtime User
The problem is that Java’s trim is an all or nothing trim when it comes to removing white spaces from the front AND rear of a string. DBF expects only the removal of trailing spaces. Here is a link to a solution to the issue (and it depends on Java version used to compile the library).
My problem is not removing the spaces, which I can do in B4X itself. Problem is to get string value as it is, i.e. both leading and trailing spaces.
jDBF as modified by Aeric now does it.
 

aeric

Expert
Licensed User
Longtime User
Now we also need to .trim() date as if blank it gives below error, (I now learnt how to check the error, from your hints :) )
B4X:
>CNAME<  |  >CADD1<  |  >BLEN<  |  >TLEN<  |  >DT1<  |  >DT2<  |  >INDIVIDUAL<  |  >PRET<  |  >SRET<  |
main._appstart (java line: 87)
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4j.object.JavaObject.RunMethod(JavaObject.java:132)
    at b4j.example.main._appstart(main.java:87)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:109)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:96)
    at b4j.example.main.main(main.java:28)
Caused by: com.hexiong.jdbf.JDBFException: java.text.ParseException: Unparseable date: "        " value=[        ]
    at com.hexiong.jdbf.JDBField.parse(JDBField.java:269)
    at com.hexiong.jdbf.DBFReader.nextRecord(DBFReader.java:249)
    ... 13 more

Attached 'book2.dbf' modified with blank date.
Updated version 1.6 in post #1.

Edit: Updated as version 1.3 in post #1.
 
Last edited:
Top