/** * This method saves all the records in the mapTable argument using the dos stream. * * @param dos Output stream writing to the .dbf file. * @param mapTable The dbf table being saved. * @throws IOException Thrown when the stream fails. */ private void saveRecords(DataOutputStream dos, DBFTable mapTable) throws IOException { // WRITE ALL ROW DATA for (int i = 0; i < mapTable.getNumberOfRecords(); i++) { // HERE'S THE RECORD WE ARE SAVING DBFRecord recordToSave = mapTable.getRecord(i); // THERE IS A MYSTERY BYTE BEFORE EACH RECORD dos.writeByte(recordToSave.getMystery()); // LOAD DATA FOR EACH FIELD Iterator<DBFField> fieldsIt = mapTable.fieldsIterator(); int fieldsCounter = 0; while (fieldsIt.hasNext()) { // WHAT TYPE OF FIELD IS IT (character data, numbers, etc.)? DBFField field = fieldsIt.next(); // TEXT? if (field.getType() == DBFFieldType.C) { int j = 0; Object data = recordToSave.getData(fieldsCounter); String text; if (data == null) text = ""; else text = data.toString(); while (j < text.length()) { dos.writeByte((byte) text.charAt(j)); j++; } while (j < field.getLength()) { dos.writeByte((byte) ' '); j++; } } // IT MUST BE AN 'N' TYPE, THOSE ARE THE ONLY TWO WE'RE USING else { Object data = recordToSave.getData(fieldsCounter); String numText; if (data == null) numText = ""; else numText = data.toString(); int x = 0; while (x < numText.length()) { dos.writeByte((byte) numText.charAt(x)); x++; } while (x < field.getLength()) { dos.writeByte((byte) ' '); x++; } } fieldsCounter++; } } }
/** * This helper method reads and loads all the row data (records) from the .dbf into the mapTable * argument. Note that the dis argument must be ready to read at the start of the records section, * which is right after the fields section. * * @param dis Input stream reading from the .dbf file. * @param mapTable The dbf table being loaded. * @throws IOException Thrown when the stream fails. */ private void loadRecords(DataInputStream dis, DBFTable mapTable) throws IOException { // READ ALL ROW DATA for (int i = 0; i < mapTable.getNumberOfRecords(); i++) { // HERE'S THE RECORD WE ARE LOADING DBFRecord recordToAdd = new DBFRecord(mapTable.getNumFields()); // THERE IS A MYSTERY BYTE BEFORE EACH RECORD byte mystery = dis.readByte(); recordToAdd.setMystery(mystery); // LOAD DATA FOR EACH FIELD Iterator<DBFField> fieldsIt = mapTable.fieldsIterator(); int fieldsCounter = 0; while (fieldsIt.hasNext()) { // WHAT TYPE OF FIELD IS IT (character data, numbers, etc.)? DBFField field = fieldsIt.next(); // TEXT? if (field.getType() == DBFFieldType.C) { String text = ""; for (int counter = 0; counter < field.getLength(); counter++) { char c = (char) dis.readByte(); text += c; } text = text.trim(); recordToAdd.setData(text, fieldsCounter); } // IT MUST BE AN 'N' TYPE SINCE THOSE ARE THE ONLY TWO WE'RE USING else { String text = ""; for (int counter = 0; counter < field.getLength(); counter++) { char c = (char) dis.readByte(); text += c; } text = text.trim(); if (text.contains(".")) { double num = 0.0; num = Double.parseDouble(text); recordToAdd.setData(num, fieldsCounter); } else { long num = 0; if (text.length() > 0) num = Long.parseLong(text); recordToAdd.setData(num, fieldsCounter); } } fieldsCounter++; } // Comparable key = (Comparable)recordToAdd.getData(mapTable.getKeyIndex()); mapTable.addRecord(recordToAdd); } }
/** * This method saves all of the fields in the mapTable argument via the dos stream, which is setup * at the proper location. * * @param dos Output stream writing to the .dbf file. * @param mapTable The dbf table being saved. * @throws IOException Thrown when the stream fails. */ private void saveFields(DataOutputStream dos, DBFTable mapTable) throws IOException { // NUMBER OF FIELDS (COLUMNS) IN THE TABLE int numFields = (mapTable.getPositionOfFirstDataRecorded() - 32 - 2 + 1) / 32; for (int i = 0; i < numFields; i++) { // HERE'S THE FIELD WE'RE SAVING DBFField fieldToSave = mapTable.getField(i); // FIELD NAME String fieldName = fieldToSave.getName(); int j = 0; for (; j < fieldName.length(); j++) { byte c = (byte) fieldName.charAt(j); dos.writeByte(c); } byte z = (byte) 0x00; while (j < 11) { dos.writeByte(z); j++; } // FIELD TYPE dos.writeByte((byte) (fieldToSave.getType().toString().charAt(0))); // DISPLACEMENT OF FIELD IN RECORD (12-15) dos.writeInt(Integer.reverseBytes(fieldToSave.getDisplacement())); // LENGTH OF FIELD (16) dos.writeByte((byte) fieldToSave.getLength()); // NUMBER OF DECIMAL PLACES (17) dos.writeByte(fieldToSave.getNumberOfDecimalPlaces()); // FIELD FLAGS (18) dos.writeByte(fieldToSave.getFlags()); // AUTOINCREMENT NEXT (19-22) dos.writeInt(Integer.reverseBytes(fieldToSave.getNext())); // AUTOINCREMENT STEP (23) dos.writeByte(fieldToSave.getStep()); // RESERVED (24-31) - WE WON'T USE THIS dos.writeLong(fieldToSave.getReservedData()); } }
private void readFieldDescriptors(LittleEndianInputStream is, int nFields) throws IOException { // read description of each field byte[] asciiFieldName = new byte[11]; for (int i = 0; i < nFields; i++) { DBFField field = new DBFField(); is.read(asciiFieldName); field.name = bytesToString(asciiFieldName, asciiFieldName.length, this.charsetName); field.type = is.readUnsignedByte(); field.address = is.readInt(); field.length = is.readUnsignedByte(); field.decimalCount = is.readUnsignedByte(); is.readShort(); // overread reserved value field.workAreaID = is.readUnsignedByte(); field.multiUserDBase = is.readShort(); field.setFields = is.readUnsignedByte(); is.skipBytes(7); // overread 7 reserved bytes field.fieldInMDXIndex = is.readUnsignedByte(); this.fields.add(field); this.printInfo("\n" + field.toString()); } // overread the Header Record Terminator, which should be 0x0D byte terminator = is.readByte(); if (terminator != 0x0D) { throw new IOException("DBF file is corrupt."); } }
/** * This method loads all of the fields in the mapTable argument via the dis stream, which is setup * at the proper location. * * @param dis Input stream reading from the .dbf file. * @param mapTable The dbf table being loaded. * @throws IOException Thrown when the stream fails. */ private void loadFields(DataInputStream dis, DBFTable mapTable) throws IOException { // NUMBER OF FIELDS (COLUMNS) IN THE TABLE int numFields = (mapTable.getPositionOfFirstDataRecorded() - 32 - 2 + 1) / 32; for (int i = 0; i < numFields; i++) { // ANOTHER COLUMN DBFField fieldToAdd = new DBFField(); mapTable.addField(fieldToAdd); // FIELD NAME String fieldName = ""; for (int j = 0; j < 11; j++) { byte c = dis.readByte(); if (c != 0) fieldName += (char) c; } fieldToAdd.setName(fieldName); // FIELD TYPE byte fieldTypeAsByte = dis.readByte(); char fieldType = (char) fieldTypeAsByte; if (fieldType == 'C') fieldToAdd.setType(DBFFieldType.C); else fieldToAdd.setType(DBFFieldType.N); // DISPLACEMENT OF FIELD IN RECORD (12-15) int displacementOfFieldInRecord = readLittleEndianInt(dis); fieldToAdd.setDisplacement(displacementOfFieldInRecord); // LENGTH OF FIELD (16) int lengthOfField = dis.readByte(); if (lengthOfField < 0) lengthOfField += 256; fieldToAdd.setLength(lengthOfField); // NUMBER OF DECIMAL PLACES (17) byte numberOfDecimalPlaces = dis.readByte(); fieldToAdd.setNumberOfDecimalPlaces(numberOfDecimalPlaces); // FIELD FLAGS (18) byte fieldFlags = dis.readByte(); fieldToAdd.setFlags(fieldFlags); // AUTOINCREMENT NEXT (19-22) int next = readLittleEndianInt(dis); fieldToAdd.setNext(next); // AUTOINCREMENT STEP (23) byte step = dis.readByte(); fieldToAdd.setStep(step); // RESERVED (24-31) - WE WON'T USE THIS long reservedFieldData = dis.readLong(); fieldToAdd.setReservedData(reservedFieldData); } }