CodeHelp是專(zhuān)門(mén)為我們程序員設(shè)計(jì)的一款源代碼管理軟件。它能方便的管理您在編程和學(xué)習(xí)中有用的源代碼,減少經(jīng)常到處查找資料的勞動(dòng),節(jié)省您在開(kāi)發(fā)中的時(shí)間和精力。這個(gè)軟件不錯(cuò),如果沒(méi)有用過(guò)請(qǐng)到這里下載(http://www.nulldo.com/)。用了一段時(shí)間,發(fā)現(xiàn)它并沒(méi)有文件導(dǎo)出功能。于是用Java寫(xiě)了一個(gè)CodeHelpExporter。
下圖為CodeHelp數(shù)據(jù)庫(kù)表的關(guān)系,是用Visio導(dǎo)入Access反向分析得來(lái)的。有了這個(gè)圖我們就可以編程了。

CodeHelpExporter.java源代碼如下:
import java.sql.*;
import java.io.*;
/*
*將CodeHelp數(shù)據(jù)庫(kù)中的文件導(dǎo)出
*@version 2009-3-15
*@author Winty (wintys@gmail.com)
*/
class CodeHelpExporter{
Database db;//數(shù)據(jù)庫(kù)連接對(duì)象
public CodeHelpExporter(String dbPath){
db = new Database(dbPath);
try{
db.connect();
}catch(SQLException sqle){
sqle.printStackTrace();
}
}
/**
*主函數(shù)
*/
public static void main(String[] args){
String dbq = "helpdb.mdb";
CodeHelpExporter exporter = new CodeHelpExporter( dbq );
exporter.export();
}
/**
*按CodeHelp的目錄結(jié)構(gòu)導(dǎo)出文章及其附件。
*但有一點(diǎn)不同,就是不含任何內(nèi)容的目錄不會(huì)被創(chuàng)建。
*文章會(huì)被導(dǎo)出到當(dāng)前目錄的CodeHelpExportedFiles目錄下。
*/
public void export(){
try{
String sql;
sql = "SELECT T.NodeId AS id , T.ParentId AS parent ,";
sql +="T.Type AS type,T.Title AS title , C.Content AS content ";
sql +="FROM TContent C, TTree T WHERE T.NodeId = C.NodeId ";
ResultSet rs = db.query(sql);
while(rs.next()){
int type = rs.getInt("type");
if(type == 0)//如果是目錄,則無(wú)操作
continue;
int parent = rs.getInt("parent");
int id = rs.getInt("id");
String title = rs.getString("title");
File fullParentPath = null;
fullParentPath = parentPath(parent , "");
fullParentPath = new File("CodeHelpExportedFiles/" +
fullParentPath.toString() );
//讀取附件的SQL
String sql2 = "SELECT A.Title AS title , A.Data AS data ";
sql2 += "FROM TAttachment A WHERE A.NodeId = " + id;
ResultSet rs2=db.query(sql2);
//判斷文章有沒(méi)有附件
//如果文章沒(méi)有附件則不創(chuàng)建目錄,即文章不包含在目錄中
rs2.last();
int num = rs2.getRow();
String article;
if(num > 0){
article = title + "/" ;
}
else{
article = "";
}
fullParentPath = new File(fullParentPath , article);
if(!fullParentPath.exists())
fullParentPath.mkdirs();
//讀取文章
InputStream input = rs.getAsciiStream("content");
readDataToFile(new File(fullParentPath , title + ".txt") , input);
//讀取文章的附件
rs2.beforeFirst();
while(rs2.next()){
String attachmentName = rs2.getString("title");
InputStream data = rs2.getBinaryStream("Data");
//將附件與其文章一同放在以文章名為目錄名的目錄中
readDataToFile(new File(fullParentPath , attachmentName) ,
data);
}
rs2.close();
}
rs.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
db.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
/**
*從數(shù)據(jù)流中讀取數(shù)據(jù)到文件
*@param fileName 輸出文件的文件名
*@param input 數(shù)據(jù)輸入流
*/
private void readDataToFile(File filePath , InputStream input)
throws IOException{
FileOutputStream file = new FileOutputStream(filePath);
BufferedOutputStream output = new BufferedOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len = input.read(buf))!=-1){
output.write(buf , 0 , len);
}
input.close();
output.close();
}
/**
*遞歸地構(gòu)造目錄(如果父目錄存在的話(huà))。即如果是子目錄,則一直找到根目錄才返回。
*@param parent 父目錄的ParentId
*@param title 文件自身目錄名,對(duì)于文章而言,path總是傳入空字符串。
*@return 返回構(gòu)造后的目錄(含從根目錄一直到子目錄的各級(jí)目錄)
*/
private File parentPath(int parent , String path)
throws IOException , SQLException{
if(parent == 0){//根目錄
File dir = new File(path);
return dir;
}
else{
String sql = "SELECT Title , ParentId FROM TTree ";
sql += "WHERE NodeId=" + parent;
ResultSet rs = db.query(sql);
if(rs.next()){
String nodeTitle = rs.getString("Title");
int nodeParent = rs.getInt("ParentId");
path = nodeTitle + "/" + path;
return parentPath(nodeParent , path);
}
rs.close();
}
return null;///
}
}
import java.io.*;
/*
*將CodeHelp數(shù)據(jù)庫(kù)中的文件導(dǎo)出
*@version 2009-3-15
*@author Winty (wintys@gmail.com)
*/
class CodeHelpExporter{
Database db;//數(shù)據(jù)庫(kù)連接對(duì)象
public CodeHelpExporter(String dbPath){
db = new Database(dbPath);
try{
db.connect();
}catch(SQLException sqle){
sqle.printStackTrace();
}
}
/**
*主函數(shù)
*/
public static void main(String[] args){
String dbq = "helpdb.mdb";
CodeHelpExporter exporter = new CodeHelpExporter( dbq );
exporter.export();
}
/**
*按CodeHelp的目錄結(jié)構(gòu)導(dǎo)出文章及其附件。
*但有一點(diǎn)不同,就是不含任何內(nèi)容的目錄不會(huì)被創(chuàng)建。
*文章會(huì)被導(dǎo)出到當(dāng)前目錄的CodeHelpExportedFiles目錄下。
*/
public void export(){
try{
String sql;
sql = "SELECT T.NodeId AS id , T.ParentId AS parent ,";
sql +="T.Type AS type,T.Title AS title , C.Content AS content ";
sql +="FROM TContent C, TTree T WHERE T.NodeId = C.NodeId ";
ResultSet rs = db.query(sql);
while(rs.next()){
int type = rs.getInt("type");
if(type == 0)//如果是目錄,則無(wú)操作
continue;
int parent = rs.getInt("parent");
int id = rs.getInt("id");
String title = rs.getString("title");
File fullParentPath = null;
fullParentPath = parentPath(parent , "");
fullParentPath = new File("CodeHelpExportedFiles/" +
fullParentPath.toString() );
//讀取附件的SQL
String sql2 = "SELECT A.Title AS title , A.Data AS data ";
sql2 += "FROM TAttachment A WHERE A.NodeId = " + id;
ResultSet rs2=db.query(sql2);
//判斷文章有沒(méi)有附件
//如果文章沒(méi)有附件則不創(chuàng)建目錄,即文章不包含在目錄中
rs2.last();
int num = rs2.getRow();
String article;
if(num > 0){
article = title + "/" ;
}
else{
article = "";
}
fullParentPath = new File(fullParentPath , article);
if(!fullParentPath.exists())
fullParentPath.mkdirs();
//讀取文章
InputStream input = rs.getAsciiStream("content");
readDataToFile(new File(fullParentPath , title + ".txt") , input);
//讀取文章的附件
rs2.beforeFirst();
while(rs2.next()){
String attachmentName = rs2.getString("title");
InputStream data = rs2.getBinaryStream("Data");
//將附件與其文章一同放在以文章名為目錄名的目錄中
readDataToFile(new File(fullParentPath , attachmentName) ,
data);
}
rs2.close();
}
rs.close();
}catch(Exception e){
e.printStackTrace();
}finally{
try{
db.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
/**
*從數(shù)據(jù)流中讀取數(shù)據(jù)到文件
*@param fileName 輸出文件的文件名
*@param input 數(shù)據(jù)輸入流
*/
private void readDataToFile(File filePath , InputStream input)
throws IOException{
FileOutputStream file = new FileOutputStream(filePath);
BufferedOutputStream output = new BufferedOutputStream(file);
byte[] buf = new byte[1024];
int len;
while((len = input.read(buf))!=-1){
output.write(buf , 0 , len);
}
input.close();
output.close();
}
/**
*遞歸地構(gòu)造目錄(如果父目錄存在的話(huà))。即如果是子目錄,則一直找到根目錄才返回。
*@param parent 父目錄的ParentId
*@param title 文件自身目錄名,對(duì)于文章而言,path總是傳入空字符串。
*@return 返回構(gòu)造后的目錄(含從根目錄一直到子目錄的各級(jí)目錄)
*/
private File parentPath(int parent , String path)
throws IOException , SQLException{
if(parent == 0){//根目錄
File dir = new File(path);
return dir;
}
else{
String sql = "SELECT Title , ParentId FROM TTree ";
sql += "WHERE NodeId=" + parent;
ResultSet rs = db.query(sql);
if(rs.next()){
String nodeTitle = rs.getString("Title");
int nodeParent = rs.getInt("ParentId");
path = nodeTitle + "/" + path;
return parentPath(nodeParent , path);
}
rs.close();
}
return null;///
}
}
Database.java:
import java.sql.*;
import java.io.*;
/**
*數(shù)據(jù)庫(kù)操作類(lèi),當(dāng)前只適用于Access數(shù)據(jù)庫(kù)。
*@version 2009-3-15
*@author wintys@gmail.com
*/
class Database{
private Connection conn = null;
private String dbPath = null;
/**
*構(gòu)造方法
*@param databasePath Access數(shù)據(jù)庫(kù)的路徑
*/
public Database(String databasePath){
dbPath = databasePath;
}
/**
*連接數(shù)據(jù)庫(kù)
*@return 返回一個(gè)數(shù)據(jù)庫(kù)連接Connection,如果連接數(shù)據(jù)庫(kù)失敗,返回null。
*/
public Connection connect()
throws SQLException{
if(conn!=null)
return conn;
if(dbPath==null || dbPath.equals("")){
conn = null;
throw new SQLException("數(shù)據(jù)庫(kù)路徑錯(cuò)誤!");
}
String url;
//Microsoft Access數(shù)據(jù)庫(kù)連接字符串
url = "jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=";
url += dbPath;
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}catch(ClassNotFoundException e){
e.printStackTrace();
}
conn = DriverManager.getConnection(url , "" , "");
return conn;
}
/**
*關(guān)閉數(shù)據(jù)庫(kù)連接
*/
public void close() throws SQLException{
if(conn!=null)
conn.close();
}
/**
*執(zhí)行查詢(xún),調(diào)用者要負(fù)責(zé)關(guān)閉結(jié)果集。
*@param sql 要執(zhí)行的SQL查詢(xún)語(yǔ)句
*@return 返回查詢(xún)結(jié)果集
*/
public ResultSet query(String sql) throws SQLException{
Statement stmt;
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE ,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery(sql);
return rs;
}
}
import java.io.*;
/**
*數(shù)據(jù)庫(kù)操作類(lèi),當(dāng)前只適用于Access數(shù)據(jù)庫(kù)。
*@version 2009-3-15
*@author wintys@gmail.com
*/
class Database{
private Connection conn = null;
private String dbPath = null;
/**
*構(gòu)造方法
*@param databasePath Access數(shù)據(jù)庫(kù)的路徑
*/
public Database(String databasePath){
dbPath = databasePath;
}
/**
*連接數(shù)據(jù)庫(kù)
*@return 返回一個(gè)數(shù)據(jù)庫(kù)連接Connection,如果連接數(shù)據(jù)庫(kù)失敗,返回null。
*/
public Connection connect()
throws SQLException{
if(conn!=null)
return conn;
if(dbPath==null || dbPath.equals("")){
conn = null;
throw new SQLException("數(shù)據(jù)庫(kù)路徑錯(cuò)誤!");
}
String url;
//Microsoft Access數(shù)據(jù)庫(kù)連接字符串
url = "jdbc:odbc:driver={Microsoft Access Driver (*.mdb)};DBQ=";
url += dbPath;
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}catch(ClassNotFoundException e){
e.printStackTrace();
}
conn = DriverManager.getConnection(url , "" , "");
return conn;
}
/**
*關(guān)閉數(shù)據(jù)庫(kù)連接
*/
public void close() throws SQLException{
if(conn!=null)
conn.close();
}
/**
*執(zhí)行查詢(xún),調(diào)用者要負(fù)責(zé)關(guān)閉結(jié)果集。
*@param sql 要執(zhí)行的SQL查詢(xún)語(yǔ)句
*@return 返回查詢(xún)結(jié)果集
*/
public ResultSet query(String sql) throws SQLException{
Statement stmt;
stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE ,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery(sql);
return rs;
}
}