/// <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 (!mHeaderWritten) { 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 != mHeader && (orec.Header.ColumnCount != mHeader.ColumnCount || orec.Header.RecordLength != mHeader.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 (mDbfFileWriter == 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)mHeader.HeaderLength + (long)((long)orec.RecordIndex * (long)mHeader.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 (mDbfFile.Length < nSeekToPosition) { throw new Exception("Invalid record position. Unable to save record."); } //move to record start mDbfFile.Seek(nSeekToPosition, SeekOrigin.Begin); //write orec.Write(mDbfFile); }
/// <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 (!mHeaderWritten) { WriteHeader(); } //if this is a new record (RecordIndex should be -1 in that case) if (orec.RecordIndex < 0) { if (mDbfFileWriter.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)(mDbfFile.Length - mHeader.HeaderLength - 1) / mHeader.RecordLength)); if (nNumRecords < 0) { nNumRecords = 0; } orec.RecordIndex = nNumRecords; Update(orec); mHeader.RecordCount++; } else { //we can not position this stream, just write out the new record. orec.Write(mDbfFile); mHeader.RecordCount++; } } else { Update(orec); } }