/// <summary> /// Reads a record specified by index. This method requires the stream to be able to seek to position. /// If you are using a http stream, or a stream that can not stream, use ReadNext() methods to read in all records. /// </summary> /// <param name="index">Zero based index.</param> /// <returns>Null if record can not be read, otherwise returns a new record.</returns> public DbfRecord Read(int index) { //create a new record and fill it. DbfRecord orec = new DbfRecord(_header); return(Read(index, orec) ? orec : null); }
/// <summary> /// Tries to read a record and returns a new record object or null if nothing was read. /// </summary> /// <returns></returns> public DbfRecord ReadNext() { //create a new record and fill it. DbfRecord orec = new DbfRecord(_header); return(ReadNext(orec) ? orec : null); }
public void Write(DbfRecord orec, bool bClearRecordAfterWrite) { Write(orec); if (bClearRecordAfterWrite) { orec.Clear(); } }
/// <summary> /// Update a record. RecordIndex (zero based index) must be more than -1, otherwise an exception is thrown. /// You can also use Write method which updates a record if it has RecordIndex or adds a new one if RecordIndex == -1. /// RecordIndex is set automatically when you call any Read() methods on this class. /// </summary> /// <param name="orec"></param> public void Update(DbfRecord orec) { //if header was never written, write it first, then output the record if (!_headerWritten) { WriteHeader(); } //Check if record has an index if (orec.RecordIndex < 0) { throw new Exception("RecordIndex is not set, unable to update record. Set RecordIndex or call Write() method to add a new record to file."); } //Check if this record matches record size specified by header and number of columns. //Client can pass a record from another DBF that is incompatible with this one and that would corrupt the file. if (orec.Header != _header && (orec.Header.ColumnCount != _header.ColumnCount || orec.Header.RecordLength != _header.RecordLength)) { throw new Exception("Record parameter does not have the same size and number of columns as the " + "header specifies. Writing this record would corrupt the DBF file. " + "This is a programming error, have you mixed up DBF file objects?"); } //DBF file writer can be null if stream is not writable to... if (_dbfFileWriter == null) { throw new Exception("Write stream is null. Either you have opened a stream that can not be " + "writen to (a read-only stream) or you have not opened a stream at all."); } //move to the specified record, note that an exception will be thrown if stream is not seekable! //This is ok, since we provide a function to check whether the stream is seekable. long nSeekToPosition = (long)_header.HeaderLength + (long)((long)orec.RecordIndex * (long)_header.RecordLength); //check whether we can seek to this position. Subtract 1 from file length (there is a terminating character 1A at the end of the file) //so if we hit end of file, there are no more records, so return false; if (_dbfFile.Length < nSeekToPosition) { throw new Exception("Invalid record position. Unable to save record."); } //move to record start _dbfFile.Seek(nSeekToPosition, SeekOrigin.Begin); //write orec.Write(_dbfFile); _footerUpdateNeeded = true; }
/// <summary> /// Reads a record specified by index into oFillRecord object. You can use this method /// to read in and process records without creating and discarding record objects. /// Note that you should check that your stream is not forward-only! If you have a forward only stream, use ReadNext() functions. /// </summary> /// <param name="index">Zero based record index.</param> /// <param name="oFillRecord">Record object to fill, must have same size and number of fields as thid DBF file header!</param> /// <remarks> /// <returns>True if read a record was read, otherwise false. If you read end of file false will be returned and oFillRecord will NOT be modified!</returns> /// The parameter record (oFillRecord) must match record size specified by the header and number of columns as well. /// It does not have to come from the same header, but it must match the structure. We are not going as far as to check size of each field. /// The idea is to be flexible but safe. It's a fine balance, these two are almost always at odds. /// </remarks> public bool Read(int index, DbfRecord oFillRecord) { //check if we can fill this record with data. it must match record size specified by header and number of columns. //we are not checking whether it comes from another DBF file or not, we just need the same structure. Allow flexibility but be safe. if (oFillRecord.Header != _header && (oFillRecord.Header.ColumnCount != _header.ColumnCount || oFillRecord.Header.RecordLength != _header.RecordLength)) { throw new Exception("Record parameter does not have the same size and number of columns as the " + "header specifies, so we are unable to read a record into oFillRecord. " + "This is a programming error, have you mixed up DBF file objects?"); } //DBF file reader can be null if stream is not readable... if (_dbfFileReader == null) { throw new Exception("ReadStream is null, either you have opened a stream that can not be " + "read from (a write-only stream) or you have not opened a stream at all."); } //move to the specified record, note that an exception will be thrown is stream is not seekable! //This is ok, since we provide a function to check whether the stream is seekable. long nSeekToPosition = _header.HeaderLength + (index * _header.RecordLength); //check whether requested record exists. Subtract 1 from file length (there is a terminating character 1A at the end of the file) //so if we hit end of file, there are no more records, so return false; if (index < 0 || _dbfFile.Length - 1 <= nSeekToPosition) { return(false); } //move to record and read _dbfFile.Seek(nSeekToPosition, SeekOrigin.Begin); //read the record bool bRead = oFillRecord.Read(_dbfFile); if (bRead) { oFillRecord.RecordIndex = index; } return(bRead); }
/// <summary> /// Write a record to file. If RecordIndex is present, record will be updated, otherwise a new record will be written. /// Header will be output first if this is the first record being writen to file. /// This method does not require stream seek capability to add a new record. /// </summary> /// <param name="orec"></param> public void Write(DbfRecord orec) { //if header was never written, write it first, then output the record if (!_headerWritten) { WriteHeader(); } //if this is a new record (RecordIndex should be -1 in that case) if (orec.RecordIndex < 0) { if (_dbfFileWriter.BaseStream.CanSeek) { //calculate number of records in file. do not rely on header's RecordCount property since client can change that value. //also note that some DBF files do not have ending 0x1A byte, so we subtract 1 and round off //instead of just cast since cast would just drop decimals. int nNumRecords = (int)Math.Round(((double)(_dbfFile.Length - _header.HeaderLength - 1) / _header.RecordLength)); if (nNumRecords < 0) { nNumRecords = 0; } orec.RecordIndex = nNumRecords; Update(orec); _header.RecordCount++; } else { //we can not position this stream, just write out the new record. orec.Write(_dbfFile); _header.RecordCount++; } } else { Update(orec); } _footerUpdateNeeded = true; }
/// <summary> /// Read next record and fill data into parameter oFillRecord. Returns true if a record was read, otherwise false. /// </summary> /// <param name="oFillRecord"></param> /// <returns></returns> public bool ReadNext(DbfRecord oFillRecord) { //check if we can fill this record with data. it must match record size specified by header and number of columns. //we are not checking whether it comes from another DBF file or not, we just need the same structure. Allow flexibility but be safe. if (oFillRecord.Header != _header && (oFillRecord.Header.ColumnCount != _header.ColumnCount || oFillRecord.Header.RecordLength != _header.RecordLength)) { throw new Exception("Record parameter does not have the same size and number of columns as the " + "header specifies, so we are unable to read a record into oFillRecord. " + "This is a programming error, have you mixed up DBF file objects?"); } //DBF file reader can be null if stream is not readable... if (_dbfFileReader == null) { throw new Exception("Read stream is null, either you have opened a stream that can not be " + "read from (a write-only stream) or you have not opened a stream at all."); } //read next record... bool bRead = oFillRecord.Read(_dbfFile); if (bRead) { if (_isForwardOnly) { //zero based index! set before incrementing count. oFillRecord.RecordIndex = _recordsReadCount; _recordsReadCount++; } else { oFillRecord.RecordIndex = ((int)((_dbfFile.Position - _header.HeaderLength) / _header.RecordLength)) - 1; } } return(bRead); }