dbf

package module
v1.3.1-0...-6752e81 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: MIT Imports: 11 Imported by: 0

README

DBF Reader

CI Coverage Go Reference Release

A pure Go library for reading DBF (dBase, FoxPro, Visual FoxPro) files with support for multiple encodings.

Features

  • ✅ Read DBF files in various formats (dBase III, FoxPro, Visual FoxPro)
  • ✅ Automatic encoding detection from Language Driver ID
  • ✅ Support for multiple encodings (CP866, CP1251, CP1252, CP437, CP850)
  • ✅ Memory-efficient streaming for large files
  • ✅ Simple, idiomatic Go API
  • ✅ No external dependencies except golang.org/x/text

Installation

go get github.com/d1n-go/dbf

Quick Start

package main

import (
    "fmt"
    "log"
    
    "github.com/d1n-go/dbf"
)

func main() {
    // Open DBF file with explicit encoding
    reader, err := dbf.NewFromFile("data.dbf", dbf.WithCP866())
    if err != nil {
        log.Fatal(err)
    }
    
    // Read all records
    records, err := reader.ReadAll()
    if err != nil {
        log.Fatal(err)
    }
    
    // Process records
    for i, record := range records {
        if record.Deleted {
            continue // Skip deleted records
        }
        fmt.Printf("Record %d: %v\n", i+1, record.Data)
    }
}

Usage Examples

Streaming Large Files

For large files, use streaming to avoid loading everything into memory:

reader, err := dbf.NewFromFile("large.dbf", dbf.WithCP866())
if err != nil {
    log.Fatal(err)
}

for reader.Next() {
    record, err := reader.Read()
    if err != nil {
        log.Fatal(err)
    }
    
    // Process record
    name := record.Data["NAME"]
    fmt.Println(name)
}

if err := reader.Err(); err != nil {
    log.Fatal(err)
}
Auto-detect Encoding

If the DBF file has a valid Language Driver ID, encoding can be auto-detected:

reader, err := dbf.NewFromFile("data.dbf") // No encoding specified
if err != nil {
    log.Fatal(err)
}
Specify Custom Encoding
import "golang.org/x/text/encoding/charmap"

// Using convenience function
reader, err := dbf.NewFromFile("data.dbf", dbf.WithCP1251())

// Using charmap directly
reader, err := dbf.NewFromFile("data.dbf", dbf.WithEncoding(charmap.Windows1251))

// Using custom decoder
decoder := charmap.CodePage850.NewDecoder()
reader, err := dbf.NewFromFile("data.dbf", dbf.WithDecoder(decoder))
Read from io.Reader
file, err := os.Open("data.dbf")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

reader, err := dbf.New(file, dbf.WithCP866())
if err != nil {
    log.Fatal(err)
}
Access Field Metadata
reader, err := dbf.NewFromFile("data.dbf", dbf.WithCP866())
if err != nil {
    log.Fatal(err)
}

fmt.Printf("File Type: %s\n", reader.FileType())
fmt.Printf("Last Update: %s\n", reader.LastUpdate())
fmt.Printf("Total Records: %d\n", reader.RecordsCount())

fmt.Println("\nFields:")
for i, field := range reader.Fields() {
    fmt.Printf("%d. %s (%s) - Length: %d\n",
        i+1,
        field.Name,
        field.TypeString(),
        field.Length,
    )
}

Supported Encodings

The library automatically detects these encodings from Language Driver ID:

LDID Encoding Description
0x26 CP866 Russian MS-DOS
0x64, 0x65, 0xC9 CP1251 Russian Windows
0x03 CP1252 Windows ANSI
0x01 CP437 US MS-DOS
0x02 CP850 International MS-DOS

You can also specify any encoding manually using WithEncoding() or WithDecoder().

Supported Field Types

Type Description Go Type
C Character string
N Numeric string
D Date string (YYYYMMDD)
L Logical string ("true"/"false")
M Memo string
F Float string

All field values are returned as strings. Parse them as needed:

age, _ := strconv.Atoi(record.Data["AGE"])
price, _ := strconv.ParseFloat(record.Data["PRICE"], 64)
date, _ := time.Parse("20060102", record.Data["BIRTHDATE"])

API Documentation

Full API documentation is available at pkg.go.dev.

Testing

# Run tests
go test -v

# Run tests with coverage
go test -v -cover

# Run benchmarks
go test -bench=.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE file for details.

Acknowledgments

DBF format specification references:

Documentation

Overview

Package dbf provides functionality for reading DBF (dBase, FoxPro, Visual FoxPro) files.

The package supports various DBF file formats and encodings, with automatic encoding detection based on Language Driver ID when available.

Basic usage:

reader, err := dbf.NewFromFile("data.dbf", dbf.WithCP866())
if err != nil {
	log.Fatal(err)
}
defer reader.Close()

records, err := reader.ReadAll()
if err != nil {
	log.Fatal(err)
}

For large files, use streaming to avoid loading everything into memory:

for reader.Next() {
	record, err := reader.Read()
	if err != nil {
		log.Fatal(err)
	}
	// process record
}

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidFileType    = errors.New("invalid file type")
	ErrInvalidHeaderSize  = errors.New("invalid header size")
	ErrInvalidRecordSize  = errors.New("invalid record size")
	ErrUnknownEncoding    = errors.New("unable to determine encoding")
	ErrInvalidTerminator  = errors.New("invalid field descriptor terminator")
	ErrFieldOutOfBounds   = errors.New("field exceeds record bounds")
	ErrReadBeforeNext     = errors.New("Read called before Next")
	ErrRecordSizeMismatch = errors.New("record size mismatch")
)

Sentinel errors returned by the library.

Functions

This section is empty.

Types

type Field

type Field struct {
	Name          string // field name (max 11 characters)
	Type          byte   // field type (C=Character, N=Numeric, D=Date, L=Logical, M=Memo, F=Float)
	MemoryAddress uint32 // memory address (reserved, not used in file-based DBF)
	Length        uint16 // field length in bytes; uint16 to support VFP character fields > 255 bytes
	DecimalCount  byte   // number of decimal places (for numeric fields)
}

Field represents a single field definition in a DBF table.

func (Field) TypeString

func (f Field) TypeString() string

TypeString returns a human-readable description of the field type.

type FileType

type FileType byte

FileType represents the type of DBF file format.

const (
	FoxBASE           FileType = 0x02
	FoxBASEPlusNoMemo FileType = 0x03

	VisualObjects       FileType = 0x07
	VisualFoxPro        FileType = 0x30
	VisualFoxProAI      FileType = 0x31
	VisualFoxProVarchar FileType = 0x32

	FoxBASEPlusMemo   FileType = 0x83
	VisualObjectsMemo FileType = 0x87

	HiPerSix FileType = 0xE5
	FoxPro2  FileType = 0xF5
	FoxBASE2 FileType = 0xFB
)

Supported DBF file type constants.

func (FileType) String

func (ft FileType) String() string

String returns a human-readable description of the file type.

type Option

type Option func(*Reader)

Option is a functional option for configuring a Reader.

func WithCP866

func WithCP866() Option

WithCP866 sets the encoding to Code Page 866 (Russian MS-DOS). This is commonly used for Russian DBF files created in DOS.

func WithCP1251

func WithCP1251() Option

WithCP1251 sets the encoding to Windows-1251 (Russian Windows). This is commonly used for Russian DBF files created in Windows.

func WithCP1252

func WithCP1252() Option

WithCP1252 sets the encoding to Windows-1252 (Western European). This is the default Windows encoding for Western European languages.

func WithDecoder

func WithDecoder(decoder *encoding.Decoder) Option

WithDecoder sets a custom text encoding decoder for reading character fields. This is the most flexible option, allowing any encoding.Decoder to be used. A nil decoder is ignored; pass WithEncoding or WithCP* to set encoding explicitly.

func WithEncoding

func WithEncoding(cm *charmap.Charmap) Option

WithEncoding sets the text encoding using a charmap.Charmap. This is a convenience wrapper around WithDecoder.

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Reader provides methods for reading DBF files. It supports both streaming (Next/Read) and batch (ReadAll) reading modes.

Reader is not safe for concurrent use.

func New

func New(r io.Reader, opts ...Option) (*Reader, error)

New creates a new DBF Reader from an io.Reader.

If no encoding is specified via options, the reader will attempt to auto-detect the encoding from the Language Driver ID byte in the DBF header. If auto-detection fails, an error is returned.

Example:

file, _ := os.Open("data.dbf")
reader, err := dbf.New(file, dbf.WithCP866())

func NewFromFile

func NewFromFile(path string, opts ...Option) (*Reader, error)

NewFromFile creates a new DBF Reader from a file path. This is a convenience wrapper around New() for file-based reading.

Example:

reader, err := dbf.NewFromFile("data.dbf", dbf.WithCP866())

func (*Reader) Close

func (r *Reader) Close() error

func (*Reader) Err

func (r *Reader) Err() error

Err returns any error that occurred during iteration. It should be called after Next() returns false to check for errors.

func (*Reader) Fields

func (r *Reader) Fields() []Field

Fields returns the field definitions for the DBF table.

func (*Reader) FieldsCount

func (r *Reader) FieldsCount() int

FieldsCount returns the number of fields in the DBF table.

func (*Reader) FileType

func (r *Reader) FileType() FileType

FileType returns the DBF file type identifier.

func (*Reader) LastUpdate

func (r *Reader) LastUpdate() time.Time

LastUpdate returns the date when the DBF file was last modified.

func (*Reader) Next

func (r *Reader) Next() bool

Next advances to the next record in the DBF file. It returns false when there are no more records or an error occurred. Use Err() to check for errors after the iteration completes.

Example:

for reader.Next() {
	record, err := reader.Read()
	if err != nil {
		log.Fatal(err)
	}
	// process record
}
if err := reader.Err(); err != nil {
	log.Fatal(err)
}

func (*Reader) Read

func (r *Reader) Read() (*Record, error)

Read reads the current record. Must be called after a successful Next() call. Returns an error if reading fails or if called without a prior Next() call.

func (*Reader) ReadAll

func (r *Reader) ReadAll() ([]*Record, error)

func (*Reader) RecordsCount

func (r *Reader) RecordsCount() uint32

RecordsCount returns the total number of records in the DBF file, including deleted records.

func (*Reader) String

func (r *Reader) String() string

String returns a string representation of the Reader for debugging.

type Record

type Record struct {
	Deleted bool              // true if the record is marked as deleted
	Data    map[string]string // field values indexed by field name
}

Record represents a single record from the DBF file.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL