Browse | Submit A New Snippet | Create A Package

 

XBase/DBase Reader class

Type:
Class
Category:
Database Manipulation
License:
GNU General Public License
Language:
Ruby
 
Description:
A class to allow access to DBase DBF files.

Versions Of This Snippet::

Lyndon Samson
Snippet ID Download Version Date Posted Author Delete
820.12005-04-01 10:26Lyndon Samson

Download a raw-text version of this code by clicking on "Download Version"

 


Latest Snippet Version: :0.1

class XBaseReader
  def initialize(fileName)
    @fileName  = fileName
    readDBASEMetaInfo()

    @filter = Proc.new { |record| true }
  end

  def readDBASEMetaInfo()
    ios = File.open(@fileName,"rb")

    @hdr         = {}
    buff         = ios.read(11)
    @hdr['size'] = (buff[8..9].unpack('S'))[0]
  
    ios.rewind

    hdrBuff            = ios.read(@hdr['size'])
    @hdr['type']       = hdrBuff[0]
    @hdr['records']    = (hdrBuff[4..7].unpack('L'))[0]
    @hdr['recordSize'] = (hdrBuff[10..11].unpack('S'))[0]
  

    # read field info from hdr
    @flds = [] 
    @fldNames = {}
    start = 32
  
    while 1 == 1  
      fldInfo = hdrBuff[start..(start+31)]  
      break if fldInfo[0] == 0x0d

      fld           = {}
      fld['name']   = fldInfo[0..10].strip
      fld['type']   = sprintf("%c",fldInfo[11])
      fld['length'] = fldInfo[16]
      @flds << fld
      xx = fld['name']
      @fldNames[xx] = @flds.size-1    
      start= start+32
    end

    ios.close

  end
  def fields
    @flds
  end
  
  def hdr(name)
    @hdr[name]
  end
  def fieldName(pos)
    @flds[pos]['name']
  end
  def fieldIndex(fldName)
    @fldNames[fldName]
  end
  def setFilter(&filterProc)
    if block_given?
      @filter = filterProc	  
    else
      @filter = Proc.new { |record| true }
    end
    
  end

  def list(startRecord=0)
    recCnt = 0
    ios = File.open(@fileName,"rb")
    ios.pos = @hdr['size'] + (@hdr['recordSize']*startRecord)

    @hdr['records'].times { |i|
    #10.times { |i|
      buff = ios.read(@hdr['recordSize'])
      break if buff == nil 
      break if buff.size != @hdr['recordSize'] # need this due to extra chars appended unexpectedly 
	      
      fldStartPos = 0

      currRec = []
      
      @flds.each { |fld|
        if fld['type'] == 'D'
          endPos = fldStartPos+fld['length']
          incr = fld['length']+1
        end
	# if fld['type'] == 'C' || fld['type'] == 'N' 
        if "CN".count(fld['type']) > 0 
          endPos = fldStartPos+fld['length']-1
          incr = fld['length']
        end
        val = buff[fldStartPos..endPos].to_s.strip
        fldStartPos = fldStartPos+incr
      
	currRec << val
	#puts "Name(#{fld['name']} Type(#{fld['type']}) Length(#{fld['length']}) Value(#{val})"
	#print "(#{val}) "
      }

      
      if @filter.call(currRec) 
        yield currRec 
	recCnt = recCnt + 1
      end
      #puts
      #puts buff

    }
  
    #puts buff

    ios.close

    return recCnt
  end
end
		

Submit a new version

You can submit a new version of this snippet if you have modified it and you feel it is appropriate to share with others..