DBF (dbf_ex v0.2.1)
Copy MarkdownRead FoxBase and dBASE DBF files.
DBFex provides read-only, positional access to records. For ordinary reads,
prefer with_open/2 or with_open/3; it owns the database resource for the
duration of the callback and closes it automatically:
DBF.with_open("customers.dbf", fn db ->
Enum.to_list(db)
end)Records and enumeration
An open DBF.Database implements Enumerable. Elements retain the physical
record status and have one of these forms:
{:record, %{"NAME" => "Ada"}}
{:deleted_record, %{"NAME" => "Grace"}}
{:error, %DBF.DatabaseError{}}Enumeration includes active and deleted records in file order. If decoding a
record fails, the error tuple is emitted as the final element. Use get/2 for
zero-based random access to a single physical record.
Options
The same options are accepted by open/2, open!/2, and with_open/3:
:memo_file- an explicit DBT path, ornilfor automatic companion discovery. Defaults tonil.:numeric-:floatfor compatible float results, or:exactfor integers andDecimalvalues. Defaults to:float.:encoding-:auto,:raw,:windows_1251, or:windows_1252. Defaults to:auto.:encoding_errors-:strict,:replace, or:raw. Defaults to:raw.
For example, to read exact numeric values and require valid Windows-1252 text:
DBF.with_open(
"customers.dbf",
[numeric: :exact, encoding: :windows_1252, encoding_errors: :strict],
fn db -> DBF.get(db, 0) end
)Resource ownership and errors
Use open/1,2 with close/1 when the database must outlive a callback, such
as for suspended enumeration. Every successful open must have a corresponding
close. close/1 is idempotent.
Non-bang operations return {:error, %DBF.DatabaseError{}}. open!/1,2
raises that same exception type when opening fails.
Summary
Functions
Closes the DBF and memo resources owned by an open database.
Gets a record by its zero-based physical index.
Opens a DBF file and returns an opaque database value.
Opens a DBF file, raising DBF.DatabaseError on failure.
Opens a database for the duration of a callback and always attempts to close it.
Types
@type close_result() :: :ok | error_result()
@type encoding() :: :auto | :raw | :windows_1251 | :windows_1252
@type encoding_error_policy() :: :strict | :replace | :raw
@type error_reason() ::
:file_not_found
| :file_error
| :close_failed
| :invalid_options
| :invalid_record_index
| :unsupported_version
| :missing_memo_file
| :unsupported_field_type
| :invalid_header
| :invalid_schema
| :invalid_record
| :invalid_memo
| :invalid_encoding
@type error_result() :: {:error, DBF.DatabaseError.t()}
@type numeric_policy() :: :float | :exact
@type open_result() :: {:ok, DBF.Database.t()} | error_result()
@type option() :: {:memo_file, String.t() | nil} | {:numeric, numeric_policy()} | {:encoding, encoding()} | {:encoding_errors, encoding_error_policy()}
@type options() :: [option()]
@type record_result() :: {record_status(), record()} | error_result()
@type record_status() :: :record | :deleted_record
@type with_open_result(result) :: result | error_result()
Functions
@spec close(DBF.Database.t()) :: close_result()
Closes the DBF and memo resources owned by an open database.
Closing the same database more than once is safe. After closing, the database must not be used for random access or resumed enumeration.
{:ok, db} = DBF.open("customers.dbf")
:ok = DBF.close(db)
:ok = DBF.close(db)
@spec get(DBF.Database.t(), term()) :: record_result()
Gets a record by its zero-based physical index.
Active and deleted records retain their status. Invalid indexes return an
:invalid_record_index database error.
DBF.with_open("customers.dbf", fn db ->
case DBF.get(db, 2) do
{:record, row} -> {:ok, row}
{:deleted_record, row} -> {:deleted, row}
{:error, error} -> {:error, error}
end
end)
@spec open(String.t(), options()) :: open_result()
Opens a DBF file and returns an opaque database value.
The caller owns the returned resource and must eventually call close/1.
Prefer with_open/2,3 when callback-scoped access is sufficient.
Options are described in the module documentation.
Example
case DBF.open("customers.dbf", numeric: :exact) do
{:ok, db} ->
try do
DBF.get(db, 0)
after
DBF.close(db)
end
{:error, error} ->
{:error, Exception.message(error)}
end
@spec open!(String.t(), options()) :: DBF.Database.t()
Opens a DBF file, raising DBF.DatabaseError on failure.
Like open/2, the caller owns the returned resource and must call close/1.
This is useful when failure should abort the current operation:
db = DBF.open!("customers.dbf")
try do
Enum.take(db, 10)
after
DBF.close(db)
end
@spec with_open(String.t(), (DBF.Database.t() -> result)) :: with_open_result(result) when result: term()
Opens a database for the duration of a callback and always attempts to close it.
This is the preferred lifecycle for complete reads. The callback result is returned unchanged. If opening or closing fails, an error tuple is returned. If the callback raises, throws, or exits, DBFex closes the resources before propagating the original failure.
The callback receives an enumerable DBF.Database and must not close it.
Examples
Read every physical record:
DBF.with_open("customers.dbf", fn db ->
Enum.to_list(db)
end)Pass decoding options and keep only active rows:
DBF.with_open("customers.dbf", [numeric: :exact], fn db ->
Enum.flat_map(db, fn
{:record, row} -> [row]
{:deleted_record, _row} -> []
{:error, error} -> raise error
end)
end)
@spec with_open(String.t(), options(), (DBF.Database.t() -> result)) :: with_open_result(result) when result: term()