2008年6月27日星期五

Java数据导出(导入)SQL,Access(mdb),Excel(xls),csv方法整理

Java数据导出(导入)SQL,Access(mdb),Excel(xls),csv方法整理
最近在做一个数据导出功能,
导出类型有文本格式的SQL,Access文件mdb,Excel文件xls 。
先说说Excel的文件格式xls。
主要有两个Java API可以对Excel文件进行读写,
一个是Apache组织下的POI ,官方地址:[url]http://jakarta.apache.org/poi/[/url]
一个是 Java Excel API ,jxl 网址:[url]http://www.andykhan.com/jexcelapi/[/url]
有个限制 65536,一个sheet,据说要到 Excel 2007里才没有这个限制,但考虑到客户用的大多还是Excel的老版本,没有办法在一个sheet中转入那么多的数据,一种解决方法就是达到 5W 的条件就创建一个新的 sheet。呵呵,但现实中呢,到了2W左右就抛出了Out of Memory 错误 ,cell 对象的个数太多了。查了很多的资料,也没有好的解决方案。
现考虑到两个方法:
一个就是用文本方式来输出,如用html的格式中的table,用td来代替一个cell。保存为.xls文件,用Excel打开,用户就知道有差别。这个方法,在输入文件的时候是没有限制了(文件流,呵呵),但在用Excel打开文件的时候就有65536的限制了
还有就是劝说用户数据不要太大,分多个excel文件输出,采用分批输出为xls的文件。

具体读写xls文件的方法我这里就不写了,参考官方网站上的doc,这里再加上一个:IBM的
利用JAVA操作EXCEL文件 : [url]http://www.ibm.com/developerworks/cn/java/l-javaExcel/index.html[/url]
还有一个在JavaEye上的关于海量数据导出的讨论:
主题: Java往Excel写入海量数据: [url]http://www.javaeye.com/topic/78448?page=3[/url]

再讨论下SQL的导出,文本格式,文件流,没有什么好讲的,create table ,insert into tablename 基本上没有问题。
Access的mdb呢,就要用到SQL中的SQL语句,可以一起写。

连接mdb的jdbc写法:

String strurl = "jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=E:\\ fileName.mdb";// 你的ACCESS文件位置
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection(strurl);
log.debug("连接成功!");
Statement stmt = conn.createStatement();
stmt.executeUpdate(createSQL);
stmt.executeUpdate(sql);
stmt.close();
conn.close();
代码中出现的两个变量createSQL ,sql分别是创建表,和插入数据的SQL。还有一个要注意的地方,就是mdb的文件的数据,需要等到conn.close()后,才真正的写入。注意,strurl 上的空格。

在来讨论csv格式,其实就是一个文本流了。不过要注意的地方就是在输出纯数字的文本串的时候,象身份证号码:'05284548110008',在Excel打开就显示为5.28E+12,科学计数的格式,这里找到一个方法:在文本前加上Tab键,就可以正常显示为字符串了。不过java里怎么输出Tab键呢,

表3-1 常用格式控制字符

控 制 字 符 作 用

\\ 反斜线 \' 单引号'

\" 双引号" \uxxxx 以十六进制数指定Unicode字符输出

\dxxx 以八进制数指定Unicode字符输出 \b 倒退一个字符

\f 换页 \n 换行

\r 光标移至行首 \t 跳格(一个Tab键)

看了这个大家都知道了吧。

在来看看导入Access的,访问mdb文件的跟上面的是一样的。接着呢,就是要得到mdb中的所有表名和字段名。
这里就有很多中方法可以得到,仁者见仁,智者见智,大家各显神通了。
我想到有两种方法:
1.每个数据库都有相应的系统表,Access作为简单的文本数据库,当然也不例外,系统表中就是MSysObjects 。
要在Access中显示系统表,点击菜单,工具 �> 选项 ,在视图选项卡中点选 系统对象。就可以看到系统表了。
通过或者

String sql ="SELECT Name FROM MSysObjects WHERE Type=1 AND LVProp <> NULL"; // 或用这个where条件 WHERE Type=1 AND Flags=0
ResultSet rs = stmt.executeQuery(sql );
rs.next();
tablename = rs.getString(1);
2.
通过jdbc的接口,DatabaseMetaData来获取table和column。

ResultSet rs= conn.getMetaData().getTables(null, null, "%",
new String[] { "TABLE" });
while (dddd.next()) {
String tablename = rs.getString(3));
}
同样可以得到字段名称

String sql = "select * from " + tablename;// 得到字段名和数据
ResultSet rs2 = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs2.getMetaData();
int count = 0;
if (rsmd != null) {
count = rsmd.getColumnCount();
String[] columnNames = new String[count];
for (int i = 0; i < count; i++) {
columnNames[i] = rsmd.getColumnName(i + 1);
}
while (rs2.next()) {
String[] value = new String[count];
for (int i = 0; i < count; i++) {
String s = rs2.getString(columnNames[i]);//相应的value值
}
}
}
这样就可以得到表名,字段名,和相应的值了。