Import dotnetDBF for error handling.
This commit is contained in:
36
dotnetdbf/original java src/DBFBase.java
Normal file
36
dotnetdbf/original java src/DBFBase.java
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
$Id: DBFBase.java,v 1.3 2004/03/31 15:59:40 anil Exp $
|
||||
Serves as the base class of DBFReader adn DBFWriter.
|
||||
|
||||
@author: anil@linuxense.com
|
||||
|
||||
Support for choosing implemented character Sets as
|
||||
suggested by Nick Voznesensky <darkers@mail.ru>
|
||||
*/
|
||||
/**
|
||||
Base class for DBFReader and DBFWriter.
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
public abstract class DBFBase {
|
||||
|
||||
protected String characterSetName = "8859_1";
|
||||
protected final int END_OF_DATA = 0x1A;
|
||||
|
||||
/*
|
||||
If the library is used in a non-latin environment use this method to set
|
||||
corresponding character set. More information:
|
||||
http://www.iana.org/assignments/character-sets
|
||||
Also see the documentation of the class java.nio.charset.Charset
|
||||
*/
|
||||
public String getCharactersetName() {
|
||||
|
||||
return this.characterSetName;
|
||||
}
|
||||
|
||||
public void setCharactersetName( String characterSetName) {
|
||||
|
||||
this.characterSetName = characterSetName;
|
||||
}
|
||||
|
||||
}
|
||||
27
dotnetdbf/original java src/DBFException.java
Normal file
27
dotnetdbf/original java src/DBFException.java
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
DBFException
|
||||
Represents exceptions happen in the JAvaDBF classes.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFException.java,v 1.2 2004/03/31 10:40:18 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class DBFException extends IOException {
|
||||
|
||||
public DBFException() {
|
||||
|
||||
super();
|
||||
}
|
||||
|
||||
public DBFException( String msg) {
|
||||
|
||||
super( msg);
|
||||
}
|
||||
}
|
||||
283
dotnetdbf/original java src/DBFField.java
Normal file
283
dotnetdbf/original java src/DBFField.java
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
DBFField
|
||||
Class represents a "field" (or column) definition of a DBF data structure.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFField.java,v 1.7 2004/03/31 10:50:11 anil Exp $
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
DBFField represents a field specification in an dbf file.
|
||||
|
||||
DBFField objects are either created and added to a DBFWriter object or obtained
|
||||
from DBFReader object through getField( int) query.
|
||||
|
||||
*/
|
||||
public class DBFField {
|
||||
|
||||
public static final byte FIELD_TYPE_C = (byte)'C';
|
||||
public static final byte FIELD_TYPE_L = (byte)'L';
|
||||
public static final byte FIELD_TYPE_N = (byte)'N';
|
||||
public static final byte FIELD_TYPE_F = (byte)'F';
|
||||
public static final byte FIELD_TYPE_D = (byte)'D';
|
||||
public static final byte FIELD_TYPE_M = (byte)'M';
|
||||
|
||||
/* Field struct variables start here */
|
||||
byte[] fieldName = new byte[ 11]; /* 0-10*/
|
||||
byte dataType; /* 11 */
|
||||
int reserv1; /* 12-15 */
|
||||
int fieldLength; /* 16 */
|
||||
byte decimalCount; /* 17 */
|
||||
short reserv2; /* 18-19 */
|
||||
byte workAreaId; /* 20 */
|
||||
short reserv3; /* 21-22 */
|
||||
byte setFieldsFlag; /* 23 */
|
||||
byte[] reserv4 = new byte[ 7]; /* 24-30 */
|
||||
byte indexFieldFlag; /* 31 */
|
||||
/* Field struct variables end here */
|
||||
|
||||
/* other class variables */
|
||||
int nameNullIndex = 0;
|
||||
|
||||
/**
|
||||
Creates a DBFField object from the data read from the given DataInputStream.
|
||||
|
||||
The data in the DataInputStream object is supposed to be organised correctly
|
||||
and the stream "pointer" is supposed to be positioned properly.
|
||||
|
||||
@param in DataInputStream
|
||||
@return Returns the created DBFField object.
|
||||
@throws IOException If any stream reading problems occures.
|
||||
*/
|
||||
protected static DBFField createField( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
DBFField field = new DBFField();
|
||||
|
||||
byte t_byte = in.readByte(); /* 0 */
|
||||
if( t_byte == (byte)0x0d) {
|
||||
|
||||
//System.out.println( "End of header found");
|
||||
return null;
|
||||
}
|
||||
|
||||
in.readFully( field.fieldName, 1, 10); /* 1-10 */
|
||||
field.fieldName[0] = t_byte;
|
||||
|
||||
for( int i=0; i<field.fieldName.length; i++) {
|
||||
|
||||
if( field.fieldName[ i] == (byte)0) {
|
||||
|
||||
field.nameNullIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
field.dataType = in.readByte(); /* 11 */
|
||||
field.reserv1 = Utils.readLittleEndianInt( in); /* 12-15 */
|
||||
field.fieldLength = in.readUnsignedByte(); /* 16 */
|
||||
field.decimalCount = in.readByte(); /* 17 */
|
||||
field.reserv2 = Utils.readLittleEndianShort( in); /* 18-19 */
|
||||
field.workAreaId = in.readByte(); /* 20 */
|
||||
field.reserv2 = Utils.readLittleEndianShort( in); /* 21-22 */
|
||||
field.setFieldsFlag = in.readByte(); /* 23 */
|
||||
in.readFully( field.reserv4); /* 24-30 */
|
||||
field.indexFieldFlag = in.readByte(); /* 31 */
|
||||
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
Writes the content of DBFField object into the stream as per
|
||||
DBF format specifications.
|
||||
|
||||
@param os OutputStream
|
||||
@throws IOException if any stream related issues occur.
|
||||
*/
|
||||
protected void write( DataOutput out)
|
||||
throws IOException {
|
||||
|
||||
//DataOutputStream out = new DataOutputStream( os);
|
||||
|
||||
// Field Name
|
||||
out.write( fieldName); /* 0-10 */
|
||||
out.write( new byte[ 11 - fieldName.length]);
|
||||
|
||||
// data type
|
||||
out.writeByte( dataType); /* 11 */
|
||||
out.writeInt( 0x00); /* 12-15 */
|
||||
out.writeByte( fieldLength); /* 16 */
|
||||
out.writeByte( decimalCount); /* 17 */
|
||||
out.writeShort( (short)0x00); /* 18-19 */
|
||||
out.writeByte( (byte)0x00); /* 20 */
|
||||
out.writeShort( (short)0x00); /* 21-22 */
|
||||
out.writeByte( (byte)0x00); /* 23 */
|
||||
out.write( new byte[7]); /* 24-30*/
|
||||
out.writeByte( (byte)0x00); /* 31 */
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the name of the field.
|
||||
|
||||
@return Name of the field as String.
|
||||
*/
|
||||
public String getName() {
|
||||
|
||||
return new String( this.fieldName, 0, nameNullIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the data type of the field.
|
||||
|
||||
@return Data type as byte.
|
||||
*/
|
||||
public byte getDataType() {
|
||||
|
||||
return dataType;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns field length.
|
||||
|
||||
@return field length as int.
|
||||
*/
|
||||
public int getFieldLength() {
|
||||
|
||||
return fieldLength;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the decimal part. This is applicable
|
||||
only if the field type if of numeric in nature.
|
||||
|
||||
If the field is specified to hold integral values
|
||||
the value returned by this method will be zero.
|
||||
|
||||
@return decimal field size as int.
|
||||
*/
|
||||
public int getDecimalCount() {
|
||||
|
||||
return decimalCount;
|
||||
}
|
||||
|
||||
// Setter methods
|
||||
|
||||
// byte[] fieldName = new byte[ 11]; /* 0-10*/
|
||||
// byte dataType; /* 11 */
|
||||
// int reserv1; /* 12-15 */
|
||||
// byte fieldLength; /* 16 */
|
||||
// byte decimalCount; /* 17 */
|
||||
// short reserv2; /* 18-19 */
|
||||
// byte workAreaId; /* 20 */
|
||||
// short reserv3; /* 21-22 */
|
||||
// byte setFieldsFlag; /* 23 */
|
||||
// byte[] reserv4 = new byte[ 7]; /* 24-30 */
|
||||
// byte indexFieldFlag; /* 31 */
|
||||
|
||||
/**
|
||||
* @deprecated This method is depricated as of version 0.3.3.1 and is replaced by {@link #setName( String)}.
|
||||
*/
|
||||
public void setFieldName( String value) {
|
||||
|
||||
setName( value);
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the name of the field.
|
||||
|
||||
@param name of the field as String.
|
||||
@since 0.3.3.1
|
||||
*/
|
||||
public void setName( String value) {
|
||||
|
||||
if( value == null) {
|
||||
|
||||
throw new IllegalArgumentException( "Field name cannot be null");
|
||||
}
|
||||
|
||||
if( value.length() == 0 || value.length() > 10) {
|
||||
|
||||
throw new IllegalArgumentException( "Field name should be of length 0-10");
|
||||
}
|
||||
|
||||
this.fieldName = value.getBytes();
|
||||
this.nameNullIndex = this.fieldName.length;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the data type of the field.
|
||||
|
||||
@param type of the field. One of the following:<br>
|
||||
C, L, N, F, D, M
|
||||
*/
|
||||
public void setDataType( byte value) {
|
||||
|
||||
switch( value) {
|
||||
|
||||
case 'D':
|
||||
this.fieldLength = 8; /* fall through */
|
||||
case 'C':
|
||||
case 'L':
|
||||
case 'N':
|
||||
case 'F':
|
||||
case 'M':
|
||||
|
||||
this.dataType = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException( "Unknown data type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Length of the field.
|
||||
This method should be called before calling setDecimalCount().
|
||||
|
||||
@param Length of the field as int.
|
||||
*/
|
||||
public void setFieldLength( int value) {
|
||||
|
||||
if( value <= 0) {
|
||||
|
||||
throw new IllegalArgumentException( "Field length should be a positive number");
|
||||
}
|
||||
|
||||
if( this.dataType == FIELD_TYPE_D) {
|
||||
|
||||
throw new UnsupportedOperationException( "Cannot do this on a Date field");
|
||||
}
|
||||
|
||||
fieldLength = value;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets the decimal place size of the field.
|
||||
Before calling this method the size of the field
|
||||
should be set by calling setFieldLength().
|
||||
|
||||
@param Size of the decimal field.
|
||||
*/
|
||||
public void setDecimalCount( int value) {
|
||||
|
||||
if( value < 0) {
|
||||
|
||||
throw new IllegalArgumentException( "Decimal length should be a positive number");
|
||||
}
|
||||
|
||||
if( value > fieldLength) {
|
||||
|
||||
throw new IllegalArgumentException( "Decimal length should be less than field length");
|
||||
}
|
||||
|
||||
decimalCount = (byte)value;
|
||||
}
|
||||
|
||||
}
|
||||
167
dotnetdbf/original java src/DBFHeader.java
Normal file
167
dotnetdbf/original java src/DBFHeader.java
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
DBFHeader
|
||||
Class for reading the metadata assuming that the given
|
||||
InputStream carries DBF data.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
Author: anil@linuxense.com
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id$
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
class DBFHeader {
|
||||
|
||||
static final byte SIG_DBASE_III = (byte)0x03;
|
||||
/* DBF structure start here */
|
||||
|
||||
byte signature; /* 0 */
|
||||
byte year; /* 1 */
|
||||
byte month; /* 2 */
|
||||
byte day; /* 3 */
|
||||
int numberOfRecords; /* 4-7 */
|
||||
short headerLength; /* 8-9 */
|
||||
short recordLength; /* 10-11 */
|
||||
short reserv1; /* 12-13 */
|
||||
byte incompleteTransaction; /* 14 */
|
||||
byte encryptionFlag; /* 15 */
|
||||
int freeRecordThread; /* 16-19 */
|
||||
int reserv2; /* 20-23 */
|
||||
int reserv3; /* 24-27 */
|
||||
byte mdxFlag; /* 28 */
|
||||
byte languageDriver; /* 29 */
|
||||
short reserv4; /* 30-31 */
|
||||
DBFField []fieldArray; /* each 32 bytes */
|
||||
byte terminator1; /* n+1 */
|
||||
|
||||
//byte[] databaseContainer; /* 263 bytes */
|
||||
/* DBF structure ends here */
|
||||
|
||||
DBFHeader() {
|
||||
|
||||
this.signature = SIG_DBASE_III;
|
||||
this.terminator1 = 0x0D;
|
||||
}
|
||||
|
||||
void read( DataInput dataInput) throws IOException {
|
||||
|
||||
signature = dataInput.readByte(); /* 0 */
|
||||
year = dataInput.readByte(); /* 1 */
|
||||
month = dataInput.readByte(); /* 2 */
|
||||
day = dataInput.readByte(); /* 3 */
|
||||
numberOfRecords = Utils.readLittleEndianInt( dataInput); /* 4-7 */
|
||||
|
||||
headerLength = Utils.readLittleEndianShort( dataInput); /* 8-9 */
|
||||
recordLength = Utils.readLittleEndianShort( dataInput); /* 10-11 */
|
||||
|
||||
reserv1 = Utils.readLittleEndianShort( dataInput); /* 12-13 */
|
||||
incompleteTransaction = dataInput.readByte(); /* 14 */
|
||||
encryptionFlag = dataInput.readByte(); /* 15 */
|
||||
freeRecordThread = Utils.readLittleEndianInt( dataInput); /* 16-19 */
|
||||
reserv2 = dataInput.readInt(); /* 20-23 */
|
||||
reserv3 = dataInput.readInt(); /* 24-27 */
|
||||
mdxFlag = dataInput.readByte(); /* 28 */
|
||||
languageDriver = dataInput.readByte(); /* 29 */
|
||||
reserv4 = Utils.readLittleEndianShort( dataInput); /* 30-31 */
|
||||
|
||||
Vector v_fields = new Vector();
|
||||
|
||||
DBFField field = DBFField.createField( dataInput); /* 32 each */
|
||||
while( field != null) {
|
||||
|
||||
v_fields.addElement( field);
|
||||
field = DBFField.createField( dataInput);
|
||||
}
|
||||
|
||||
fieldArray = new DBFField[ v_fields.size()];
|
||||
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
fieldArray[ i] = (DBFField)v_fields.elementAt( i);
|
||||
}
|
||||
//System.out.println( "Number of fields: " + fieldArray.length);
|
||||
|
||||
}
|
||||
|
||||
void write( DataOutput dataOutput) throws IOException {
|
||||
|
||||
dataOutput.writeByte( signature); /* 0 */
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar();
|
||||
year = (byte)( calendar.get( Calendar.YEAR) - 1900);
|
||||
month = (byte)( calendar.get( Calendar.MONTH)+1);
|
||||
day = (byte)( calendar.get( Calendar.DAY_OF_MONTH));
|
||||
|
||||
dataOutput.writeByte( year); /* 1 */
|
||||
dataOutput.writeByte( month); /* 2 */
|
||||
dataOutput.writeByte( day); /* 3 */
|
||||
|
||||
//System.out.println( "Number of records in O/S: " + numberOfRecords);
|
||||
numberOfRecords = Utils.littleEndian( numberOfRecords);
|
||||
dataOutput.writeInt( numberOfRecords); /* 4-7 */
|
||||
|
||||
headerLength = findHeaderLength();
|
||||
dataOutput.writeShort( Utils.littleEndian( headerLength)); /* 8-9 */
|
||||
|
||||
recordLength = findRecordLength();
|
||||
dataOutput.writeShort( Utils.littleEndian( recordLength)); /* 10-11 */
|
||||
|
||||
dataOutput.writeShort( Utils.littleEndian( reserv1)); /* 12-13 */
|
||||
dataOutput.writeByte( incompleteTransaction); /* 14 */
|
||||
dataOutput.writeByte( encryptionFlag); /* 15 */
|
||||
dataOutput.writeInt( Utils.littleEndian( freeRecordThread));/* 16-19 */
|
||||
dataOutput.writeInt( Utils.littleEndian( reserv2)); /* 20-23 */
|
||||
dataOutput.writeInt( Utils.littleEndian( reserv3)); /* 24-27 */
|
||||
|
||||
dataOutput.writeByte( mdxFlag); /* 28 */
|
||||
dataOutput.writeByte( languageDriver); /* 29 */
|
||||
dataOutput.writeShort( Utils.littleEndian( reserv4)); /* 30-31 */
|
||||
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
//System.out.println( "Length: " + fieldArray[i].getFieldLength());
|
||||
fieldArray[i].write( dataOutput);
|
||||
}
|
||||
|
||||
dataOutput.writeByte( terminator1); /* n+1 */
|
||||
}
|
||||
|
||||
private short findHeaderLength() {
|
||||
|
||||
return (short)(
|
||||
1+
|
||||
3+
|
||||
4+
|
||||
2+
|
||||
2+
|
||||
2+
|
||||
1+
|
||||
1+
|
||||
4+
|
||||
4+
|
||||
4+
|
||||
1+
|
||||
1+
|
||||
2+
|
||||
(32*fieldArray.length)+
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
private short findRecordLength() {
|
||||
|
||||
int recordLength = 0;
|
||||
for( int i=0; i<fieldArray.length; i++) {
|
||||
|
||||
recordLength += fieldArray[i].getFieldLength();
|
||||
}
|
||||
|
||||
return (short)(recordLength + 1);
|
||||
}
|
||||
}
|
||||
315
dotnetdbf/original java src/DBFReader.java
Normal file
315
dotnetdbf/original java src/DBFReader.java
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
DBFReader
|
||||
Class for reading the records assuming that the given
|
||||
InputStream comtains DBF data.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
Author: anil@linuxense.com
|
||||
License: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFReader.java,v 1.8 2004/03/31 10:54:03 anil Exp $
|
||||
*/
|
||||
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
DBFReader class can creates objects to represent DBF data.
|
||||
|
||||
This Class is used to read data from a DBF file. Meta data and
|
||||
records can be queried against this document.
|
||||
|
||||
<p>
|
||||
DBFReader cannot write anythng to a DBF file. For creating DBF files
|
||||
use DBFWriter.
|
||||
|
||||
<p>
|
||||
Fetching rocord is possible only in the forward direction and
|
||||
cannot re-wound. In such situation, a suggested approach is to reconstruct the object.
|
||||
|
||||
<p>
|
||||
The nextRecord() method returns an array of Objects and the types of these
|
||||
Object are as follows:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>xBase Type</th><th>Java Type</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>C</td><td>String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>N</td><td>Integer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>F</td><td>Double</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>L</td><td>Boolean</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>D</td><td>java.util.Date</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
*/
|
||||
public class DBFReader extends DBFBase {
|
||||
|
||||
DataInputStream dataInputStream;
|
||||
DBFHeader header;
|
||||
|
||||
/* Class specific variables */
|
||||
boolean isClosed = true;
|
||||
|
||||
/**
|
||||
Initializes a DBFReader object.
|
||||
|
||||
When this constructor returns the object
|
||||
will have completed reading the hader (meta date) and
|
||||
header information can be quried there on. And it will
|
||||
be ready to return the first row.
|
||||
|
||||
@param InputStream where the data is read from.
|
||||
*/
|
||||
public DBFReader( InputStream in) throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
this.dataInputStream = new DataInputStream( in);
|
||||
this.isClosed = false;
|
||||
this.header = new DBFHeader();
|
||||
this.header.read( this.dataInputStream);
|
||||
|
||||
/* it might be required to leap to the start of records at times */
|
||||
int t_dataStartIndex = this.header.headerLength - ( 32 + (32*this.header.fieldArray.length)) - 1;
|
||||
if( t_dataStartIndex > 0) {
|
||||
|
||||
dataInputStream.skip( t_dataStartIndex);
|
||||
}
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public String toString() {
|
||||
|
||||
StringBuffer sb = new StringBuffer( this.header.year + "/" + this.header.month + "/" + this.header.day + "\n"
|
||||
+ "Total records: " + this.header.numberOfRecords +
|
||||
"\nHEader length: " + this.header.headerLength +
|
||||
"");
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
sb.append( this.header.fieldArray[i].getName());
|
||||
sb.append( "\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of records in the DBF.
|
||||
*/
|
||||
public int getRecordCount() {
|
||||
|
||||
return this.header.numberOfRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the asked Field. In case of an invalid index,
|
||||
it returns a ArrayIndexOutofboundsException.
|
||||
|
||||
@param index. Index of the field. Index of the first field is zero.
|
||||
*/
|
||||
public DBFField getField( int index)
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
return this.header.fieldArray[ index];
|
||||
}
|
||||
|
||||
/**
|
||||
Returns the number of field in the DBF.
|
||||
*/
|
||||
public int getFieldCount()
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
if( this.header.fieldArray != null) {
|
||||
|
||||
return this.header.fieldArray.length;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
Reads the returns the next row in the DBF stream.
|
||||
@returns The next row as an Object array. Types of the elements
|
||||
these arrays follow the convention mentioned in the class description.
|
||||
*/
|
||||
public Object[] nextRecord()
|
||||
throws DBFException {
|
||||
|
||||
if( isClosed) {
|
||||
|
||||
throw new DBFException( "Source is not open");
|
||||
}
|
||||
|
||||
Object recordObjects[] = new Object[ this.header.fieldArray.length];
|
||||
|
||||
try {
|
||||
|
||||
boolean isDeleted = false;
|
||||
do {
|
||||
|
||||
if( isDeleted) {
|
||||
|
||||
dataInputStream.skip( this.header.recordLength-1);
|
||||
}
|
||||
|
||||
int t_byte = dataInputStream.readByte();
|
||||
if( t_byte == END_OF_DATA) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
isDeleted = ( t_byte == '*');
|
||||
} while( isDeleted);
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
switch( this.header.fieldArray[i].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
|
||||
byte b_array[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( b_array);
|
||||
recordObjects[i] = new String( b_array, characterSetName);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
|
||||
byte t_byte_year[] = new byte[ 4];
|
||||
dataInputStream.read( t_byte_year);
|
||||
|
||||
byte t_byte_month[] = new byte[ 2];
|
||||
dataInputStream.read( t_byte_month);
|
||||
|
||||
byte t_byte_day[] = new byte[ 2];
|
||||
dataInputStream.read( t_byte_day);
|
||||
|
||||
try {
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar(
|
||||
Integer.parseInt( new String( t_byte_year)),
|
||||
Integer.parseInt( new String( t_byte_month)) - 1,
|
||||
Integer.parseInt( new String( t_byte_day))
|
||||
);
|
||||
|
||||
recordObjects[i] = calendar.getTime();
|
||||
}
|
||||
catch ( NumberFormatException e) {
|
||||
/* this field may be empty or may have improper value set */
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
|
||||
try {
|
||||
|
||||
byte t_float[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( t_float);
|
||||
t_float = Utils.trimLeftSpaces( t_float);
|
||||
if( t_float.length > 0 && !Utils.contains( t_float, (byte)'?')) {
|
||||
|
||||
recordObjects[i] = new Float( new String( t_float));
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch( NumberFormatException e) {
|
||||
|
||||
throw new DBFException( "Failed to parse Float: " + e.getMessage());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
|
||||
try {
|
||||
|
||||
byte t_numeric[] = new byte[ this.header.fieldArray[i].getFieldLength()];
|
||||
dataInputStream.read( t_numeric);
|
||||
t_numeric = Utils.trimLeftSpaces( t_numeric);
|
||||
|
||||
if( t_numeric.length > 0 && !Utils.contains( t_numeric, (byte)'?')) {
|
||||
|
||||
recordObjects[i] = new Double( new String( t_numeric));
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = null;
|
||||
}
|
||||
}
|
||||
catch( NumberFormatException e) {
|
||||
|
||||
throw new DBFException( "Failed to parse Number: " + e.getMessage());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
|
||||
byte t_logical = dataInputStream.readByte();
|
||||
if( t_logical == 'Y' || t_logical == 't' || t_logical == 'T' || t_logical == 't') {
|
||||
|
||||
recordObjects[i] = Boolean.TRUE;
|
||||
}
|
||||
else {
|
||||
|
||||
recordObjects[i] = Boolean.FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
// TODO Later
|
||||
recordObjects[i] = new String( "null");
|
||||
break;
|
||||
|
||||
default:
|
||||
recordObjects[i] = new String( "null");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( EOFException e) {
|
||||
|
||||
return null;
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
|
||||
return recordObjects;
|
||||
}
|
||||
}
|
||||
350
dotnetdbf/original java src/DBFWriter.java
Normal file
350
dotnetdbf/original java src/DBFWriter.java
Normal file
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
DBFWriter
|
||||
Class for defining a DBF structure and addin data to that structure and
|
||||
finally writing it to an OutputStream.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: DBFWriter.java,v 1.9 2004/03/31 10:57:16 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
An object of this class can create a DBF file.
|
||||
|
||||
Create an object, <br>
|
||||
then define fields by creating DBFField objects and<br>
|
||||
add them to the DBFWriter object<br>
|
||||
add records using the addRecord() method and then<br>
|
||||
call write() method.
|
||||
*/
|
||||
public class DBFWriter extends DBFBase {
|
||||
|
||||
/* other class variables */
|
||||
DBFHeader header;
|
||||
Vector v_records = new Vector();
|
||||
int recordCount = 0;
|
||||
RandomAccessFile raf = null; /* Open and append records to an existing DBF */
|
||||
boolean appendMode = false;
|
||||
|
||||
/**
|
||||
Creates an empty Object.
|
||||
*/
|
||||
public DBFWriter() {
|
||||
|
||||
this.header = new DBFHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a DBFWriter which can append to records to an existing DBF file.
|
||||
@param dbfFile. The file passed in shouls be a valid DBF file.
|
||||
@exception Throws DBFException if the passed in file does exist but not a valid DBF file, or if an IO error occurs.
|
||||
*/
|
||||
public DBFWriter( File dbfFile)
|
||||
throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
this.raf = new RandomAccessFile( dbfFile, "rw");
|
||||
|
||||
/* before proceeding check whether the passed in File object
|
||||
is an empty/non-existent file or not.
|
||||
*/
|
||||
if( !dbfFile.exists() || dbfFile.length() == 0) {
|
||||
|
||||
this.header = new DBFHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
header = new DBFHeader();
|
||||
this.header.read( raf);
|
||||
|
||||
/* position file pointer at the end of the raf */
|
||||
this.raf.seek( this.raf.length()-1 /* to ignore the END_OF_DATA byte at EoF */);
|
||||
}
|
||||
catch( FileNotFoundException e) {
|
||||
|
||||
throw new DBFException( "Specified file is not found. " + e.getMessage());
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage() + " while reading header");
|
||||
}
|
||||
|
||||
this.recordCount = this.header.numberOfRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
Sets fields.
|
||||
*/
|
||||
public void setFields( DBFField[] fields)
|
||||
throws DBFException {
|
||||
|
||||
if( this.header.fieldArray != null) {
|
||||
|
||||
throw new DBFException( "Fields has already been set");
|
||||
}
|
||||
|
||||
if( fields == null || fields.length == 0) {
|
||||
|
||||
throw new DBFException( "Should have at least one field");
|
||||
}
|
||||
|
||||
for( int i=0; i<fields.length; i++) {
|
||||
|
||||
if( fields[i] == null) {
|
||||
|
||||
throw new DBFException( "Field " + (i+1) + " is null");
|
||||
}
|
||||
}
|
||||
|
||||
this.header.fieldArray = fields;
|
||||
|
||||
try {
|
||||
|
||||
if( this.raf != null && this.raf.length() == 0) {
|
||||
|
||||
/*
|
||||
this is a new/non-existent file. So write header before proceeding
|
||||
*/
|
||||
this.header.write( this.raf);
|
||||
}
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( "Error accesing file");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Add a record.
|
||||
*/
|
||||
public void addRecord( Object[] values)
|
||||
throws DBFException {
|
||||
|
||||
if( this.header.fieldArray == null) {
|
||||
|
||||
throw new DBFException( "Fields should be set before adding records");
|
||||
}
|
||||
|
||||
if( values == null) {
|
||||
|
||||
throw new DBFException( "Null cannot be added as row");
|
||||
}
|
||||
|
||||
if( values.length != this.header.fieldArray.length) {
|
||||
|
||||
throw new DBFException( "Invalid record. Invalid number of fields in row");
|
||||
}
|
||||
|
||||
for( int i=0; i<this.header.fieldArray.length; i++) {
|
||||
|
||||
if( values[i] == null) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
switch( this.header.fieldArray[i].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
if( !(values[i] instanceof String)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
if( !( values[i] instanceof Boolean)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
if( !( values[i] instanceof Double)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if( !( values[i] instanceof Date)) {
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
if( !(values[i] instanceof Double)) {
|
||||
|
||||
throw new DBFException( "Invalid value for field " + i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( this.raf == null) {
|
||||
|
||||
v_records.addElement( values);
|
||||
}
|
||||
else {
|
||||
|
||||
try {
|
||||
|
||||
writeRecord( this.raf, values);
|
||||
this.recordCount++;
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( "Error occured while writing record. " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Writes the set data to the OutputStream.
|
||||
*/
|
||||
public void write( OutputStream out)
|
||||
throws DBFException {
|
||||
|
||||
try {
|
||||
|
||||
if( this.raf == null) {
|
||||
|
||||
DataOutputStream outStream = new DataOutputStream( out);
|
||||
|
||||
this.header.numberOfRecords = v_records.size();
|
||||
this.header.write( outStream);
|
||||
|
||||
/* Now write all the records */
|
||||
int t_recCount = v_records.size();
|
||||
for( int i=0; i<t_recCount; i++) { /* iterate through records */
|
||||
|
||||
Object[] t_values = (Object[])v_records.elementAt( i);
|
||||
|
||||
writeRecord( outStream, t_values);
|
||||
}
|
||||
|
||||
outStream.write( END_OF_DATA);
|
||||
outStream.flush();
|
||||
}
|
||||
else {
|
||||
|
||||
/* everything is written already. just update the header for record count and the END_OF_DATA mark */
|
||||
this.header.numberOfRecords = this.recordCount;
|
||||
this.raf.seek( 0);
|
||||
this.header.write( this.raf);
|
||||
this.raf.seek( raf.length());
|
||||
this.raf.writeByte( END_OF_DATA);
|
||||
this.raf.close();
|
||||
}
|
||||
|
||||
}
|
||||
catch( IOException e) {
|
||||
|
||||
throw new DBFException( e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void write()
|
||||
throws DBFException {
|
||||
|
||||
this.write( null);
|
||||
}
|
||||
|
||||
private void writeRecord( DataOutput dataOutput, Object []objectArray)
|
||||
throws IOException {
|
||||
|
||||
dataOutput.write( (byte)' ');
|
||||
for( int j=0; j<this.header.fieldArray.length; j++) { /* iterate throught fields */
|
||||
|
||||
switch( this.header.fieldArray[j].getDataType()) {
|
||||
|
||||
case 'C':
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
String str_value = objectArray[j].toString();
|
||||
dataOutput.write( Utils.textPadding( str_value, characterSetName, this.header.fieldArray[j].getFieldLength()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( Utils.textPadding( "", this.characterSetName, this.header.fieldArray[j].getFieldLength()));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
GregorianCalendar calendar = new GregorianCalendar();
|
||||
calendar.setTime( (Date)objectArray[j]);
|
||||
StringBuffer t_sb = new StringBuffer();
|
||||
dataOutput.write( String.valueOf( calendar.get( Calendar.YEAR)).getBytes());
|
||||
dataOutput.write( Utils.textPadding( String.valueOf( calendar.get( Calendar.MONTH)+1), this.characterSetName, 2, Utils.ALIGN_RIGHT, (byte)'0'));
|
||||
dataOutput.write( Utils.textPadding( String.valueOf( calendar.get( Calendar.DAY_OF_MONTH)), this.characterSetName, 2, Utils.ALIGN_RIGHT, (byte)'0'));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( " ".getBytes());
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
dataOutput.write( Utils.doubleFormating( (Double)objectArray[j], this.characterSetName, this.header.fieldArray[j].getFieldLength(), this.header.fieldArray[j].getDecimalCount()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( Utils.textPadding( "?", this.characterSetName, this.header.fieldArray[j].getFieldLength(), Utils.ALIGN_RIGHT));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
dataOutput.write(
|
||||
Utils.doubleFormating( (Double)objectArray[j], this.characterSetName, this.header.fieldArray[j].getFieldLength(), this.header.fieldArray[j].getDecimalCount()));
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write(
|
||||
Utils.textPadding( "?", this.characterSetName, this.header.fieldArray[j].getFieldLength(), Utils.ALIGN_RIGHT));
|
||||
}
|
||||
|
||||
break;
|
||||
case 'L':
|
||||
|
||||
if( objectArray[j] != null) {
|
||||
|
||||
if( (Boolean)objectArray[j] == Boolean.TRUE) {
|
||||
|
||||
dataOutput.write( (byte)'T');
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write((byte)'F');
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
dataOutput.write( (byte)'?');
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new DBFException( "Unknown field type " + this.header.fieldArray[j].getDataType());
|
||||
}
|
||||
} /* iterating through the fields */
|
||||
}
|
||||
}
|
||||
172
dotnetdbf/original java src/Utils.java
Normal file
172
dotnetdbf/original java src/Utils.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
Utils
|
||||
Class for contining utility functions.
|
||||
|
||||
This file is part of JavaDBF packege.
|
||||
|
||||
author: anil@linuxense.com
|
||||
license: LGPL (http://www.gnu.org/copyleft/lesser.html)
|
||||
|
||||
$Id: Utils.java,v 1.7 2004/03/31 16:00:34 anil Exp $
|
||||
*/
|
||||
package com.linuxense.javadbf;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.text.*;
|
||||
|
||||
/**
|
||||
Miscelaneous functions required by the JavaDBF package.
|
||||
*/
|
||||
public final class Utils {
|
||||
|
||||
public static final int ALIGN_LEFT = 10;
|
||||
public static final int ALIGN_RIGHT = 12;
|
||||
|
||||
private Utils(){}
|
||||
|
||||
public static int readLittleEndianInt( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
int bigEndian = 0;
|
||||
for( int shiftBy=0; shiftBy<32; shiftBy+=8) {
|
||||
|
||||
bigEndian |= (in.readUnsignedByte()&0xff) << shiftBy;
|
||||
}
|
||||
|
||||
return bigEndian;
|
||||
}
|
||||
|
||||
public static short readLittleEndianShort( DataInput in)
|
||||
throws IOException {
|
||||
|
||||
int low = in.readUnsignedByte() & 0xff;
|
||||
int high = in.readUnsignedByte();
|
||||
|
||||
return (short )(high << 8 | low);
|
||||
}
|
||||
|
||||
public static byte[] trimLeftSpaces( byte [] arr) {
|
||||
|
||||
StringBuffer t_sb = new StringBuffer( arr.length);
|
||||
|
||||
for( int i=0; i<arr.length; i++) {
|
||||
|
||||
if( arr[i] != ' ') {
|
||||
|
||||
t_sb.append( (char)arr[ i]);
|
||||
}
|
||||
}
|
||||
|
||||
return t_sb.toString().getBytes();
|
||||
}
|
||||
|
||||
public static short littleEndian( short value) {
|
||||
|
||||
short num1 = value;
|
||||
short mask = (short)0xff;
|
||||
|
||||
short num2 = (short)(num1&mask);
|
||||
num2<<=8;
|
||||
mask<<=8;
|
||||
|
||||
num2 |= (num1&mask)>>8;
|
||||
|
||||
return num2;
|
||||
}
|
||||
|
||||
public static int littleEndian(int value) {
|
||||
|
||||
int num1 = value;
|
||||
int mask = 0xff;
|
||||
int num2 = 0x00;
|
||||
|
||||
num2 |= num1 & mask;
|
||||
|
||||
for( int i=1; i<4; i++) {
|
||||
|
||||
num2<<=8;
|
||||
mask <<= 8;
|
||||
num2 |= (num1 & mask)>>(8*i);
|
||||
}
|
||||
|
||||
return num2;
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
return textPadding( text, characterSetName, length, Utils.ALIGN_LEFT);
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length, int alignment) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
return textPadding( text, characterSetName, length, alignment, (byte)' ');
|
||||
}
|
||||
|
||||
public static byte[] textPadding( String text, String characterSetName, int length, int alignment,
|
||||
byte paddingByte) throws java.io.UnsupportedEncodingException {
|
||||
|
||||
if( text.length() >= length) {
|
||||
|
||||
return text.substring( 0, length).getBytes( characterSetName);
|
||||
}
|
||||
|
||||
byte byte_array[] = new byte[ length];
|
||||
Arrays.fill( byte_array, paddingByte);
|
||||
|
||||
switch( alignment) {
|
||||
|
||||
case ALIGN_LEFT:
|
||||
System.arraycopy( text.getBytes( characterSetName), 0, byte_array, 0, text.length());
|
||||
break;
|
||||
|
||||
case ALIGN_RIGHT:
|
||||
int t_offset = length - text.length();
|
||||
System.arraycopy( text.getBytes( characterSetName), 0, byte_array, t_offset, text.length());
|
||||
break;
|
||||
}
|
||||
|
||||
return byte_array;
|
||||
}
|
||||
|
||||
public static byte[] doubleFormating( Double doubleNum, String characterSetName, int fieldLength, int sizeDecimalPart) throws java.io.UnsupportedEncodingException{
|
||||
|
||||
int sizeWholePart = fieldLength - (sizeDecimalPart>0?( sizeDecimalPart + 1):0);
|
||||
|
||||
StringBuffer format = new StringBuffer( fieldLength);
|
||||
|
||||
for( int i=0; i<sizeWholePart; i++) {
|
||||
|
||||
format.append( "#");
|
||||
}
|
||||
|
||||
if( sizeDecimalPart > 0) {
|
||||
|
||||
format.append( ".");
|
||||
|
||||
for( int i=0; i<sizeDecimalPart; i++) {
|
||||
|
||||
format.append( "0");
|
||||
}
|
||||
}
|
||||
|
||||
DecimalFormat df = new DecimalFormat( format.toString());
|
||||
|
||||
return textPadding( df.format( doubleNum.doubleValue()).toString(), characterSetName, fieldLength, ALIGN_RIGHT);
|
||||
}
|
||||
|
||||
public static boolean contains( byte[] arr, byte value) {
|
||||
|
||||
boolean found = false;
|
||||
for( int i=0; i<arr.length; i++) {
|
||||
|
||||
if( arr[i] == value) {
|
||||
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user