`
njlovey
  • 浏览: 9215 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

使用Java读写DIF格式文件

阅读更多
  DIF文件是FoxPro在早期时候通过程序可以另存为的一种文件,它的格式同FoxBase下DBF文件格式相同。在去年,我接手的一个海事局考试的项目中,客户需要用这种文件格式,通过其他的系统,向我们的系统中导入数据。本着懒人法则,先在网上看看有没有现成的可以处理的包等信息,但是相当悲剧的事情发生了,不仅没有找到jar包可以直接处理,而且也连现成可以读写这种文件格式的软件(如果现成软件可以处理,可以让做客户端程序的程序员给写一个OCX,到时候直接嵌套在系统中就用就可以了)都没有。没有办法了,为了简单,用java写了一个读写该文件格式的包,从系统上线到现在,效果还可以。由于这个问题在网上尚没有比较好的解决方案,为了以后有需要的兄弟们别像我这么纠结,这儿把代码及相关文件上传上来了。
  非常郁闷,没有整懂在javaeye上面怎么发附件,算了,直接上代码,有需要的兄弟们将就这看吧。
DIFManager.java
package com.cdmcs.pub.dif;

import java.util.Arrays;
import java.util.List;

/**
* @用途 管理(读/写)FoxPro格式的DBF文件
* @author 聂蛟
* @version 0.1
* */
public class DIFManager {

private int rowCount;
private long headLength;
//private long bodyLength;

private java.util.List fields;  // 字段列表
private java.util.List body;    // 内容

public DIFManager(){
fields = new java.util.ArrayList();
body   = new java.util.ArrayList();
}

public java.util.List getBody(){
return body;
}

/**
* 取数据
* @param row - 行号
* @param columnName - 列名称,大小写不敏感
* @return
* @throws Exception - 行或者列不存在时,抛出异常。
*/
public String getBodyString(int row , String columnName)throws Exception{
int colIdx = -1;

// 循环,取列号
int fieldSize = fields.size();
for(int i = 0 ; i < fieldSize ; i++){

DIFField fieldItem = (DIFField) fields.get(i);

if(columnName.toUpperCase().equals( fieldItem.getName().toUpperCase() )){

colIdx = i;

break;

}

}

if(colIdx == -1) throw new Exception("002:列不存在");

return getBodyString(row , colIdx);

}

/**
* 取数据
* @param row - 行号
* @param column - 列号
* @return
* @throws Exception - 行或者列不存在时,抛出异常。
*/
public String getBodyString(int row , int column)throws Exception{

if( row >= body.size()){
throw new Exception("001:行越界");
}

java.util.List rowList = (List) body.get(row);

if( column >= rowList.size()){
throw new Exception("002:列不存在");
}

return (String) rowList.get(column);
}

/**
* 设置数据
* @param row - 行号
* @param columnName - 列名称,大小写不敏感
* @param value - 字段值
* @return
* @throws Exception - 行或者列不存在时,抛出异常。
*/
public void setBodyString(int row , String columnName, String value)throws Exception{
int colIdx = -1;

// 循环,取列号
int fieldSize = fields.size();
for(int i = 0 ; i < fieldSize ; i++){

DIFField fieldItem = (DIFField) fields.get(i);

if(columnName.toUpperCase().equals( fieldItem.getName().toUpperCase() )){

colIdx = i;

break;

}

}

if(colIdx == -1) throw new Exception("002:列不存在");
//System.out.println(colIdx);
setBodyString(row , colIdx, value);

}

/**
* 设置数据
* @param row - 行号
* @param column - 列号
* @param value - 字段值
* @return
* @throws Exception - 行或者列不存在时,抛出异常。
*/
public void setBodyString(int row , int column, String value)throws Exception{

//System.out.println(body.size());
java.util.List rowList = null;
if (row + 1 > body.size()) {
rowList = new java.util.ArrayList();
body.add(rowList);
} else {
rowList = (List) body.get(row);
}


if (column + 1 > rowList.size()) {
// 添加
rowList.add(value);
} else{
// 修改
rowList.set(column , value);
}

}

/**
* 取字段数
* @return
*/
public int getFieldCnt(){
return fields.size();
}

/**
* 取字段
* @param idx - 序号
* @return
*/
public DIFField getField(int idx)throws Exception{

if(idx >= this.fields.size()) throw new Exception("003:列越界");

return (DIFField) fields.get(idx);
}

/**
* 增加字段
* @param field - 字段
*/
public void addField( DIFField field ){
fields.add(field);
}

/**
* 增加字段
* @param name - 字段名
* @param type - 字段类型
* @param length - 字段长度
*/
public void addField(String name , char type , int length){

DIFField field = new DIFField();
field.setName(name);
field.setType(type);
field.setLength(length);

addField(field);
this.rowCount ++ ;
//System.out.println(this.rowCount);
}

/**
* 清空全部数据
*/
public void clearAll(){
fields.clear();
body.clear();
}


/**
* 读FoxPro格式的DBF文件
* @param is - 输入流
* @throws Exception
*/
public void read(java.io.InputStream is)throws Exception {

java.io.FileOutputStream fos = new java.io.FileOutputStream(
"DIFTEMPFILE");
try {

int num;
byte[] buf = new byte[1024];
while( (num = is.read(buf)) > 0 ){
fos.write(buf , 0 , num);
}

fos.close();
fos = null;

// 解析文件
read("DIFTEMPFILE");

java.io.File tempFile = new java.io.File("DIFTEMPFILE");

tempFile.delete();

tempFile = null;

} catch (Exception e) {

if (fos != null) {
fos.close();
fos = null;
}

}



}

/**
* 读FoxPro格式的DBF文件
* @param file
* @throws Exception
*/
public void read(String file) throws Exception {
body = new java.util.ArrayList();

java.io.RandomAccessFile raf = new java.io.RandomAccessFile(file, "r");
try {

//==========================================================================
// 读文件头
//==========================================================================
raf.skipBytes(4);

int RecordCount = 0;
// 记录总数=第4个字节+2561×第5个字节+2562×第6个字节+2563×第7个字节
for (int i = 0; i < 32; i += {// 读取记录总数,即4~7字节内容,采用移位异或操作实现
byte curByte = raf.readByte();

if(curByte == 0x00) continue;

rowCount |= curByte & 0xff;

}
// 读表结构长度
int Low = raf.readByte() & 0xff;// 与运算得到低字节内容
int Hight = raf.readByte();
headLength = (long) (Hight << 8 | Low);

int rLow = raf.readByte() & 0xff;
int rHight = raf.readByte();
int RecordLen = (rHight << 8 | rLow);

raf.skipBytes(20);

//==========================================================================
// 读文件结构
//==========================================================================
fields = new java.util.ArrayList();
for(;;){
DIFField fieldItem = new DIFField();
if(! fieldItem.parse(raf) ) break;

fields.add(fieldItem);
}

//==========================================================================
// 读文件内容
//==========================================================================
long curPos = raf.getFilePointer();

raf.skipBytes( (int) (headLength - curPos) + 1);

int fieldCnt = fields.size();
for( int i = 0 ; i < rowCount ; i++ ){

java.util.ArrayList row = new java.util.ArrayList();
for( int j = 0 ; j < fieldCnt ; j++ ){
DIFField fieldItem = (DIFField) this.fields.get(j);

byte[] bValue = new byte[ fieldItem.getLength() ];
raf.read(bValue);
//row.add(new String(bValue));
// 读出来的有空格
row.add(new String(bValue).trim());
}

body.add(row);

raf.skipBytes(1);
}

raf.close();
raf = null;

} catch (Exception e) {
e.printStackTrace();
if(raf != null){
raf.close();
raf = null;
}
} finally {
if(raf != null){
raf.close();
raf = null;
}
}
}

/**
* 生成FoxPro格式的文件
* @param outStream
* @throws Exception
*/
public void write(java.io.OutputStream outStream)throws Exception{

int fieldCnt = this.fields.size();

// 1、生成文件头
byte[] bHead = new byte[32];
bHead[0] = (byte)0x30;
// 取年月日
java.text.SimpleDateFormat sdf_Y = new java.text.SimpleDateFormat("yy");
java.text.SimpleDateFormat sdf_M = new java.text.SimpleDateFormat("MM");
java.text.SimpleDateFormat sdf_D = new java.text.SimpleDateFormat("dd");

java.util.Date curDate = new java.util.Date();

int curYear  = Integer.parseInt(sdf_Y.format(curDate));
int curMonth = Integer.parseInt(sdf_M.format(curDate));
int curDay   = Integer.parseInt(sdf_D.format(curDate));

bHead[1] = (byte)curYear;
bHead[2] = (byte)curMonth;
bHead[3] = (byte)curDay;

// 记录长度
for(int i = 0 ; i < 4 ; i++){
bHead[4 + i] = (byte) (this.rowCount>>>(i *);
}

// 文件头长度,DIF文件固定写0x88 0x03
/*
int headLength = 0;
for(int i = 0 ; i < fieldCnt ; i++){
DIFField fieldItem = (DIFField)this.fields.get(i);
headLength += fieldItem.getLength();
}

int headLengthHeight = headLength / 2561;
int headLengthLower  = headLength % 2561;
bHead[8] = (byte)headLengthLower;
bHead[9] = (byte)headLengthHeight;
*/
bHead[8] = (byte)0x88;
bHead[9] = (byte)0x03;

// 记录长度固定写0x9E
bHead[10] = (byte)0x9E;

// 系统保留区,写0x7A,原因未知(参见已有DIF文件)
bHead[29] = (byte)0x7A;

outStream.write(bHead);

// 2、生成字段描述
int iMemPosi = 1;

for(int i = 0 ; i < fieldCnt ; i++){
DIFField fieldItem = (DIFField)this.fields.get(i);

outStream.write(fieldItem.generateField(iMemPosi));

iMemPosi+= fieldItem.getLength();

}

outStream.write(0x0D);

if(iMemPosi - 2 < 904){
// 填充,填充数量为 904-head(32)-1(0x0d)-(字段数量*32)
byte[] bStrFill = new byte[904 - 33 - fieldCnt * 32];
outStream.write(bStrFill);
}

// 3、生成数据
byte defaultFill = (byte)0x20;
outStream.write(0x20);
int rowCnt = this.body.size();



for( int i = 0 ; i < rowCnt ; i++ ){

java.util.List list = (List) this.body.get(i);
for(int j = 0 ; j < fieldCnt ; j++){
DIFField fieldItem = (DIFField)this.fields.get(j);

String value = (String)list.get(j);
byte[] bValue = value.getBytes();

int bValueSize = bValue.length;

byte[] writeByte = new byte[fieldItem.getLength()];
if(bValueSize >= fieldItem.getLength()){
bValueSize = fieldItem.getLength();
// 构造向输入流中写入数据
System.arraycopy(bValue, 0, writeByte, 0, fieldItem.getLength());
}else{
System.arraycopy(bValue, 0, writeByte, 0, bValueSize);

Arrays.fill(writeByte, bValueSize , writeByte.length , defaultFill);
}

outStream.write(writeByte);
}

if(i != rowCnt - 1){
// 行级分隔符
outStream.write(0x20);
}else{
// 文件级分隔符
outStream.write(0x1A);
}
}


}

public static void main(String[] argv) throws Exception {

// java.io.FileInputStream fin = new
// java.io.FileInputStream("c:\\1.DIF");

DIFManager dr = new DIFManager();
dr.read("c:\\D100-A13UT220081219初考.DIF");

java.io.FileOutputStream fos = new java.io.FileOutputStream("c:\\D100-A13UT220081219初考.DIF_bak");
dr.write(fos);
fos.close();

}

}

DIFField.java
package com.cdmcs.pub.dif;

public class DIFField {

private String name;
private char type;
private int length;

// 将int转换为byte[],使用移位方式实现。每次向有移动1个byte(8个bit)
private void memPosInt2Byte(int source , byte[] bRef){
for( int i = 0 ; i < 4; i++ ){
bRef[12 + i] = (byte) (source >>> (i *);
}
}

public byte[] generateField(int memoryPosi)throws Exception{

// 返回32位长度
byte[] bRef = new byte[32];

// 前11位,字段名
byte[] bFieldName = name.getBytes("GBK");

// 构造返回byte
int fieldPosi = bFieldName.length;
if(fieldPosi > 11){
fieldPosi = 11;
}
// 字段名
System.arraycopy(bFieldName, 0, bRef, 0, fieldPosi);

// 字段类型
bRef[11] =  (byte)type;

// 字段在内存中位置
memPosInt2Byte(memoryPosi , bRef);

// 字段长度
bRef[16] = (byte)length;

return bRef;
}

/**
* @用途 从当前位置解析文件,取一个Field的位置,构造出Field
* @param raf
* @return
* @throws java.io.IOException
*/
public boolean parse( java.io.RandomAccessFile raf )throws java.io.IOException{

byte[] bName = new byte[11];

bName[0] = raf.readByte();

// 判断是否结束字符
if(bName[0] == 0x0D){
return false;
}

// 取字段名
raf.read(bName , 1 , 10);  // 偏移量为1,取10位
for(int i = 0 ; i < 10 ; i++){
if(bName[i] == (byte)0x00){
this.name = new String(bName , 0 , i);
break;
}
}

// 取字段类型
int iTypeAscii = raf.readByte();
this.type = (char)iTypeAscii;



raf.readInt(); // 跳过4位,此四位表示数据在内存中的区域

this.length = raf.readByte();
System.out.println(this.name + "\t" + this.type + "\t" + this.length);
raf.skipBytes(15);//跳过系统保留字节

return true;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getType() {
return type;
}
public void setType(char type) {
this.type = type;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}

}

DIFFieldType.java
package com.cdmcs.pub.dif;

public class DIFFieldType {

public static char CHAR = 'C';
public static char NUMERIC = 'N';
//public static char  = 'Y';
public static char FLOAT = 'F';
public static char DATE = 'D';
public static char DATETIME = 'T';
public static char LOGICAL = 'L';
public static char MEMO = 'M';
public static char GENERAL = 'G';
//public static char  = 'B';
public static char INTEGER = 'I';

}


分享到:
评论

相关推荐

    java读写hdf5格式文件需要使用的库

    Java编程语言在处理科学数据时,常常会遇到HDF5(Hierarchical Data Format 5)这种文件格式。HDF5是一种高效、灵活的数据存储格式,广泛应用于科研、工程等领域,支持大数据存储和复杂的多维数组操作。为了在Java中...

    java读写properties配置文件

    通过上述介绍,我们可以看到使用Java读写`Properties`配置文件是非常直观和方便的。这种能力对于开发过程中管理和维护配置信息至关重要。无论是简单的键值对读取还是复杂的批量更新,`Properties`类都能满足需求。...

    Java 读写文件文本文件的示例

    Java中读写文本文件主要依赖于`InputStream`和`OutputStream`的使用,结合`Reader`和`Writer`接口的实现类如`BufferedReader`和`PrintWriter`,可以高效地完成文件的读取和写入操作。掌握这些核心类的使用是进行文件...

    Java 读写Ini文件

    Ini文件是一种常见的配置文件格式,通常用于存储程序的设置和选项。在Windows系统中,许多应用程序使用 Ini 文件来保存用户配置。在Java中,虽然没有内置的Ini文件处理库,但我们可以借助第三方库如JIniFile或者...

    java读写excel文件

    本篇文章将深入探讨如何使用Java进行Excel文件的读取与写入操作,主要聚焦于Apache POI库,这是一个广泛使用的开源Java API,专为处理Microsoft Office格式的文件而设计。 首先,我们需要了解Apache POI库中的核心...

    Java_读写json格式的文件方法详解

    在读取 JSON 文件时,可以使用文件输入流来读取文件内容,然后将文件内容格式化成 JSON 对象,最后将 JSON 对象转换成 Java 对象。例如,public ElectSet findElectSet(String path) 方法可以读取 JSON 文件的内容,...

    JAVA简单的读写文本文件的代码

    文件流复制是一种常见的文件操作,通常用于备份文件、转换文件格式等场景。这里采用`BufferedReader`和`PrintWriter`组合的方式来实现文件流之间的复制。 #### 代码实现: ```java public void copyStream...

    java 随机读写Java类文件

    10. **学习资源**:理解类文件格式的官方文档是《Java Virtual Machine Specification》,而深入学习`RandomAccessFile`可以查阅Java API文档。此外,相关的书籍和在线教程也能提供深入的理论和实践指导。 总之,...

    java 读写 DBF 文件 xBaseJ

    在IT行业中,数据库文件格式是数据存储和交换的重要方式之一,DBF(dBase File Format)就是其中一种常见的表格数据格式,尤其在早期的桌面数据库系统中广泛应用。本篇文章将详细探讨如何使用Java来读写DBF文件,...

    Java读写xml,word,xml文件(防乱码)

    本文将详细介绍如何使用Java进行XML、Word以及TXT文件的读写操作,并确保在读写过程中不会出现乱码现象。 #### 二、理解文件编码 在深入探讨具体的解决方案之前,我们先来了解一下文件编码的基本概念。文件编码是指...

    Java读写Yaml文件的工具类-snakeyaml

    java通过snakeyaml类能非常方便的操作,读写yaml文件。

    JAVA使用JNI读写INI文件

    JAVA使用JNI读写INI文件的实例。 JAVA本身并没有读写INI文件的现成方法,有些人自己编写方法来读写INI文件,但是这样的方法或多或少的存在着一些问题。此示例旨在利用本地的WIN32API函数来读写INI文件,这样可以保证...

    C++,java读写二进制文件方法介绍.docx

    * 使用文件流需要包含 `&lt;fstream.h&gt;` 头文件。 Java读写二进制文件 * 在Java中,读写二进制文件需要使用 `FileInputStream` 和 `FileOutputStream` 类。 * 使用 `FileInputStream` 可以读取文件中的二进制数据。 *...

    Java读写文件(excel)

    Java读写文件-Excel

    java 二进制文件的读写操作

    ### Java 二进制文件的读写操作 在Java中,进行二进制文件的读写操作是非常常见的需求,尤其是在处理非文本类型的文件(如图片、音频或视频等)时。本文将详细介绍如何使用`FileInputStream`和`FileOutputStream`类...

    C++,java读写二进制文件方法介绍.pdf

    C++,java读写二进制文件方法介绍.pdf java从第九页开始

    Java读写.txt文件

    在Java编程中,读写文本文件(如`.txt`文件)是常见的操作,尤其是在处理配置文件时。配置文件通常以键值对(key-value pairs)的形式存储数据,便于程序访问和管理设置。以下是对这个主题的详细阐述: 1. **Java I...

    JAVA读写二进制文件

    下面我们将深入探讨如何在Java中进行二进制文件的读写操作。 1. **字节流基础** Java提供了两种基本的字节流接口:`InputStream` 和 `OutputStream`。`InputStream` 用于读取数据,而 `OutputStream` 用于写入数据...

Global site tag (gtag.js) - Google Analytics