/*
*Copyright 2007, 2011 CCLS Columbia University (USA), LIFO University of Orl��ans (France), BRGM (France)
*
*Authors: Cyril Nortet, Xiangrong Kong, Ansaf Salleb-Aouissi, Christel Vrain, Daniel Cassard
*
*This file is part of QuantMiner.
*
*QuantMiner is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.
*
*QuantMiner is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
*You should have received a copy of the GNU General Public License along with QuantMiner. If not, see <http://www.gnu.org/licenses/>.
*/
package src.database;
import java.io.*;
import java.util.*;
/**DBF file reader
*/
public class DBFReader {
DataInputStream m_dataInputStream = null;
int m_iNombreChamps = 0;
DBFChamp[] m_champs = null;
int m_iTailleEnregistrement = 0;
int m_iNombreLignes = 0;
final static int DBF_TYPE_CHAMP_ERRONE = 0;
final static int DBF_TYPE_CHAMP_CARAC = 1;
final static int DBF_TYPE_CHAMP_DATE = 2;
final static int DBF_TYPE_CHAMP_REEL = 3;
final static int DBF_TYPE_CHAMP_DECIMAL = 4;
final static int DBF_TYPE_CHAMP_LOGIQUE = 5;
final static int DBF_TYPE_CHAMP_MEMO = 6;
public class DBFChamp {
String m_sNom = null; //field name
int m_iTypeChamp = DBF_TYPE_CHAMP_ERRONE; //field type
int m_iTailleChamp = 0; //field length
DBFChamp(String sNom, int iTypeChamp, int iTailleChamp) {
m_sNom = sNom;
m_iTypeChamp = iTypeChamp;
m_iTailleChamp = iTailleChamp;
}
public String ObtenirNom() {
return m_sNom;
}
public int ObtenirType() {
return m_iTypeChamp;
}
public int ObtenirTaille() {
return m_iTailleChamp;
}
/**isplay column information
*/
public void AfficherChamp() {
String sType = null;
System.out.print(m_sNom + " : ");
sType = "type ";
switch (m_iTypeChamp) {
case DBF_TYPE_CHAMP_CARAC:
sType += "caract�res";
break;
case DBF_TYPE_CHAMP_DATE:
sType += "date";
break;
case DBF_TYPE_CHAMP_REEL:
sType += "flottant";
break;
case DBF_TYPE_CHAMP_DECIMAL:
sType += "d�cimal";
break;
case DBF_TYPE_CHAMP_LOGIQUE:
sType += "bool�en";
break;
case DBF_TYPE_CHAMP_MEMO:
sType += "m�mo";
break;
default:
sType += "ind�termin�";
}
System.out.print(sType);
System.out.print(", taille ");
System.out.println(m_iTailleChamp);
}
}
/**read 32bit value
* @param fluxEntree DataInputStream
* @return int
* @throws IOException
*/
public int LireValeur32Bits(DataInputStream fluxEntree) throws IOException {
int iValeurLue = 0;
int iDecalage = 0;
for (iDecalage = 0; iDecalage < 32; iDecalage += 8)
iValeurLue |= (fluxEntree.readByte() & 0xff) << iDecalage;
return iValeurLue;
}
/**read 16bit value
* @param fluxEntree DataInputStream
* @return short
* @throws IOException
*/
public short LireValeur16Bits(DataInputStream fluxEntree)
throws IOException {
short iValeurLue = 0;
int iDecalage = 0;
for (iDecalage = 0; iDecalage < 16; iDecalage += 8)
iValeurLue |= (fluxEntree.readByte() & 0xff) << iDecalage;
return iValeurLue;
}
public void IgnorerOctets(DataInputStream fluxEntree, int iNombreOctets)
throws IOException {
int iValeurLue = 0;
int iDecalage = 0;
for (iDecalage = 0; iDecalage < iNombreOctets; iDecalage++)
fluxEntree.readByte();
}
/**
* This function gets all field information, i.e. number of fields, type, name. It also gets number of records/rows
* This function does not read each row's value
* @param sNomFichier the full name of a file, including path
*/
public DBFReader(String sNomFichier) {
boolean bChampsTousLus = false;
boolean bLectureEnTeteCorrecte = false;
byte octetLu = 0;
byte[] tOctetsLus = null;
int positionZeroTerminal = 0;
int iIndexLettre = 0; // Lettre means letter
int iTypeChamp = DBF_TYPE_CHAMP_ERRONE; // ERRONE means error
String sNomChamp = null;
int iTailleChamp = 0;
Vector<DBFChamp> champs = null;
DBFChamp champ = null;
// Structure Informations about DBF file :
byte signature; // 1st byte "database start signal(if database includes DBT file->80H,else->03H)"
byte annee; // 2nd byte annee means year "file create or modify date(YYMMDD with YY=Date-1900)"
byte mois; // 3rd byte mois means month
byte jour; // 4th byte jour means day
short longueurEnTete; // 9-10 Length of File structure information
try {
m_dataInputStream = new DataInputStream(new FileInputStream(
sNomFichier));
} catch (IOException e) {
System.out.println(e.getMessage());
m_dataInputStream = null;
}
if (m_dataInputStream == null)
return;
try {
signature = m_dataInputStream.readByte(); //Reads one signed input byte. range -128 through 127
annee = m_dataInputStream.readByte();
mois = m_dataInputStream.readByte();
jour = m_dataInputStream.readByte();
m_iNombreLignes = LireValeur32Bits(m_dataInputStream); //lire means read. number of lines 5-8bytes
//5-8bytes number of database records,with lower bytes in front and higher bytes after
longueurEnTete = LireValeur16Bits(m_dataInputStream);
System.out.println("longueurEnTete " + longueurEnTete);
m_iTailleEnregistrement = (int) LireValeur16Bits(m_dataInputStream); //11-12bytes the total length of each record
System.out.println("m_iTailleEnregistrement " + m_iTailleEnregistrement);
// On se place au niveau de la description des champs :
IgnorerOctets(m_dataInputStream, 20); //13-32bytes reserved
} catch (IOException e) {
}
// End of Structure Informations about DBF file
champs = new Vector<DBFChamp>();
bChampsTousLus = false;
while (!bChampsTousLus) {
try {
octetLu = m_dataInputStream.readByte();
if (octetLu == (byte) 0x0d) { // Indicator of termination
// l'en-t�te
bChampsTousLus = true;
bLectureEnTeteCorrecte = true;
}
} catch (IOException e) {
bChampsTousLus = true;
bLectureEnTeteCorrecte = false;
}
if (!bChampsTousLus) {
try {
// Get field's name 1-11 bytes
tOctetsLus = new byte[11];
m_dataInputStream.read(tOctetsLus, 1, 10); //read 10 bytes to tOctetsLus, start at tOctetsLus[1]
tOctetsLus[0] = octetLu;
for (iIndexLettre = 10; iIndexLettre >= 0; iIndexLettre--)
if (tOctetsLus[iIndexLettre] == 0)
positionZeroTerminal = iIndexLettre;
if (positionZeroTerminal > 0)
sNomChamp = new String(tOctetsLus, 0,
positionZeroTerminal);
else
sNomChamp = new String("");
// Get field's type the 12th byte
octetLu = m_dataInputStream.readByte();
switch (octetLu) {
case (byte) 0x43:
iTypeChamp = DBF_TYPE_CHAMP_CARAC; //type is character
break; // 'C'
case (byte) 0x44:
iTypeChamp = DBF_TYPE_CHAMP_DATE; //type is date
break; // 'D'
case (byte) 0x46:
iTypeChamp = DBF_TYPE_CHAMP_REEL; //type is float number
break; // 'F'
case (byte) 0x4E:
iTypeChamp = DBF_TYPE_CHAMP_DECIMAL; //type is decimal
break; // 'N'
case (byte) 0x4C:
iTypeChamp = DBF_TYPE_CHAMP_LOGIQUE; //type is boolean
break; // 'L'
case (byte) 0x4D:
iTypeChamp = DBF_TYPE_CHAMP_MEMO; //type is memo??
break; // 'M'
default:
iTypeChamp = DBF_TYPE_CHAMP_ERRONE; //type is error
}
IgnorerOctets(m_dataInputStream, 4);
// Get the length of the field:
iTailleChamp = (int) m_dataInputStream.readUnsignedByte();
IgnorerOctets(m_dataInputStream, 15);
// create a field and put into field list
champ = new DBFChamp(sNomChamp, iTypeChamp, iTailleChamp); //field name, field type and field length
champs.add(champ); //add to field list
} catch (IOException e) {
}
}
}
// End of Structure of Records
m_iNombreChamps = champs.size();
//System.out.println("m_iNombreChamps before " + m_iNombreChamps);
if (m_iNombreChamps > 0) {
m_champs = (DBFChamp[]) champs.toArray(new DBFChamp[1]); //return an array with all elements in that vector, the array type is specified
m_iNombreChamps = m_champs.length; // pour �tre s�r...
System.out.println("m_iNombreChamps after " + m_iNombreChamps);
} else
m_champs = null;
}
public void close() {
if (m_dataInputStream == null)
return;
try {
m_dataInputStream.close();
} catch (IOException e) {
}
}
public int ObtenirNombreChamps() {
return m_iNombreChamps;
}
public DBFChamp ObtenirChamp(int iIndexChamp) {
if (iIndexChamp < m_iNombreChamps)
return m_champs[iIndexChamp];
else
return null;
}
/**Get the index of a column by name
* @param sNomChamp Column name
* @return int
*/
public int ObtenirIndiceChamp(String sNomChamp) {
int iIndiceChamp = 0;
boolean bChampTrouve = false;
String sNomChampEnumere = null;
if (sNomChamp == null)
return -1;
iIndiceChamp = 0;
while ((!bChampTrouve) && (iIndiceChamp < m_iNombreChamps)) {
sNomChampEnumere = m_champs[iIndiceChamp].ObtenirNom();
if (sNomChamp.equals(sNomChampEnumere))
bChampTrouve = true;
else
iIndiceChamp++;
}
if (bChampTrouve)
return iIndiceChamp;
else
return -1;
}
public int ObtenirNombreLignes() {
return m_iNombreLignes;
}
public String[] LireEnregistrementSuivant() { //read subsequent data (DBFLecteur Constructor read all data before real row values)
byte octetLu = 0;
byte[] tOctetsLus = null;
int iIndiceChamp = 0;
int iTailleChamp = 0;
int iTypeChamp = 0;
String tValeursChamps[] = null;
String sChaineLue = null;
if (m_dataInputStream == null)
return null;
tValeursChamps = new String[m_iNombreChamps];
try {
// On ignore les enregistrements marqu�s comme effac�s :
octetLu = 0x2A;
while (octetLu == 0x2A) {//skip all deleted rows
octetLu = m_dataInputStream.readByte();
if (octetLu == 0x2A) { //this record has been deleted
IgnorerOctets(m_dataInputStream, //ignore the rest record size - 1 bytes
m_iTailleEnregistrement - 1);
}
}
// mark the end of that file:
if (octetLu == 0x1A)
return null;
for (iIndiceChamp = 0; iIndiceChamp < m_iNombreChamps; iIndiceChamp++) {
iTailleChamp = m_champs[iIndiceChamp].ObtenirTaille();
iTypeChamp = m_champs[iIndiceChamp].ObtenirType();
// Test de correction en cas de fichier mal con�u :
if (iTailleChamp <= 0) {
if (iTypeChamp == DBF_TYPE_CHAMP_DATE)
iTailleChamp = 8;
else if (iTypeChamp == DBF_TYPE_CHAMP_LOGIQUE)
iTailleChamp = 1;
else
iTailleChamp = 0;
}
if (iTailleChamp > 0) {
tOctetsLus = new byte[iTailleChamp];
m_dataInputStream.read(tOctetsLus);
switch (iTypeChamp) {
case DBF_TYPE_CHAMP_CARAC:
tValeursChamps[iIndiceChamp] = new String(tOctetsLus);
break;
case DBF_TYPE_CHAMP_DATE:
tValeursChamps[iIndiceChamp] = new String(tOctetsLus);
break;
case DBF_TYPE_CHAMP_REEL:
tValeursChamps[iIndiceChamp] = (new String(tOctetsLus))
.trim();
break;
case DBF_TYPE_CHAMP_DECIMAL:
tValeursChamps[iIndiceChamp] = (new String(tOctetsLus))
.trim();
break;
case DBF_TYPE_CHAMP_LOGIQUE:
if (tOctetsLus[0] == 0x59 || tOctetsLus[0] == 0x79
|| tOctetsLus[0] == 0x54
|| tOctetsLus[0] == 0x74) // 'Y', 'y', 'T', 't'
tValeursChamps[iIndiceChamp] = new String("Vrai"); //True
else
tValeursChamps[iIndiceChamp] = new String("Faux"); //False
break;
default:
tValeursChamps[iIndiceChamp] = new String(tOctetsLus);
}
} else
tValeursChamps[iIndiceChamp] = "";
}
} catch (EOFException e) {
return null;
} catch (IOException e) {
return null;
}
return tValeursChamps;
}
}