Class ShapefileDbfReader

java.lang.Object
edu.cnu.mdi.mapping.shapefile.ShapefileDbfReader
All Implemented Interfaces:
Closeable, AutoCloseable

public final class ShapefileDbfReader extends Object implements Closeable
Zero-dependency reader for dBASE III (.dbf) attribute tables as used in ESRI Shapefiles.

File format overview

A .dbf file consists of:

  1. A 32-byte file header containing the record count, header size, and record size.
  2. One 32-byte field descriptor per column, terminated by a 0x0D byte.
  3. A sequence of fixed-width data records, each preceded by a one-byte deletion flag (0x20 = valid, 0x2A = deleted).

All integers in the header are little-endian. Field values are stored as fixed-width, space-padded ASCII (or the file's declared charset).

Usage


 try (ShapefileDbfReader dbf = new ShapefileDbfReader(path)) {
     List<Map<String, String>> records = dbf.readAllRecords();
     for (Map<String, String> record : records) {
         String name = record.get("ADMIN");
         String iso  = record.get("ISO_A3");
     }
 }
 

Character encoding

Natural Earth shapefiles use UTF-8 or ISO-8859-1. By default this reader uses UTF-8 (StandardCharsets.UTF_8); callers can override this with ShapefileDbfReader(Path, Charset). The dBASE language-driver byte at offset 29 is read but not acted upon — explicit charset specification is more reliable in practice.

Thread safety

Instances are not thread-safe. Each calling thread should open its own reader.

  • Constructor Details

    • ShapefileDbfReader

      public ShapefileDbfReader(Path path) throws IOException
      Opens the .dbf file at the given path using UTF-8 encoding for field values.
      Parameters:
      path - path to the .dbf file; must not be null
      Throws:
      IOException - if the file cannot be opened or the header is malformed
    • ShapefileDbfReader

      public ShapefileDbfReader(Path path, Charset charset) throws IOException
      Opens the .dbf file at the given path using the specified character encoding for field values.
      Parameters:
      path - path to the .dbf file; must not be null
      charset - character encoding to use when decoding field values; must not be null
      Throws:
      IOException - if the file cannot be opened or the header is malformed
  • Method Details

    • getRecordCount

      public int getRecordCount()
      Returns the number of data records declared in the file header.

      This includes records marked as deleted. readAllRecords() preserves this positional record count by representing deleted records as empty maps.

      Returns:
      declared record count (≥ 0)
    • getFields

      Returns an unmodifiable view of the field descriptors in column order.
      Returns:
      list of ShapefileDbfReader.FieldDescriptor instances
    • getFieldNames

      public List<String> getFieldNames()
      Returns the names of all fields in column order.
      Returns:
      ordered list of field name strings
    • readAllRecords

      public List<Map<String,String>> readAllRecords() throws IOException
      Reads and returns all records as an ordered list of String-valued maps.

      Each map key is the field name (trimmed, upper-cased as stored in the dBASE header). Each map value is the decoded, whitespace-trimmed field value, or an empty string if the field contained only spaces.

      This is a sequential full-scan; the channel is rewound to the first data record before reading begins. Deleted records (deletion flag 0x2A) are represented by empty maps so that DBF record indexes remain aligned with the corresponding shapefile geometry records. Any other flag besides the valid-record marker 0x20 causes an IOException.

      Returns:
      unmodifiable list of records, each a field-name → value map
      Throws:
      IOException - if a read error occurs
    • readRecord

      public Map<String,String> readRecord(int index) throws IOException
      Reads a single record by its zero-based index.

      This performs a seek to the record's position rather than a sequential scan, making it efficient for random access. Returns null if the record is marked deleted.

      Parameters:
      index - zero-based record index; must be in [0, recordCount)
      Returns:
      field-name → value map, or null if the record is deleted
      Throws:
      IOException - if a read error occurs
      IndexOutOfBoundsException - if index is out of range
    • close

      public void close() throws IOException
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Throws:
      IOException