Add Seek and RecordIndex for random record access - #283
Merged
Conversation
Reading was strictly forward-only: there was no way to jump to a record by index or to tell which record had just been read. DbfTable.Seek(recordIndex) positions the stream at the given zero-based record using the header's HeaderLength and RecordLength, and DbfRecord.RecordIndex reports the zero-based index of the record most recently read (-1 before any read). The index is derived from the stream position rather than a counter, so it stays correct across seeks and interleaved readers. DbfDataReader exposes both. The offset math accounts for streams where the DBF content starts at a non-zero position (the table captures the stream position at construction), and seeking past the last record simply causes the next read to return no record. This is groundwork for CDX index support, where index searches yield record numbers that need to be turned into rows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
This was referenced Jul 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Reading has been strictly forward-only — no way to jump to a record by index, and no way to tell which record was just read. This adds:
DbfTable.Seek(int recordIndex)— positions the table at the given zero-based record (dataStart + recordIndex * RecordLength). Also exposed asDbfDataReader.Seek. Negative indexes throwArgumentOutOfRangeException; non-seekable streams throwNotSupportedException; seeking past the last record is allowed and simply makes the nextRead()returnfalse(deliberately not validated againstHeader.RecordCount, which is unreliable in real-world files).DbfRecord.RecordIndex— zero-based index of the record most recently read,-1before any read. Also exposed asDbfDataReader.RecordIndex. The value is derived from the stream position rather than a counter, so it stays correct across seeks and across multipleDbfRecords reading interleaved from one table. WithSkipDeletedRecords, it reports the file index of the record actually surfaced.Design notes
Seek(record.RecordIndex)+Readre-reads the current record — one consistent convention. (xBase record numbers are traditionally 1-based; a future CDX index integration will convert in one documented place.)Seekto become rows.Test plan
New
SeekTests(8 tests): sequentialRecordIndextracking (-1 → 0..13), seek-then-read matches sequential values, rewind after full scan, seek past end reads nothing, negative index throws, non-seekable stream throws, DBF embedded at a non-zero stream offset seeks correctly, and theDbfDataReader-levelSeek/RecordIndexpath. Full suite: 112 passed, 1 skipped (pre-existing WIP skip).🤖 Generated with Claude Code