Categories
ruby

Reading & Writing DBF files in ruby

DBFs are a set of database file formats similar to sqlite, except that each file will have only one table. The support for reading & writing dbase file formats in ruby is pretty rudimentary.

The following are the gems that can be used to read & write dbase files.

1. SHP

The file format it supports is xbase. It supports creation of columns of type string, integer and float only. The type codes for columns types are
0 -> string, 1 -> integer and 2 -> float respectively. Even though date is a valid xbase column type, it is not supported. Simple usage is

Add

gem shp

to you Gemfile.

Then the code to read the data from dbase is

#Open the file to read
dbf = SHP::DBF.open('path_to/file.dbf', 'rb+')
data = [] #variable to collect read data
dbf.get_record_count.times do |record_no|
  data[record_no] ||= []
  dbf.get_field_count.times do |column_no|
    # call appropriate function according to field type
    data[record_no][column_no] = case dbf.get_field_info(column_no)[:type]
                                  when 0
                                    dbf.read_string_attribute(record_no, column_no)
                                  when 1
                                    dbf.read_integer_attribute(record_no, column_no)
                                  when 2
                                    dbf.read_double_attribute(record_no, column_no)
                                  end
  end
end

puts data

While reading is kind of straight forward, writing to the dbf is a complicated affair. You have to create the file first then add field specifications and then add data.

require "shp"
#Open the file to write
dbf = SHP::DBF.create('file.dbf')

#declare type of columns
fields = [
            {name: 'name', type: 0, width: 25, decimals: 0}, 
            {name: 'age', type: 1, width: 19, decimals: 0}
        ]
fields.each do |field_info|
  dbf.add_field(field_info[:name], field_info[:type], field_info[:width], field_info[:decimals])
end

data = [['john', 28], ['mike', 21], ['jack', 20]]
data.each_with_index do |details, record_no|
 details.each_with_index do |value, index|
    case fields[index][:type]
    when 0
      dbf.write_string_attribute(record_no, index,  value)
    when 1
      dbf.write_integer_attribute(record_no, index, value)
    end
  end
end
#close the file after writing
dbf.close

2. DBF
This gem can only be used for reading from dbf files. One cannot use it to create dbf files.
To use as usual add to you Gemfile

gem 'dbf'

and

data = File.open('widgets.dbf')
widgets = DBF::Table.new(data)
#returns all file data into rows as an array of hashes with field names as keys
rows = widgets.map{|widget| widget.attributes }

3. Rbase

Rbase lacks documentation. But if you are used to wading through code in the wild, you will quickly get a hang of it and start writing & reading dbase files using this. It definitely provides a rich interface to reading
To read from a dbase file.

require "rbase"
require "date"
dbf = RBase::Table.open('file') #notice, without .dbf extension
records = []
dbf.each do |record|
  attr_hash = {}
  dbf.columns.each do |column|
    attribute_name = column.name
    attr_hash[attribute_name] = record.send(attribute_name)
  end
  records << attr_hash
end