// numLine is the current line being read in the CSV file.
numLine int
+ // offset is the input stream byte offset of the current reader position.
+ offset int64
+
// rawBuffer is a line buffer only used by the readLine method.
rawBuffer []byte
return p.line, p.col
}
+// InputOffset returns the input stream byte offset of the current reader
+// position. The offset gives the location of the end of the most recently
+// read row and the beginning of the next row.
+func (r *Reader) InputOffset() int64 {
+ return r.offset
+}
+
// pos holds the position of a field in the current line.
type position struct {
line, col int
}
line = r.rawBuffer
}
- if len(line) > 0 && err == io.EOF {
+ readSize := len(line)
+ if readSize > 0 && err == io.EOF {
err = nil
// For backwards compatibility, drop trailing \r before EOF.
- if line[len(line)-1] == '\r' {
- line = line[:len(line)-1]
+ if line[readSize-1] == '\r' {
+ line = line[:readSize-1]
}
}
r.numLine++
+ r.offset += int64(readSize)
// Normalize \r\n to \n on all input lines.
if n := len(line); n >= 2 && line[n-2] == '\r' && line[n-1] == '\n' {
line[n-2] = '\n'
}}
func TestRead(t *testing.T) {
- newReader := func(tt readTest) (*Reader, [][][2]int, map[int][2]int) {
+ newReader := func(tt readTest) (*Reader, [][][2]int, map[int][2]int, string) {
positions, errPositions, input := makePositions(tt.Input)
r := NewReader(strings.NewReader(input))
r.LazyQuotes = tt.LazyQuotes
r.TrimLeadingSpace = tt.TrimLeadingSpace
r.ReuseRecord = tt.ReuseRecord
- return r, positions, errPositions
+ return r, positions, errPositions, input
}
for _, tt := range readTests {
t.Run(tt.Name, func(t *testing.T) {
- r, positions, errPositions := newReader(tt)
+ r, positions, errPositions, input := newReader(tt)
out, err := r.ReadAll()
if wantErr := firstError(tt.Errors, positions, errPositions); wantErr != nil {
if !reflect.DeepEqual(err, wantErr) {
}
}
+ // Check input offset after call ReadAll()
+ inputByteSize := len(input)
+ inputOffset := r.InputOffset()
+ if err == nil && int64(inputByteSize) != inputOffset {
+ t.Errorf("wrong input offset after call ReadAll():\ngot: %d\nwant: %d\ninput: %s", inputOffset, inputByteSize, input)
+ }
+
// Check field and error positions.
- r, _, _ = newReader(tt)
+ r, _, _, _ = newReader(tt)
for recNum := 0; ; recNum++ {
rec, err := r.Read()
var wantErr error