All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jamel.dbf.DbfReader Maven / Gradle / Ivy

There is a newer version: 0.3.0
Show newest version
package org.jamel.dbf;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.GregorianCalendar;

import org.jamel.dbf.exception.DbfException;
import org.jamel.dbf.structure.DbfField;
import org.jamel.dbf.structure.DbfHeader;
import org.jamel.dbf.utils.DbfUtils;
import org.jamel.dbf.utils.StringUtils;

import static org.jamel.dbf.utils.StringUtils.rightPad;

/**
 * Dbf file reader.
 * This class is not thread safe.
 *
 * @author Sergey Polovko
 * @see DBF specification
 */
public class DbfReader {

    protected final int END_OF_DATA = 0x1A;

    private final DataInputStream dataInputStream;
    private final DbfHeader header;

    private boolean isClosed = true;


    /**
     * 

Initializes a DbfReader object.

* *

When this constructor returns the object will have completed reading the header (meta date) and * header information can be queried there on. And it will be ready to return the first row.

* * @param file where the data is read from. */ public DbfReader(File file) { try { dataInputStream = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); isClosed = false; header = DbfHeader.read(dataInputStream); // it might be required to jump to the start of records at times int dataStartIndex = header.getHeaderLength() - 32 * (header.getFieldsCount() + 1) - 1; if (dataStartIndex > 0) { dataInputStream.skip(dataStartIndex); } } catch (IOException e) { throw new DbfException("Cannot open Dbf file " + file, e); } } /** * Reads and returns the next row in the Dbf stream. * * @return The next row as an Object array. Types of the elements these arrays * follow the convention mentioned in the class description. */ public Object[] nextRecord() { if (isClosed) { throw new IllegalStateException("Source is not open"); } Object recordObjects[] = new Object[header.getFieldsCount()]; try { boolean isDeleted = false; do { if (isDeleted) { dataInputStream.skip(header.getRecordLength() - 1); } int nextByte = dataInputStream.readByte(); if (nextByte == END_OF_DATA) { return null; } isDeleted = (nextByte == '*'); } while (isDeleted); for (int i = 0; i < header.getFieldsCount(); i++) { recordObjects[i] = readFieldValue(header.getField(i)); } } catch (EOFException e) { return null; // we currently end reading file } catch (IOException e) { throw new DbfException("Cannot read next record form Dbf file", e); } return recordObjects; } private Object readFieldValue(DbfField field) throws IOException { switch (field.getDataType()) { case 'C': byte buf[] = new byte[field.getFieldLength()]; dataInputStream.read(buf); return buf; case 'D': byte dateBuf[] = new byte[4 + 2 + 2]; dataInputStream.read(dateBuf); int year = DbfUtils.parseInt(dateBuf, 0, 4); int month = DbfUtils.parseInt(dateBuf, 4, 6); int day = DbfUtils.parseInt(dateBuf, 6, 8); return new GregorianCalendar(year, month - 1, day).getTime(); case 'F': try { byte floatBuf[] = new byte[field.getFieldLength()]; dataInputStream.read(floatBuf); floatBuf = DbfUtils.trimLeftSpaces(floatBuf); if (floatBuf.length > 0 && !DbfUtils.contains(floatBuf, (byte) '?')) { return Float.valueOf(new String(floatBuf)); } else { return null; } } catch (NumberFormatException e) { throw new DbfException("Failed to parse Float from " + field.getName(), e); } case 'N': try { byte numericBuf[] = new byte[field.getFieldLength()]; dataInputStream.read(numericBuf); numericBuf = DbfUtils.trimLeftSpaces(numericBuf); if (numericBuf.length > 0 && !DbfUtils.contains(numericBuf, (byte) '?')) { return Double.valueOf(new String(numericBuf)); } else { return null; } } catch (NumberFormatException e) { throw new DbfException("Failed to parse Number from " + field.getName(), e); } case 'L': byte logicalByte = dataInputStream.readByte(); if (logicalByte == 'Y' || logicalByte == 'y' || logicalByte == 'T' || logicalByte == 't') { return Boolean.TRUE; } else { return Boolean.FALSE; } default: return null; } } /** * @return the number of records in the Dbf. */ public int getRecordCount() { return header.getNumberOfRecords(); } /** * @return Dbf header info. */ public DbfHeader getHeader() { return header; } @Override public String toString() { StringBuilder sb = new StringBuilder(256); sb.append("Created at: ") .append(header.getYear()).append('-').append(header.getMonth()) .append('-').append(header.getDay()).append('\n') .append("Total records: ").append(getRecordCount()).append('\n') .append("Header length: ").append(header.getHeaderLength()).append('\n') .append("Columns: ").append('\n'); sb.append(rightPad("Name", 16, ' ')) .append(rightPad("Type", 8, ' ')) .append(rightPad("Length", 8, ' ')) .append(rightPad("Decimal", 8, ' ')) .append('\n'); for (int i = 0; i < header.getFieldsCount(); i++) { DbfField field = header.getField(i); sb.append(rightPad(field.getName(), 16, ' ')) .append(rightPad(String.valueOf((char) field.getDataType()), 8, ' ')) .append(rightPad(String.valueOf(field.getFieldLength()), 8, ' ')) .append(rightPad(String.valueOf(field.getDecimalCount()), 8, ' ')) .append('\n'); } return sb.toString(); } public void close() { try { dataInputStream.close(); } catch (IOException e) { // ignore } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy