/// <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); }
/// <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); } }