package org.geotools.dbffile;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Vector;
import jeql.io.EndianDataOutputStream;
import org.geotools.misc.FormatedString;
/**
* a class for writing dbf files
*
* @author Ian Turton
*
*/
public class DbfFileWriter implements DbfConsts {
private final static boolean DEBUG = false;
private final static String DBC = "DbFW>";
int numFields = 1;
int numRecs = 0;
int recLength = 0;
DbfFieldDef fields[];
EndianDataOutputStream ls;
private boolean header = false;
public DbfFileWriter(String file) throws IOException {
ls = new EndianDataOutputStream(new BufferedOutputStream(
new FileOutputStream(file)));
}
public void writeHeader(DbfFieldDef fld[], int nrecs) throws IOException {
numFields = fld.length;
numRecs = nrecs;
fields = new DbfFieldDef[numFields];
for (int i = 0; i < numFields; i++) {
fields[i] = fld[i];
}
ls.writeByteLE(3); // ID - dbase III without memo
// sort out the date
Calendar calendar = new GregorianCalendar();
Date trialTime = new Date();
calendar.setTime(trialTime);
ls.writeByteLE(calendar.get(Calendar.YEAR) - DBF_CENTURY);
ls.writeByteLE(calendar.get(Calendar.MONTH) + 1); // month is 0-indexed
ls.writeByteLE(calendar.get(Calendar.DAY_OF_MONTH));
int dataOffset = 32 * numFields + 32 + 1;
for (int i = 0; i < numFields; i++) {
recLength += fields[i].fieldlen;
}
recLength++; // delete flag
if (DEBUG)
System.out.println(DBC + "rec length " + recLength);
ls.writeIntLE(numRecs);
ls.writeShortLE(dataOffset); // length of header
ls.writeShortLE(recLength);
for (int i = 0; i < 20; i++)
ls.writeByteLE(0); // 20 bytes of junk!
// field descriptions
for (int i = 0; i < numFields; i++) {
ls.writeBytesLE(fields[i].fieldname.toString());
ls.writeByteLE(fields[i].fieldtype);
for (int j = 0; j < 4; j++)
ls.writeByteLE(0); // junk
ls.writeByteLE(fields[i].fieldlen);
ls.writeByteLE(fields[i].fieldnumdec);
for (int j = 0; j < 14; j++)
ls.writeByteLE(0); // more junk
}
ls.writeByteLE(0xd);
header = true;
}
public void writeRecords(Vector[] recs) throws DbfFileException, IOException {
if (!header) {
throw (new DbfFileException("Must write header before records"));
}
int i = 0;
try {
for (i = 0; i < recs.length; i++) {
if (recs[i].size() != numFields)
throw new DbfFileException("wrong number of records in " + i
+ "th record " +
recs[i].size() + " expected " + numFields);
writeRecord(recs[i]);
}
}
catch (DbfFileException e) {
throw new DbfFileException(DBC + "at rec " + i + "\n" + e);
}
}
private static final String BLANK_255 = " ";
public void writeRecord(Vector rec) throws DbfFileException, IOException {
if (!header) {
throw (new DbfFileException(DBC + "Must write header before records"));
}
if (rec.size() != numFields)
throw new DbfFileException(DBC + "wrong number of fields " +
rec.size() + " expected " + numFields);
String s;
ls.writeByteLE(' ');
int len;
StringBuffer tmps;
for (int i = 0; i < numFields; i++) {
len = fields[i].fieldlen;
Object o = rec.elementAt(i);
switch (fields[i].fieldtype) {
case 'C':
case 'c':
case 'D': // Added by [Jon Aquino]
case 'L':
case 'M':
case 'G':
// chars
String ss = (String) o;
while (ss.length() < fields[i].fieldlen)
{
// need to fill it with ' ' chars
ss = ss + BLANK_255;
}
tmps = new StringBuffer(ss);
tmps.setLength(fields[i].fieldlen);
ls.writeBytesLE(tmps.toString());
break;
case 'N':
case 'n':
// int?
if (fields[i].fieldnumdec == 0) {
ls.writeBytesLE(FormatedString.format(((Integer) o).intValue(),
fields[i].fieldlen));
break;
}
case 'F':
case 'f':
// double
s = ((Double) o).toString();
String x = FormatedString.format(s, fields[i].fieldnumdec,
fields[i].fieldlen);
ls.writeBytesLE(x);
break;
}// switch
}// fields
}
public void close() throws IOException {
ls.writeByteLE(0x1a); // eof mark
ls.close();
}
}