文本数据库的简单java实现
?注:?转载请注明出处: http://hejiangtao.iteye.com ,?用于商业得给我分成
这个是一个文本数据库简单的实现思路, 从这里可以下载到完整的java代码工程: ?http://download.csdn.net/detail/hejiangtao/3991735
什么人适合阅读本文:
1. 我自己平时写些小程序,存储数据使用那些收钱/开源的数据库太浪费电脑资源,直接存到文件里面更方便. 所以才搞了这个东东, 如果你和我有同样的苦恼和需求,你可以参考下,看有木有你需要的.?我简单把实现思路写了一下,需要的兄弟也可以参考下,根据情况自己做扩展或者封装
.
2.其中使用到了java泛型,java反射机制,文本输入输出等技术,如果想研究这些技术也可以参考这些代码,,看有么有你需要的.
? ?设计思路说明:
1.数据存相关规则
一般的数据库的存储规则是不暴露给用户的,如果使用文本来存储数据,用户可以随便修改,所以必须建立一定的规则,用户不能随意手动修改文本数据库内容. 我实现的时候是一个表,一个文本文件; 一个表对应一个Bean class, 并假设,Bean Class的名字就是文件名加Bean后缀, 列名和TableBean的域(Field)名是一样,这样可以轻松使用java反射机制; 文本文件的第一行有效列需指明列名和顺序,因为Field的顺序是不可控的,存在文本里面就可控了; 第一列为主键,列与列之间使用$_$分割.
2. 关键算法/设计
1)读写文件--数据肯定是多行的,所以使用buffered reader 和writer是必要的, 写入和读出数据的时候都按照一条记录一行的方式,方便解析
2)文本数据和Bean之间的转化--将数据存入Bean是为了更方便的解析和使用, 由于Bean的Class Name和Field Name及其Set/Get方法都是采用同样的命名方式,所以可以通过使用一个java泛型方法实现所有表/Bean的文本数据和Bean之间的转化,访问数据也可以java反射机制访问.
3)数据分析--由于文件内容分析只能在内存里面分析,如果数据量太大,只能先一部分一本的分析,将分析完的数据先写入到临时文件, 本例作为demo就按照全部写入内存方式来分析
?实现:
?整个工程的文件分布如下如图:
1.在工程主目录下的db下面是两个示例表的文件T_FamilyMember.db, T_Home.db, 后缀名是.db其实是文本
2.在包名com.ross.filedb下面, tablebean下是两张表对应的Bean,命名必须符合规则; util下是一些公共的业务不相关的一些操作实现或系统级变量; FileDBTool.java则实现了基本的增/删/改/查功能.
3. junit.ross.filedb下是简单的junit功能测试用例 (木有main,看运行结果请用junit看
)
? 先把Bean和db文件贴出来,命名是相互对应的,很明显,就不浪费口舌了:
T_Home.db:
?
?
[java] view plaincopy
- /**???????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com?
- ??????*?Description:????????*?1.?Get?the?string?of?new?record?which?will?be?save?to?DB?
- ??????*?2.?Since?the?object?is?a?generic?object,?so?the?reflect?mechanism?will?be????????*????used?to?access?the?data?of?the?bean.?
- ??????*?3.?assume?that?all?fields'nameof?the?bean?class?is?the?same?as????????*????the?columns'?name?of?table.?The?first?available?line?should?
- ??????*????give?the?columns'?sequence,?which?is?start?with?'ColumnSeq'.???????*????for?different?columns,?they?will?be?separated?by?'$_$'?
- ??????*?@param?oT:?the?object?of?bean????????*?@param?sFullFileName:?DB?file?name?with?completing?path?
- ??????*?@return?sRowData:?return?the?new?record?string???????*?@throws?IOException??
- ??????*?@throws?NoSuchMethodException????????*?@throws?SecurityException??
- ??????*?@throws?InvocationTargetException????????*?@throws?IllegalAccessException??
- ??????*?@throws?IllegalArgumentException????????*/??
- ??????private?<T>?String?convertBeantoStr(T?oT,?String?sFullFileName)??
- ????????????throws?IOException,?SecurityException,?NoSuchMethodException,??????????????IllegalArgumentException,?IllegalAccessException,??
- ????????????InvocationTargetException??????{??
- ????????//?define?the?return?value??????????String?sRowdata?=?"";??
- ??????????String[]?sColumns?=?null;??
- ????????BufferedReader?oBRead?=?null;??????????//?to?get?the?columns'?sequence??
- ????????try??????????{??
- ????????????oBRead?=?fileProcess.getBufferedFileReader(sFullFileName);??????????????String?sReadLine;??
- ????????????while?(null?!=?(sReadLine?=?oBRead.readLine()))??????????????{??
- ????????????????sReadLine?=?sReadLine.trim();??????????????????//?skip?the?comments?and?empty?lines??
- ????????????????if?("".equals(sReadLine)?||?sReadLine.startsWith("#"))??????????????????{??
- ????????????????????continue;??????????????????}??
- ??????????????????//?find?the?columns'?sequence??
- ????????????????if?(sReadLine.startsWith("ColumnSeq"))??????????????????{??
- ????????????????????sColumns?=?sReadLine.split(":")[1].split("\\$_\\$");??????????????????????break;??
- ????????????????}??????????????}??
- ????????}??????????catch?(IOException?e)??
- ????????{??????????????//?print?e,?and?throw?it,?so?the?method?which?invoked?it?can?process??
- ????????????//?it?freely.??????????????e.printStackTrace();??
- ????????????throw?e;??????????}??
- ????????finally??????????{??
- ????????????//?close?the?writer??????????????if?(null?!=?oBRead)??
- ????????????{??????????????????oBRead.close();??
- ????????????}??????????}??
- ??????????//?define?field?variable??
- ????????Method?oMethod?=?null;??????????String?sFieldName?=?"";??
- ????????String?sMethodName?=?"";??????????//?get?the?corresponding?columns'?value?through?the?reflect?mechanism??
- ????????for?(int?i?=?0;?i?<?sColumns.length;?i++)??????????{??
- ????????????//?initialize?the?method?name??????????????sMethodName?=?"get";??
- ????
- ????????????//?get?the?get?method?name?of?the?current?column??????????????sFieldName?=?sColumns[i].trim();??
- ????????????if?(sFieldName.length()?>?1)??????????????{??
- ????????????????sMethodName?=?sMethodName??????????????????????????+?sFieldName.substring(0,?1).toUpperCase()??
- ????????????????????????+?sFieldName.substring(1);??????????????}??
- ????????????else??????????????{??
- ????????????????sMethodName?=?sMethodName?+?sFieldName.toUpperCase();??????????????}??
- ????????????//?get?the?get?method??????????????oMethod?=?oT.getClass().getMethod(sMethodName);??
- ????????????//?Execute?the?method?to?get?the?value?of?the?current?field??????????????//?add?the?separator?of?the?columns?too??
- ????????????sRowdata?=?sRowdata?+?oMethod.invoke(oT)?+?"$_$";??????????}??
- ????????//?remove?the?last?separator??????????if?(!"".equals(sRowdata))??
- ????????{??????????????sRowdata?=?sRowdata.substring(0,?sRowdata.lastIndexOf("$_$"));??
- ????????}??????????return?sRowdata;??
- ????}??
3.有了上面两个步骤,就可以实现数据库记录的插入功能了a. 这个insert方法的传入参数就是一个Table Bean的对象, 当然对象里面有你要存储到文本文件里的数据
b.根据这个Table Bean的对象获取带路径的完整文件名
c.将Bean转化成一条合格的字符串
d.将该字符串写入对应的DB文件的最后(为了保证数据在单独的一行,数据前先插入了换行符)
同样的,为了使所有的表Bean都可以通过这一个方法插入数据,将方法定义成了泛型方法.?
本方法并没有实现检查主键的工作,自己可以根据需要重载或封装实现.
?
[java] view plaincopy
- /**??????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com?
- ?????*?Description:?Insert?one?record?to?text?DB??????*?@param?oT:?the?object?of?bean??
- ?????*?@return?oResult:???????*??????????ResultBean.result:?true?-?insert?success;?false?-?insert?failed?
- ?????*??????????ResultBean.description:?the?description?of?the?result;??????*?@throws?IOException??
- ?????*?@throws?InvocationTargetException???????*?@throws?IllegalAccessException??
- ?????*?@throws?NoSuchMethodException???????*?@throws?IllegalArgumentException??
- ?????*?@throws?SecurityException???????*/??
- ????public?<T>?ResultBean?insert(T?oT)?throws?IOException,?SecurityException,??????????????IllegalArgumentException,?NoSuchMethodException,??
- ????????????IllegalAccessException,?InvocationTargetException??????{??
- ????????ResultBean?oResult?=?new?ResultBean();????
- ????????boolean?bRet?=?false;??????????String?sDescription?=?"";??
- ??????????//?get?full?text?DB?file?name?with?full?path??
- ????????String?sFullFileName?=?this.getFullTableFileName(oT);????
- ????????//?get?sRowdata??????????String?sRowData?=?this.convertBeantoStr(oT,?sFullFileName);??
- ??????????PrintWriter?oPWriter?=?null;??
- ????????try??????????{??
- ????????????//?get?writer??????????????oPWriter?=?fileProcess??
- ????????????????????.getAppendBufferedFilePrintWriter(sFullFileName);??????????????//?write?to?file??
- ????????????oPWriter.write(System.getProperty("line.separator")?+?sRowData);??????????????oPWriter.flush();??
- ??????????????//?set?return?value?as?success??
- ????????????bRet?=?true;??????????????sDescription?=?"the?insert?record?is?\""?+?sRowData?+?"\".?"??
- ????????????????????+?".?It?is?saved?in?\""?+?sFullFileName??????????????????????+?"\"?successfully.";??
- ????????}??????????catch?(IOException?e)??
- ????????{??????????????e.printStackTrace();??
- ????????????throw?e;??????????}??
- ????????finally??????????{??
- ????????????//?close?the?writer??????????????if?(null?!=?oPWriter)??
- ????????????{??????????????????oPWriter.close();??
- ????????????}??????????}??
- ????????//?set?final?result.??????????oResult.setDescription(sDescription);??
- ????????oResult.setResult(bRet);????
- ????????return?oResult;??????}??
4. 先了解下如何将一条记录从文本数据库表文件中删除
java没有删除文本中某一行的接口,所以实现删除的算法就是,将文本内容全部读出来,将改行从缓存中删除,然后将处理后的缓存数据覆盖写入原文件. 缓存方式有两种一种全部存入内存适用于数据较少的时候,另一种是写入临时文件,适用于大数量时候.本demo全部读入内存了.
a. 获取对应DB文件的reader
b.然后一行一行的读取,一行一行的判断是否当前行就是要删除的行,如果不是则加入缓存的字符串中,否则丢弃
c.将处理后的缓存字符串写入对应的DB文件
?
[java] view plaincopy
- /**??????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com?
- ?????*?Description:???????*?1.delete?the?record?from?text?DB?file.??
- ?????*?2.the?arithmetic?is?read?all?the?contents?in??a?string?buffer?except???????*???the?deleting?record,?then?write?to?file?again.?
- ?????*?3.One?suggestion?for?huge?data,?develop?your?own?method?by?using?a??temporary?file??????*???as?a?buffered?
- ?????*?@param?sRowData:?the?record?which?will?be?deleted?from?the?file??????*?@param?sFullFileName:?DB?file?name?with?completing?path?
- ?????*?@return?bRet:?true?-?insert?success;?false?-?insert?failed??????*?@throws?IOException??
- ?????*/??????private?boolean?deleteRecordFromFile(String?sRowData,?String?sFullFileName)??
- ????????????throws?IOException??????{??
- ????????boolean?bRet?=?false;????
- ????????StringBuffer?sbFinalContent?=?new?StringBuffer();????
- ????????PrintWriter?oPWriter?=?null;??????????BufferedReader?oBRead?=?null;??
- ????????//?to?get?the?columns'?sequence??????????try??
- ????????{??????????????oBRead?=?fileProcess.getBufferedFileReader(sFullFileName);??
- ????????????String?sReadLine;??????????????String?sLastLIne?=?"sLastLIne";??
- ????????????while?(null?!=?(sReadLine?=?oBRead.readLine()))??????????????{??
- ????????????????sReadLine?=?sReadLine.trim();????
- ????????????????//?make?conjoined?duplicated?lines?to?one?line??????????????????//?to?avoid?too?many?empty?lines??
- ????????????????if?(sLastLIne.equals(sReadLine))??????????????????{??
- ????????????????????continue;??????????????????}??
- ????????????????//?delete?the?target?record??????????????????if?(sRowData.equals(sReadLine))??
- ????????????????{???????????????????//?set?result??
- ????????????????????bRet?=?true;??????????????????????????????????????????continue;??
- ????????????????}??????????????????//?cache?in?the?buffer??
- ????????????????sbFinalContent.append(sReadLine).append(??????????????????????????System.getProperty("line.separator"));??
- ????????????????//?set?last?line??????????????????sLastLIne?=?sReadLine;??
- ????????????}????
- ????????????//?get?writer??????????????oPWriter?=?fileProcess??
- ????????????????????.getBufferedFilePrintWriter(sFullFileName);????
- ????????????//?write?the?final?content?to?file??????????????oPWriter.write(sbFinalContent.toString());??
- ????????????oPWriter.flush();??????????}??
- ????????catch?(IOException?e)??????????{??
- ????????????//?print?e,?and?throw?it,?so?the?method?which?invoked?it?can?process??????????????//?it?freely.??
- ????????????e.printStackTrace();??????????????throw?e;??
- ????????}??????????finally??
- ????????{??????????????if?(null?!=?oBRead)??
- ????????????{??????????????????oBRead.close();??
- ????????????}??????????????//?close?the?writer??
- ????????????if?(null?!=?oPWriter)??????????????{??
- ????????????????oPWriter.close();??????????????}??
- ????????}??????????return?bRet;??
- ????}??
5. 有了上面的方法,我们就可以实现数据的删除功能了.
我们平时用的数据库可以使用主键或者其他字段作为条件来做删除, 这个在java里面就是多了一步字符串的分析操作.所以我没有实现这个功能, 在本demo中就是直接将整条记录作为判断条件来删除数据, 可以根据实际需要扩展本方法.
a.首先根据表的Bean对象获取文件名
b.然后将Bean对象转换为合格的表记录字符串
同样的,为了使所有的表Bean都可以通过这一个方法删除数据,将方法定义成了泛型方法.?c.调用上面的方法将记录从文件中删除.
?
[java] view plaincopy6.再看下如何更新文本数据库中的一条记录
- ?/**??????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com?
- ?????*?Description:?Delete?one?record?from?text?DB??????*?@param?oT:?the?object?of?bean??
- ?????*?@return?oResult:???????*??????????ResultBean.result:?true?-?insert?success;?false?-?insert?failed?
- ?????*??????????ResultBean.description:?the?description?of?the?result;??????*?@throws?InvocationTargetException??
- ?????*?@throws?IllegalAccessException???????*?@throws?NoSuchMethodException??
- ?????*?@throws?IOException???????*?@throws?IllegalArgumentException??
- ?????*?@throws?SecurityException???????*/??
- ????public?<T>?ResultBean?delete(T?oT)?throws?SecurityException,??????????????IllegalArgumentException,?IOException,?NoSuchMethodException,??
- ????????????IllegalAccessException,?InvocationTargetException??????{??
- ????????ResultBean?oResult?=?new?ResultBean();????
- ????????boolean?bRet?=?false;??????????String?sDescription?=?"";??
- ??????????//?get?full?text?DB?file?name?with?full?path??
- ????????String?sFullFileName?=?this.getFullTableFileName(oT);????
- ??????????//?get?sRowdata??
- ????????String?sRowData?=?this.convertBeantoStr(oT,?sFullFileName);????
- ????????//?delete?from?file??????????bRet?=?this.deleteRecordFromFile(sRowData,?sFullFileName);??
- ??????????//?set?result?description??
- ????????if?(bRet)??????????{??
- ????????????sDescription?=?"The?deleted?record?is?\""?+?sRowData?+?"\"?.?"??????????????????????+?"It?is?delete?from?\""?+?sFullFileName??
- ????????????????????+?"\"?successfully.";??????????}??
- ????????else??????????{??
- ????????????sDescription?=?"The?deleting?record?\""?+?sRowData??????????????????????+?"\"?is?not?there?in?the?file"?+?"?\""?+?sFullFileName??
- ????????????????????+?"\".";??????????}??
- ????????//?set?final?result.??????????oResult.setDescription(sDescription);??
- ????????oResult.setResult(bRet);????
- ????????return?oResult;??????}??
更新记录算法和删除记录是一样的,只不过删除时丢弃该记录, 更新时更换该记录, 不再赘述.
?
a. 获取对应DB文件的reader
b.然后一行一行的读取,一行一行的判断是否当前行就是要删除的行,如果不是则加入缓存的字符串中,否则增更换为目标字符串
c.将处理后的缓存字符串写入对应的DB文件
?
[java] view plaincopy
- /**??????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com?
- ?????*?Description:???????*?1.update?the?record?to?text?DB?file.??
- ?????*?2.the?arithmetic?is?read?all?the?contents?in??a?string?buffer,?replace???????*???the?updating?record,?then?write?to?file?again.?
- ?????*?3.One?suggestion?for?huge?data,?develop?your?own?method?by?using?a??temporary?file??????*???as?a?buffered?
- ?????*?@param?sRowData:?the?record?which?will?be?deleted?from?the?file??????*?@param?sFullFileName:?DB?file?name?with?completing?path??
- ?????*?@param?sPrimaryKeyValue:?the?value?of?the?primary?key??????*?@return?bRet:?true?-?insert?success;?false?-?insert?failed?
- ?????*?@throws?IOException???????*/??
- ????private?boolean?updateRecordToFile(String?sRowData,??????????????String?sPrimaryKeyValue,?String?sFullFileName)?throws?IOException??
- ????{??????????boolean?bRet?=?false;??
- ??????????StringBuffer?sbFinalContent?=?new?StringBuffer();??
- ??????????PrintWriter?oPWriter?=?null;??
- ????????BufferedReader?oBRead?=?null;????
- ????????try??????????{??
- ????????????oBRead?=?fileProcess.getBufferedFileReader(sFullFileName);??????????????String?sReadLine;??
- ????????????String?sLastLIne?=?"sLastLIne";??????????????String[]?sColumnValues?=?null;??
- ????????????while?(null?!=?(sReadLine?=?oBRead.readLine()))??????????????{??
- ????????????????sReadLine?=?sReadLine.trim();????
- ????????????????//?make?conjoined?duplicated?lines?to?one?line??????????????????//?to?avoid?too?many?empty?lines??
- ????????????????if?(sLastLIne.equals(sReadLine))??????????????????{??
- ????????????????????continue;??????????????????}??
- ??????????????????//?handle?the?comments,?empty?line,?ColumnSeq?line??
- ????????????????if?(sReadLine.startsWith("#")?||?"".equals(sReadLine)??????????????????????????||?sReadLine.startsWith("ColumnSeq"))??
- ????????????????{??????????????????????//?cache?in?the?buffer??
- ????????????????????sbFinalContent.append(sReadLine).append(??????????????????????????????System.getProperty("line.separator"));??
- ????????????????????continue;??????????????????}??
- ??????????????????//?handle?changing?record??
- ????????????????sColumnValues?=?sReadLine.split("\\$_\\$");??????????????????if?(sPrimaryKeyValue.trim().equals(sColumnValues[0].trim()))??
- ????????????????{??????????????????????//?cache?in?the?buffer??
- ????????????????????sbFinalContent.append(sRowData).append(??????????????????????????????System.getProperty("line.separator"));??
- ????????????????????continue;??????????????????}??
- ??????????????????//?cache?normal?record?in?the?buffer??
- ????????????????sbFinalContent.append(sReadLine).append(??????????????????????????System.getProperty("line.separator"));??
- ??????????????????//?set?last?line??
- ????????????????sLastLIne?=?sReadLine;??????????????}??
- ??????????????//?get?writer??
- ????????????oPWriter?=?fileProcess.getBufferedFilePrintWriter(sFullFileName);????
- ????????????//?write?the?final?content?to?file??????????????oPWriter.write(sbFinalContent.toString());??
- ????????????oPWriter.flush();????
- ????????????//?set?result??????????????bRet?=?true;??
- ????????}??????????catch?(IOException?e)??
- ????????{??????????????//?print?e,?and?throw?it,?so?the?method?which?invoked?it?can?process??
- ????????????//?it?freely.??????????????e.printStackTrace();??
- ????????????throw?e;??????????}??
- ????????finally??????????{??
- ????????????if?(null?!=?oBRead)??????????????{??
- ????????????????oBRead.close();??????????????}??
- ????????????//?close?the?writer??????????????if?(null?!=?oPWriter)??
- ????????????{??????????????????oPWriter.close();??
- ????????????}??????????}??
- ????????return?bRet;??????}??
7. 通过上面的更新方法,就可以实现记录的更新功能了.
同样的对与更新方法没有实现根据列值判断来更新相关的记录, 只是实现了根据主键更新整列数据局, 可以根据需要重写/扩展该方法
a.首先根据Table Bean后去带路径的玩这个路径名
b.在将Table Bean转换成一个合格的数据记录字符串
c.调用上面的方法,根据主键将目标记录替换
同样的,为了使所有的表Bean都可以通过这一个方更新数据,将方法定义成了泛型方法.?
?
[java] view plaincopy8. 了解下如何根据列名获取Table Bean的get 方法
- /**??????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com?
- ?????*?Description:?update?one?record?from?text?DB??????*?@param?oT:?the?object?of?bean??
- ?????*?@param?sPrimaryKeyValue:?the?value?of?the?primary?key??????*?@return?oResult:??
- ?????*??????????ResultBean.result:?true?-?insert?success;?false?-?insert?failed??????*??????????ResultBean.description:?the?description?of?the?result;?
- ?????*?@throws?InvocationTargetException???????*?@throws?IllegalAccessException??
- ?????*?@throws?NoSuchMethodException???????*?@throws?IOException??
- ?????*?@throws?IllegalArgumentException???????*?@throws?SecurityException??
- ?????*/??????public?<T>?ResultBean?update(T?oT,?String?sPrimaryKeyValue)??
- ????????????throws?SecurityException,?IllegalArgumentException,?IOException,??????????????NoSuchMethodException,?IllegalAccessException,??
- ????????????InvocationTargetException??????{??
- ????????ResultBean?oResult?=?new?ResultBean();????
- ????????boolean?bRet?=?false;??????????String?sDescription?=?"";??
- ??????????//?get?full?text?DB?file?name?with?full?path??
- ????????String?sFullFileName?=?this.getFullTableFileName(oT);????
- ????????//?get?sRowdata??????????String?sRowData?=?this.convertBeantoStr(oT,?sFullFileName);??
- ??????????//?delete?from?file??
- ????????bRet?=?this.updateRecordToFile(sRowData,?sPrimaryKeyValue,??????????????????sFullFileName);??
- ??????????//?set?result?description??
- ????????if?(bRet)??????????{??
- ????????????sDescription?=?"The?updated?record?is?\""?+?sRowData?+?"\".?"??????????????????????+?"?It?is?update?to?\""?+?sFullFileName??
- ????????????????????+?"\"?successfully.";??????????}??
- ????????else??????????{??
- ????????????sDescription?=?"The?updating?record?\""?+?sRowData??????????????????????+?"\"?is?not?there?in?the?file"?+?"?\""?+?sFullFileName??
- ????????????????????+?"\".";??????????}??
- ????????//?set?final?result.??????????oResult.setDescription(sDescription);??
- ????????oResult.setResult(bRet);??????????return?oResult;??
- ????}??
由于列名和Bean的Field名字是一样的,根据这儿特性,可以拼接出来对应的set方法的方法名. 详细步骤可以参考注释
同样的,为了使所有的表Bean都可以通过这一个方法获取set方法,将方法定义成了泛型方法.?
?
[java] view plaincopy
- /**??????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com?
- ?????*?Description:?Get?all?set?method?names.??????*?assume?that?all?the?field?names?of?bean?class?of?table?are?the?same?as?the?column?names?
- ?????*?@param?oT:?the?object?of?bean???????*?@param?sColumns:?the?columns?
- ?????*?@return?HashMap?<String,String>???????*???????????-?key:?column?name;???
- ?????*???????????-?value:?the?corresponding?set?method?name??????*/??
- ????private?<T>?HashMap<String,?String>?getSetMethods(String[]?sColumns,?T?oT)??????{??
- ????????HashMap<String,?String>?oHM?=?new?HashMap<String,?String>();??????????String?sMethodName?=?"";??
- ????????String?sFieldName?=?"";??????????for?(int?i?=?0;?i?<?sColumns.length;?i++)??
- ????????{??????????????//?initialize?the?method?name??
- ????????????sMethodName?=?"set";????
- ????????????//?get?the?get?method?name?of?the?current?column??????????????sFieldName?=?sColumns[i].trim();??
- ????????????if?(sFieldName.length()?>?1)??????????????{??
- ????????????????sMethodName?=?sMethodName??????????????????????????+?sFieldName.substring(0,?1).toUpperCase()??
- ????????????????????????+?sFieldName.substring(1);??????????????}??
- ????????????else??????????????{??
- ????????????????sMethodName?=?sMethodName?+?sFieldName.toUpperCase();??????????????}??
- ????????????oHM.put(sColumns[i],?sMethodName);??????????}??
- ????????return?oHM;??????}??
9. 有了上面的方法,我们也可以更加easy的实现数据的查询功能了.
为了免去分析字符串的麻烦,本demo只是先了查询所有数据的功能,可以根据需要扩展该方法.
这个方法设计是将所有数据读取出来放入Bean中,一条记录就是一个Bean对象,所以最终返回值是一个Bean对象的list
a.首先获取对应的带路径的完整文件名
b.获取对应数据库文件的reader
c.将数据一条一条的读出来,一条一条的处理. 跳过注释,空行,及标示列名和列顺序的行, 将其他有效的数据库记录进行处理
d.根据列名得出所有field的set方法
c.将数据库记录分割后,调用set方法赋给Bean对象
d.将赋值完后的Bean对象加入List, 如此循环处理所有记录.
同样的,为了使所有的表Bean都可以通过这一个方法获取对应的数据列表,将方法定义成了泛型方法.?
另外注意一点, 由于set方法是有输入参数的,所以使用反射机制构造或者执行方法的时候是需要指定这些参数类型或者参数的, 由于demo中的数据类型都是使用的String类型,所以是取巧了的, 如果需要支持其他类型,可以对此方法做修改,对类型做下分析.
?
[java] view plaincopy
- /**??????*?Author:?Jiangtao?He;?Email:?ross.jiangtao.he@gmail.com?
- ?????*?Description:?query?all?the?records?from?text?DB??????*?@param?oT:?the?object?of?bean??
- ?????*?@param?sPrimaryKeyValue:?the?value?of?the?primary?key??????*?@return?oTList:?the?object?list?of?the?bean?
- ?????*?@throws?InvocationTargetException???????*?@throws?IllegalAccessException??
- ?????*?@throws?IllegalArgumentException???????*?@throws?NoSuchMethodException??
- ?????*?@throws?SecurityException???????*?@throws?InstantiationException??
- ?????*?@throws?IOException???????*/??
- ????public?<T>?List<T>?queryAll(T?oT)?throws?IllegalArgumentException,??????????????IllegalAccessException,?InvocationTargetException,??
- ????????????SecurityException,?NoSuchMethodException,?InstantiationException,?IOException??????{??
- ????????List<T>?oTList?=?new?ArrayList<T>();????
- ????????//?get?full?text?DB?file?name?with?full?path??????????String?sFullFileName?=?this.getFullTableFileName(oT);??
- ??????????BufferedReader?oBRead?=?null;??
- ????????try??????????{??
- ????????????oBRead?=?fileProcess.getBufferedFileReader(sFullFileName);??????????????String?sReadLine;??
- ????????????String[]?sColumns?=?null;??????????????HashMap<String,?String>?oHM?=?null;??
- ????????????String[]?sColumnValues?=?null;??????????????int?iNumOfColumns;??
- ????????????Method?oMethod;??????????????while?(null?!=?(sReadLine?=?oBRead.readLine()))??
- ????????????{??????????????????sReadLine?=?sReadLine.trim();??
- ??????????????????//?skip?comments,?empty?line??
- ????????????????if?(sReadLine.startsWith("#")?||?"".equals(sReadLine))??????????????????{??
- ????????????????????continue;??????????????????}??
- ??????????????????//?get?set?method?names?of?the?bean??
- ????????????????if?(sReadLine.startsWith("ColumnSeq"))??????????????????{??
- ????????????????????sColumns?=?sReadLine.split(":")[1].split("\\$_\\$");??????????????????????oHM?=?this.getSetMethods(sColumns,?oT);??
- ????????????????????continue;??????????????????}??
- ??????????????????//?get?values?of?the?a?record??
- ????????????????sColumnValues?=?sReadLine.split("\\$_\\$");????
- ????????????????//?check?the?number?of?values?is?less?than?columns?or?not,?the??????????????????//?smaller?one?will?be?used?in?the?loop?to?avoid?out?of?array??
- ????????????????//?index?exception??????????????????iNumOfColumns?=?sColumnValues.length?>?sColumns.length???sColumns.length??
- ????????????????????????:?sColumnValues.length;??????????????????for?(int?i?=?0;?i?<?iNumOfColumns;?i++)??
- ????????????????{??????????????????????//?get?the?get?method??
- ????????????????????oMethod?=?oT.getClass().getMethod(oHM.get(sColumns[i]),String.class);??????????????????????//?execute?the?method?to?set?the?value?into?bean??
- ????????????????????oMethod.invoke(oT,?sColumnValues[i]);??????????????????}??
- ????????????????//add?the?bean?into?the?bean?list??????????????????oTList.add(oT);??
- ????????????????//assign?a?new?instance?to?the?bean??????????????????oT?=?(T)?oT.getClass().newInstance();??
- ????????????}??????????}??
- ????????catch?(IOException?e)??????????{??
- ????????????//?print?e,?and?throw?it,?so?the?method?which?invoked?it?can?process??????????????//?it?freely.??
- ????????????e.printStackTrace();??????????????throw?e;??
- ????????}??????????finally??
- ????????{??????????????if?(null?!=?oBRead)??
- ????????????{??????????????????oBRead.close();??
- ????????????}??????????}??
- ????????return?oTList;??????}??
?至此增删改查功能的思路算是实现了.
我们使用junit做下测试看下效果--我在4个测试方法上都打了断点, 分别看下实际效果(由于junit代码较长,我就不贴了,感兴趣的可以下载下来看):
增加一条记录到home和member表:
控制台:
?
[java] view plaincopy
- Insert?one?home?record?-?result:?true;?description:?the?insert?record?is?"Ross_1$_$Ross's?Home$_$252363693$_$ross.jiangtao.he@gmail.com$_$China?P.R.".?.?It?is?saved?in?"E:\myspace\MyJavaExpert?V1.0\db\T_Home.db"?successfully.??Insert?one?faminily?member?record?-?result:?true;?description:?the?insert?record?is?"Yan$_$Pery$_$Female$_$252363693$_$ross.jiangtao.he@gmail.com$_$null$_$Ross_1".?.?It?is?saved?in?"E:\myspace\MyJavaExpert?V1.0\db\T_FamilyMember.db"?successfully.??
数据库文件内容:T_Home.db:
?
[java] view plaincopyT_FamilyMember.db:
- #Column?Sequence??ColumnSeq:?id$_$name$_$phone$_$email$_$address??
- ??#Content?Start??
- Ross_1$_$Ross's?Home$_$252363693$_$ross.jiangtao.he@gmail.com$_$China?P.R.??
?
[java] view plaincopy
- #Column?Sequence??ColumnSeq:?id$_$name$_$gender$_$mobile$_$email$_$address$_$family_id??
- ??#content?start??
- Yan$_$Pery$_$Female$_$252363693$_$ross.jiangtao.he@gmail.com$_$null$_$Ross_1??
查询home和member表的记录:
控制台:?
[java] view plaincopy
- Query?all?the?home?record(s)?from?file,?totally?get?:?1?record(s)??Query?all?the?family?member?record(s)?from?file,?totally?get?:?1?record(s)??
更新home和member表的记录(可以看多了"O(∩_∩)O~~"的列)控制台:?
[java] view plaincopyT_Home.db:
- Update?one?faminily?member?record?-?result:?true;?description:?The?updated?record?is?"Yan$_$Pery$_$Female$_$10086?O(∩_∩)O~~$_$ross.jiangtao.he@gmail.com$_$null$_$Ross_1".??It?is?update?to?"E:\myspace\MyJavaExpert?V1.0\db\T_FamilyMember.db"?successfully.??Update?one?home?record?-?result:?true;?description:?The?updated?record?is?"Ross_1$_$Pery's?Home?O(∩_∩)O~~$_$252363693$_$ross.jiangtao.he@gmail.com$_$China?P.R.".??It?is?update?to?"E:\myspace\MyJavaExpert?V1.0\db\T_Home.db"?successfully.??
?
[java] view plaincopy
- #Column?Sequence??ColumnSeq:?id$_$name$_$phone$_$email$_$address??
- #Content?Start??Ross_1$_$Pery's?Home?O(∩_∩)O~~$_$252363693$_$ross.jiangtao.he@gmail.com$_$China?P.R.??
T_FamilyMember.db:
[java] view plaincopy
- <pre?name="code"?class="java">#Column?Sequence??ColumnSeq:?id$_$name$_$gender$_$mobile$_$email$_$address$_$family_id??
- #content?start??Yan$_$Pery$_$Female$_$10086?O(∩_∩)O~~$_$ross.jiangtao.he@gmail.com$_$null$_$Ross_1??
删除home和member表的一条记录控制台:[java] view plaincopyT_Home.db:[java] view plaincopy
- Delete?one?faminily?member?record?-?result:?true;?description:?The?deleted?record?is?"Yan$_$Pery$_$Female$_$10086?O(∩_∩)O~~$_$ross.jiangtao.he@gmail.com$_$null$_$Ross_1"?.?It?is?delete?from?"E:\myspace\MyJavaExpert?V1.0\db\T_FamilyMember.db"?successfully.??Delete?one?home?record?-?result:?true;?description:?The?deleted?record?is?"Ross_1$_$Pery's?Home?O(∩_∩)O~~$_$252363693$_$ross.jiangtao.he@gmail.com$_$China?P.R."?.?It?is?delete?from?"E:\myspace\MyJavaExpert?V1.0\db\T_Home.db"?successfully.??
T_FamilyMember.db:
- #Column?Sequence??ColumnSeq:?id$_$name$_$phone$_$email$_$address??
- #Content?Start??
?
[java] view plaincopy
- #Column?Sequence??ColumnSeq:?id$_$name$_$gender$_$mobile$_$email$_$address$_$family_id??
- #content?start??
?至此"文本数据库简单的实现思路"已经完成了.