`

文本数据库的简单java实现

    博客分类:
  • 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 plain copy
  1. #Column Sequence  
  2. ColumnSeq: id$_$name$_$phone$_$email$_$address  
  3. #Content Start  
T_FamilyMember.db:

 

[java] view plain copy
  1. #Column Sequence  
  2. ColumnSeq: id$_$name$_$gender$_$mobile$_$email$_$address$_$family_id  
  3. #content start  
T_HomeBean.java:

 

[java] view plain copy
  1. package  com.ross.filedb.tablebean;  
  2. /**  
  3.  * Author: Jiangtao He  
  4.  * Since: MyJavaExpert v1.0  
  5.  */   
  6. public   class  T_HomeBean  
  7. {  
  8.     private  String id;  
  9.     private  String name;  
  10.     private  String phone;  
  11.     private  String email;  
  12.     private  String address;  
  13.   
  14.     //省略了set/get方法   
  15. }  
T_FamilyMemberBean.java:

 

[java] view plain copy
  1. package  com.ross.filedb.tablebean;  
  2. /**  
  3.  * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  4.  * Since: MyJavaExpert v1.0  
  5.  */   
  6. public   class  T_FamilyMemberBean  
  7. {  
  8.     private  String id;  
  9.     private  String name;  
  10.     private  String gender;  
  11.     private  String mobile;  
  12.     private  String email;  
  13.     private  String address;  
  14.     private  String family_id;  
  15.     //省略了set/get方法   
  16. }  


再介绍下我的通用方法和系统级变量:

           SysValues.java:

系统及变量,主要是在使用java反射机制的时候分析类名或者文件名.

 

[java] view plain copy
  1. package  com.ross.filedb.util;  
  2. /**  
  3.  * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  4.  * Date: 2011-12-30  
  5.  * Version: MyJavaExpert v1.0  
  6.  * Description: system level variables  
  7.  */   
  8. public   class  SysValues  
  9. {  
  10.     // DB constant variables   
  11.     public   static   final  String DB_Path = System.getProperty( "user.dir" )  
  12.             + System.getProperty("file.separator" ) +  "db"   
  13.             + System.getProperty("file.separator" );  
  14.     public   static   final  String DB_Bean_Suffix =  "Bean" ;  
  15.     public   static   final  String DB_File_Suffix =  ".db" ;  
  16.   
  17. }  
ResultBean.java:

用于一般的方法返回结果.

 

[java] view plain copy
  1. package  com.ross.filedb.util;  
  2. /**  
  3.  * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  4.  * Date: 2011-12-31  
  5.  * Since: MyJavaExpert v1.0  
  6.  * Description: To store the return value.  
  7.  */   
  8. public   class  ResultBean  
  9. {  
  10.     boolean  result;  
  11.     String description;  
  12.    //省略了set/get方法   
  13. }  
FileProcess.java

java IO的操作,总要一堆的对象相互嵌套才能生成合适的writer或者reader, 这个类的作用就是把这个步骤汇总,其他类可以直接引用,省去这些繁琐的麻烦. 具体功能,代码里有详细注释.

[java] view plain copy
  1. package  com.ross.filedb.util;  
  2.   
  3. import  java.io.BufferedReader;  
  4. import  java.io.BufferedWriter;  
  5. import  java.io.FileReader;  
  6. import  java.io.FileWriter;  
  7. import  java.io.IOException;  
  8. import  java.io.PrintWriter;  
  9. /**  
  10.  * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  11.  * Since: MyJavaExpert v1.0  
  12.  * Description: this class will implement the common file process.  
  13.  */   
  14. public   class  FileProcess  
  15. {  
  16.     /**  
  17.      * Description: get a buffered file append writer according the file name (with full path)  
  18.      * PrintWriter will be more easy to access text, BufferedWriter is used to   
  19.      * cache the data to improve the performance.  
  20.      */   
  21.     public  PrintWriter getAppendBufferedFilePrintWriter(String sFullFileName)  
  22.             throws  IOException  
  23.     {  
  24.         PrintWriter oPWriter = new  PrintWriter( new  BufferedWriter(  
  25.                 new  FileWriter(sFullFileName,  true )));  
  26.         return  oPWriter;  
  27.     }  
  28.   
  29.     /**  
  30.      * Author: Jiangtao He  
  31.      * Description: get a buffered file writer according the file name (with full path)  
  32.      * PrintWriter will be more easy to access text, BufferedWriter is used to   
  33.      * cache the data to improve the performance.  
  34.      */   
  35.     public  PrintWriter getBufferedFilePrintWriter(String sFullFileName)  
  36.             throws  IOException  
  37.     {  
  38.         PrintWriter oPWriter = new  PrintWriter( new  BufferedWriter(  
  39.                 new  FileWriter(sFullFileName)));  
  40.         return  oPWriter;  
  41.     }  
  42.       
  43.     /**  
  44.      * Author: Jiangtao He  
  45.      * Description: get a buffered file reader according the file name (with full path)  
  46.      * BufferedReader is used to cache the data to improve the performance.  
  47.      */   
  48.     public  BufferedReader getBufferedFileReader(String sFullFileName)  
  49.             throws  IOException  
  50.     {  
  51.         BufferedReader oBufferedReader = new  BufferedReader( new  FileReader(  
  52.                 sFullFileName));  
  53.         return  oBufferedReader;  
  54.     }  
  55. }  


最后就是我们的增删改查功能实现了:

FileDBTool.java:

1. 看下如何根据bean类获取对应的文本数据库的表文件名. 

a.首先获取完整类名,例如 com.ross.filedb.tablebean.T_HomeBean;

b.然后去除包名,只剩T_HomeBean; 

c.再将Bean后缀去掉,加上路径和.db后缀,就将文本数据库的表文件名给拼出来了.

 

[java] view plain copy
  1. /**  
  2.      * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.      * Description: Get the text DB's file name with full path name.  
  4.      * assume that all the bean class of table is formed by   
  5.      * table name + suffix (like: Bean), for example: T_Home-->T_HomeBean.java  
  6.      * @param oT: the object of bean   
  7.      * @return sFullFileName: db file name with completing path  
  8.      */   
  9.     private  <T> String getFullTableFileName(T oT)  
  10.     {  
  11.         String sFullFileName = "" ;  
  12.   
  13.         // the class name is like com.ross.filedb.tablebean.T_HomeBean, only keep   
  14.         // T_Home   
  15.         String[] sTmps = oT.getClass().getName().split("\\." );  
  16.         sFullFileName = sTmps[sTmps.length - 1 ];  
  17.   
  18.         sFullFileName = SysValues.DB_Path  
  19.                 + sFullFileName.substring(0 , sFullFileName  
  20.                         .indexOf(SysValues.DB_Bean_Suffix))  
  21.                 + SysValues.DB_File_Suffix;  
  22.         return  sFullFileName;  
  23.     }  
2. 看下如何将Bean转换成一条表记录(使用"$_$"分割各列,各列需按照指定顺序排列)

a.首先根据上面的方法拼出来的带路径的文件名读出列名和各列顺序

b.然后根据列名拼出类的Field的get方法

c.再根据拼接出来的get方法,使用java的反射机制, 生成对应的Method对象, 并使用invoke方法执行该方法

d.使用循环拼接各个Field的值在一起,并使用"$_$"分割各个Field

另外,为了使所有的Bean都可以通过这一个方法转换成对应的字符串,将方法定义成了泛型方法, 可以看到泛型T.

不了解java反射和泛型的可以从网上搜一下,或者看我后续的博客了解 奋斗

 

[java] view plain copy
  1. /**  
  2.       * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.       * Description:   
  4.       * 1. Get the string of new record which will be save to DB  
  5.       * 2. Since the object is a generic object, so the reflect mechanism will be   
  6.       *    used to access the data of the bean.  
  7.       * 3. assume that all fields'nameof the bean class is the same as   
  8.       *    the columns' name of table. The first available line should  
  9.       *    give the columns' sequence, which is start with 'ColumnSeq'.  
  10.       *    for different columns, they will be separated by '$_$'  
  11.       * @param oT: the object of bean   
  12.       * @param sFullFileName: DB file name with completing path  
  13.       * @return sRowData: return the new record string  
  14.       * @throws IOException   
  15.       * @throws NoSuchMethodException   
  16.       * @throws SecurityException   
  17.       * @throws InvocationTargetException   
  18.       * @throws IllegalAccessException   
  19.       * @throws IllegalArgumentException   
  20.       */   
  21.   
  22.     private  <T> String convertBeantoStr(T oT, String sFullFileName)  
  23.             throws  IOException, SecurityException, NoSuchMethodException,  
  24.             IllegalArgumentException, IllegalAccessException,  
  25.             InvocationTargetException  
  26.     {  
  27.         // define the return value   
  28.         String sRowdata = "" ;  
  29.   
  30.         String[] sColumns = null ;  
  31.         BufferedReader oBRead = null ;  
  32.         // to get the columns' sequence   
  33.         try   
  34.         {  
  35.             oBRead = fileProcess.getBufferedFileReader(sFullFileName);  
  36.             String sReadLine;  
  37.             while  ( null  != (sReadLine = oBRead.readLine()))  
  38.             {  
  39.                 sReadLine = sReadLine.trim();  
  40.                 // skip the comments and empty lines   
  41.                 if  ( "" .equals(sReadLine) || sReadLine.startsWith( "#" ))  
  42.                 {  
  43.                     continue ;  
  44.                 }  
  45.   
  46.                 // find the columns' sequence   
  47.                 if  (sReadLine.startsWith( "ColumnSeq" ))  
  48.                 {  
  49.                     sColumns = sReadLine.split(":" )[ 1 ].split( "\\$_\\$" );  
  50.                     break ;  
  51.                 }  
  52.             }  
  53.         }  
  54.         catch  (IOException e)  
  55.         {  
  56.             // print e, and throw it, so the method which invoked it can process   
  57.             // it freely.   
  58.             e.printStackTrace();  
  59.             throw  e;  
  60.         }  
  61.         finally   
  62.         {  
  63.             // close the writer   
  64.             if  ( null  != oBRead)  
  65.             {  
  66.                 oBRead.close();  
  67.             }  
  68.         }  
  69.   
  70.         // define field variable   
  71.         Method oMethod = null ;  
  72.         String sFieldName = "" ;  
  73.         String sMethodName = "" ;  
  74.         // get the corresponding columns' value through the reflect mechanism   
  75.         for  ( int  i =  0 ; i < sColumns.length; i++)  
  76.         {  
  77.             // initialize the method name   
  78.             sMethodName = "get" ;  
  79.   
  80.   
  81.             // get the get method name of the current column   
  82.             sFieldName = sColumns[i].trim();  
  83.             if  (sFieldName.length() >  1 )  
  84.             {  
  85.                 sMethodName = sMethodName  
  86.                         + sFieldName.substring(0 1 ).toUpperCase()  
  87.                         + sFieldName.substring(1 );  
  88.             }  
  89.             else   
  90.             {  
  91.                 sMethodName = sMethodName + sFieldName.toUpperCase();  
  92.             }  
  93.             // get the get method   
  94.             oMethod = oT.getClass().getMethod(sMethodName);  
  95.             // Execute the method to get the value of the current field   
  96.             // add the separator of the columns too   
  97.             sRowdata = sRowdata + oMethod.invoke(oT) + "$_$" ;  
  98.         }  
  99.         // remove the last separator   
  100.         if  (! "" .equals(sRowdata))  
  101.         {  
  102.             sRowdata = sRowdata.substring(0 , sRowdata.lastIndexOf( "$_$" ));  
  103.         }  
  104.         return  sRowdata;  
  105.     }  
3.有了上面两个步骤,就可以实现数据库记录的插入功能了

a. 这个insert方法的传入参数就是一个Table Bean的对象, 当然对象里面有你要存储到文本文件里的数据

b.根据这个Table Bean的对象获取带路径的完整文件名

c.将Bean转化成一条合格的字符串

d.将该字符串写入对应的DB文件的最后(为了保证数据在单独的一行,数据前先插入了换行符)

同样的,为了使所有的表Bean都可以通过这一个方法插入数据,将方法定义成了泛型方法. 

本方法并没有实现检查主键的工作,自己可以根据需要重载或封装实现.

 

[java] view plain copy
  1. /**  
  2.      * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.      * Description: Insert one record to text DB  
  4.      * @param oT: the object of bean   
  5.      * @return oResult:   
  6.      *          ResultBean.result: true - insert success; false - insert failed  
  7.      *          ResultBean.description: the description of the result;  
  8.      * @throws IOException   
  9.      * @throws InvocationTargetException   
  10.      * @throws IllegalAccessException   
  11.      * @throws NoSuchMethodException   
  12.      * @throws IllegalArgumentException   
  13.      * @throws SecurityException   
  14.      */   
  15.     public  <T> ResultBean insert(T oT)  throws  IOException, SecurityException,  
  16.             IllegalArgumentException, NoSuchMethodException,  
  17.             IllegalAccessException, InvocationTargetException  
  18.     {  
  19.         ResultBean oResult = new  ResultBean();  
  20.   
  21.         boolean  bRet =  false ;  
  22.         String sDescription = "" ;  
  23.   
  24.         // get full text DB file name with full path   
  25.         String sFullFileName = this .getFullTableFileName(oT);  
  26.   
  27.         // get sRowdata   
  28.         String sRowData = this .convertBeantoStr(oT, sFullFileName);  
  29.   
  30.         PrintWriter oPWriter = null ;  
  31.         try   
  32.         {  
  33.             // get writer   
  34.             oPWriter = fileProcess  
  35.                     .getAppendBufferedFilePrintWriter(sFullFileName);  
  36.             // write to file   
  37.             oPWriter.write(System.getProperty("line.separator" ) + sRowData);  
  38.             oPWriter.flush();  
  39.   
  40.             // set return value as success   
  41.             bRet = true ;  
  42.             sDescription = "the insert record is \""  + sRowData +  "\". "   
  43.                     + ". It is saved in \""  + sFullFileName  
  44.                     + "\" successfully." ;  
  45.         }  
  46.         catch  (IOException e)  
  47.         {  
  48.             e.printStackTrace();  
  49.             throw  e;  
  50.         }  
  51.         finally   
  52.         {  
  53.             // close the writer   
  54.             if  ( null  != oPWriter)  
  55.             {  
  56.                 oPWriter.close();  
  57.             }  
  58.         }  
  59.         // set final result.   
  60.         oResult.setDescription(sDescription);  
  61.         oResult.setResult(bRet);  
  62.   
  63.         return  oResult;  
  64.     }  

4. 先了解下如何将一条记录从文本数据库表文件中删除

java 没有删除文本中某一行的接口,所以实现删除的算法就是,将文本内容全部读出来,将改行从缓存中删除,然后将处理后的缓存数据覆盖写入原文件. 缓存方式有两种一种全部存入内存适用于数据较少的时候,另一种是写入临时文件,适用于大数量时候.本demo全部读入内存了.

a. 获取对应DB文件的reader

b. 然后一行一行的读取,一行一行的判断是否当前行就是要删除的行,如果不是则加入缓存的字符串中,否则丢弃

c.将处理后的缓存字符串写入对应的DB文件

 

[java] view plain copy
  1. /**  
  2.      * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.      * Description:   
  4.      * 1.delete the record from text DB file.   
  5.      * 2.the arithmetic is read all the contents in  a string buffer except   
  6.      *   the deleting record, then write to file again.  
  7.      * 3.One suggestion for huge data, develop your own method by using a  temporary file  
  8.      *   as a buffered  
  9.      * @param sRowData: the record which will be deleted from the file  
  10.      * @param sFullFileName: DB file name with completing path  
  11.      * @return bRet: true - insert success; false - insert failed  
  12.      * @throws IOException   
  13.      */   
  14.     private   boolean  deleteRecordFromFile(String sRowData, String sFullFileName)  
  15.             throws  IOException  
  16.     {  
  17.         boolean  bRet =  false ;  
  18.   
  19.         StringBuffer sbFinalContent = new  StringBuffer();  
  20.   
  21.         PrintWriter oPWriter = null ;  
  22.         BufferedReader oBRead = null ;  
  23.         // to get the columns' sequence   
  24.         try   
  25.         {  
  26.             oBRead = fileProcess.getBufferedFileReader(sFullFileName);  
  27.             String sReadLine;  
  28.             String sLastLIne = "sLastLIne" ;  
  29.             while  ( null  != (sReadLine = oBRead.readLine()))  
  30.             {  
  31.                 sReadLine = sReadLine.trim();  
  32.   
  33.                 // make conjoined duplicated lines to one line   
  34.                 // to avoid too many empty lines   
  35.                 if  (sLastLIne.equals(sReadLine))  
  36.                 {  
  37.                     continue ;  
  38.                 }  
  39.                 // delete the target record   
  40.                 if  (sRowData.equals(sReadLine))  
  41.                 {  
  42.                  // set result   
  43.                     bRet = true ;                      
  44.                     continue ;  
  45.                 }  
  46.                 // cache in the buffer   
  47.                 sbFinalContent.append(sReadLine).append(  
  48.                         System.getProperty("line.separator" ));  
  49.                 // set last line   
  50.                 sLastLIne = sReadLine;  
  51.             }  
  52.   
  53.             // get writer   
  54.             oPWriter = fileProcess  
  55.                     .getBufferedFilePrintWriter(sFullFileName);  
  56.   
  57.             // write the final content to file   
  58.             oPWriter.write(sbFinalContent.toString());  
  59.             oPWriter.flush();  
  60.         }  
  61.         catch  (IOException e)  
  62.         {  
  63.             // print e, and throw it, so the method which invoked it can process   
  64.             // it freely.   
  65.             e.printStackTrace();  
  66.             throw  e;  
  67.         }  
  68.         finally   
  69.         {  
  70.             if  ( null  != oBRead)  
  71.             {  
  72.                 oBRead.close();  
  73.             }  
  74.             // close the writer   
  75.             if  ( null  != oPWriter)  
  76.             {  
  77.                 oPWriter.close();  
  78.             }  
  79.         }  
  80.         return  bRet;  
  81.     }  

5. 有了上面的方法,我们就可以实现数据的删除功能了.

我们平时用的数据库可以使用主键或者其他字段作为条件来做删除, 这个在java里面就是多了一步字符串的分析操作.所以我没有实现这个功能, 在本demo中就是直接将整条记录作为判断条件来删除数据, 可以根据实际需要扩展本方法.

a.首先根据表的Bean对象获取文件名

b.然后将Bean对象转换为合格的表记录字符串

c.调用上面的方法将记录从文件中删除.

同样的, 为了使所有的表Bean都可以通过这一个方法删除数据,将方法定义成了泛型方法. 

 

[java] view plain copy
  1.   /**  
  2.      * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.      * Description: Delete one record from text DB  
  4.      * @param oT: the object of bean   
  5.      * @return oResult:   
  6.      *          ResultBean.result: true - insert success; false - insert failed  
  7.      *          ResultBean.description: the description of the result;  
  8.      * @throws InvocationTargetException   
  9.      * @throws IllegalAccessException   
  10.      * @throws NoSuchMethodException   
  11.      * @throws IOException   
  12.      * @throws IllegalArgumentException   
  13.      * @throws SecurityException   
  14.      */   
  15.     public  <T> ResultBean delete(T oT)  throws  SecurityException,  
  16.             IllegalArgumentException, IOException, NoSuchMethodException,  
  17.             IllegalAccessException, InvocationTargetException  
  18.     {  
  19.         ResultBean oResult = new  ResultBean();  
  20.   
  21.         boolean  bRet =  false ;  
  22.         String sDescription = "" ;  
  23.   
  24.         // get full text DB file name with full path   
  25.         String sFullFileName = this .getFullTableFileName(oT);  
  26.   
  27.   
  28.         // get sRowdata   
  29.         String sRowData = this .convertBeantoStr(oT, sFullFileName);  
  30.   
  31.         // delete from file   
  32.         bRet = this .deleteRecordFromFile(sRowData, sFullFileName);  
  33.   
  34.         // set result description   
  35.         if  (bRet)  
  36.         {  
  37.             sDescription = "The deleted record is \""  + sRowData +  "\" . "   
  38.                     + "It is delete from \""  + sFullFileName  
  39.                     + "\" successfully." ;  
  40.         }  
  41.         else   
  42.         {  
  43.             sDescription = "The deleting record \""  + sRowData  
  44.                     + "\" is not there in the file"  +  " \""  + sFullFileName  
  45.                     + "\"." ;  
  46.         }  
  47.         // set final result.   
  48.         oResult.setDescription(sDescription);  
  49.         oResult.setResult(bRet);  
  50.   
  51.         return  oResult;  
  52.     }  
6.再看下如何更新文本数据库中的一条记录

更新记录算法和删除记录是一样的,只不过删除时丢弃该记录, 更新时更换该记录, 不再赘述.

 

a. 获取对应DB文件的reader

b. 然后一行一行的读取,一行一行的判断是否当前行就是要删除的行,如果不是则加入缓存的字符串中,否则增更换为目标字符串

c.将处理后的缓存字符串写入对应的DB文件

 

[java] view plain copy
  1. /**  
  2.      * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.      * Description:   
  4.      * 1.update the record to text DB file.   
  5.      * 2.the arithmetic is read all the contents in  a string buffer, replace   
  6.      *   the updating record, then write to file again.  
  7.      * 3.One suggestion for huge data, develop your own method by using a  temporary file  
  8.      *   as a buffered  
  9.      * @param sRowData: the record which will be deleted from the file  
  10.      * @param sFullFileName: DB file name with completing path   
  11.      * @param sPrimaryKeyValue: the value of the primary key  
  12.      * @return bRet: true - insert success; false - insert failed  
  13.      * @throws IOException   
  14.      */   
  15.     private   boolean  updateRecordToFile(String sRowData,  
  16.             String sPrimaryKeyValue, String sFullFileName) throws  IOException  
  17.     {  
  18.         boolean  bRet =  false ;  
  19.   
  20.         StringBuffer sbFinalContent = new  StringBuffer();  
  21.   
  22.         PrintWriter oPWriter = null ;  
  23.         BufferedReader oBRead = null ;  
  24.   
  25.         try   
  26.         {  
  27.             oBRead = fileProcess.getBufferedFileReader(sFullFileName);  
  28.             String sReadLine;  
  29.             String sLastLIne = "sLastLIne" ;  
  30.             String[] sColumnValues = null ;  
  31.             while  ( null  != (sReadLine = oBRead.readLine()))  
  32.             {  
  33.                 sReadLine = sReadLine.trim();  
  34.   
  35.                 // make conjoined duplicated lines to one line   
  36.                 // to avoid too many empty lines   
  37.                 if  (sLastLIne.equals(sReadLine))  
  38.                 {  
  39.                     continue ;  
  40.                 }  
  41.   
  42.                 // handle the comments, empty line, ColumnSeq line   
  43.                 if  (sReadLine.startsWith( "#" ) ||  "" .equals(sReadLine)  
  44.                         || sReadLine.startsWith("ColumnSeq" ))  
  45.                 {  
  46.                     // cache in the buffer   
  47.                     sbFinalContent.append(sReadLine).append(  
  48.                             System.getProperty("line.separator" ));  
  49.                     continue ;  
  50.                 }  
  51.   
  52.                 // handle changing record   
  53.                 sColumnValues = sReadLine.split("\\$_\\$" );  
  54.                 if  (sPrimaryKeyValue.trim().equals(sColumnValues[ 0 ].trim()))  
  55.                 {  
  56.                     // cache in the buffer   
  57.                     sbFinalContent.append(sRowData).append(  
  58.                             System.getProperty("line.separator" ));  
  59.                     continue ;  
  60.                 }  
  61.   
  62.                 // cache normal record in the buffer   
  63.                 sbFinalContent.append(sReadLine).append(  
  64.                         System.getProperty("line.separator" ));  
  65.   
  66.                 // set last line   
  67.                 sLastLIne = sReadLine;  
  68.             }  
  69.   
  70.             // get writer   
  71.             oPWriter = fileProcess.getBufferedFilePrintWriter(sFullFileName);  
  72.   
  73.             // write the final content to file   
  74.             oPWriter.write(sbFinalContent.toString());  
  75.             oPWriter.flush();  
  76.   
  77.             // set result   
  78.             bRet = true ;  
  79.         }  
  80.         catch  (IOException e)  
  81.         {  
  82.             // print e, and throw it, so the method which invoked it can process   
  83.             // it freely.   
  84.             e.printStackTrace();  
  85.             throw  e;  
  86.         }  
  87.         finally   
  88.         {  
  89.             if  ( null  != oBRead)  
  90.             {  
  91.                 oBRead.close();  
  92.             }  
  93.             // close the writer   
  94.             if  ( null  != oPWriter)  
  95.             {  
  96.                 oPWriter.close();  
  97.             }  
  98.         }  
  99.         return  bRet;  
  100.     }  

7. 通过上面的更新方法,就可以实现记录的更新功能了.

同样的对与更新方法没有实现根据列值判断来更新相关的记录, 只是实现了根据主键更新整列数据局, 可以根据需要重写/扩展该方法

a.首先根据Table Bean后去带路径的玩这个路径名

b.在将Table Bean转换成一个合格的数据记录字符串

c.调用上面的方法,根据主键将目标记录替换

同样的, 为了使所有的表Bean都可以通过这一个方更新数据,将方法定义成了泛型方法. 

 

[java] view plain copy
  1. /**  
  2.      * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.      * Description: update one record from text DB  
  4.      * @param oT: the object of bean   
  5.      * @param sPrimaryKeyValue: the value of the primary key  
  6.      * @return oResult:   
  7.      *          ResultBean.result: true - insert success; false - insert failed  
  8.      *          ResultBean.description: the description of the result;  
  9.      * @throws InvocationTargetException   
  10.      * @throws IllegalAccessException   
  11.      * @throws NoSuchMethodException   
  12.      * @throws IOException   
  13.      * @throws IllegalArgumentException   
  14.      * @throws SecurityException   
  15.      */   
  16.     public  <T> ResultBean update(T oT, String sPrimaryKeyValue)  
  17.             throws  SecurityException, IllegalArgumentException, IOException,  
  18.             NoSuchMethodException, IllegalAccessException,  
  19.             InvocationTargetException  
  20.     {  
  21.         ResultBean oResult = new  ResultBean();  
  22.   
  23.         boolean  bRet =  false ;  
  24.         String sDescription = "" ;  
  25.   
  26.         // get full text DB file name with full path   
  27.         String sFullFileName = this .getFullTableFileName(oT);  
  28.   
  29.         // get sRowdata   
  30.         String sRowData = this .convertBeantoStr(oT, sFullFileName);  
  31.   
  32.         // delete from file   
  33.         bRet = this .updateRecordToFile(sRowData, sPrimaryKeyValue,  
  34.                 sFullFileName);  
  35.   
  36.         // set result description   
  37.         if  (bRet)  
  38.         {  
  39.             sDescription = "The updated record is \""  + sRowData +  "\". "   
  40.                     + " It is update to \""  + sFullFileName  
  41.                     + "\" successfully." ;  
  42.         }  
  43.         else   
  44.         {  
  45.             sDescription = "The updating record \""  + sRowData  
  46.                     + "\" is not there in the file"  +  " \""  + sFullFileName  
  47.                     + "\"." ;  
  48.         }  
  49.         // set final result.   
  50.         oResult.setDescription(sDescription);  
  51.         oResult.setResult(bRet);  
  52.         return  oResult;  
  53.     }  
8. 了解下如何根据列名获取Table Bean的get 方法

由于列名和Bean的Field名字是一样的,根据这儿特性,可以拼接出来对应的set方法的方法名. 详细步骤可以参考注释

同样的, 为了使所有的表Bean都可以通过这一个方法获取set方法,将方法定义成了泛型方法. 

 

[java] view plain copy
  1. /**  
  2.      * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.      * Description: Get all set method names.  
  4.      * assume that all the field names of bean class of table are the same as the column names  
  5.      * @param oT: the object of bean   
  6.      * @param sColumns: the columns  
  7.      * @return HashMap <String,String>   
  8.      *           - key: column name;    
  9.      *           - value: the corresponding set method name  
  10.      */   
  11.     private  <T> HashMap<String, String> getSetMethods(String[] sColumns, T oT)  
  12.     {  
  13.         HashMap<String, String> oHM = new  HashMap<String, String>();  
  14.         String sMethodName = "" ;  
  15.         String sFieldName = "" ;  
  16.         for  ( int  i =  0 ; i < sColumns.length; i++)  
  17.         {  
  18.             // initialize the method name   
  19.             sMethodName = "set" ;  
  20.   
  21.             // get the get method name of the current column   
  22.             sFieldName = sColumns[i].trim();  
  23.             if  (sFieldName.length() >  1 )  
  24.             {  
  25.                 sMethodName = sMethodName  
  26.                         + sFieldName.substring(0 1 ).toUpperCase()  
  27.                         + sFieldName.substring(1 );  
  28.             }  
  29.             else   
  30.             {  
  31.                 sMethodName = sMethodName + sFieldName.toUpperCase();  
  32.             }  
  33.             oHM.put(sColumns[i], sMethodName);  
  34.         }  
  35.         return  oHM;  
  36.     }  

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 plain copy
  1. /**  
  2.      * Author: Jiangtao He; Email: ross.jiangtao.he@gmail.com  
  3.      * Description: query all the records from text DB  
  4.      * @param oT: the object of bean   
  5.      * @param sPrimaryKeyValue: the value of the primary key  
  6.      * @return oTList: the object list of the bean  
  7.      * @throws InvocationTargetException   
  8.      * @throws IllegalAccessException   
  9.      * @throws IllegalArgumentException   
  10.      * @throws NoSuchMethodException   
  11.      * @throws SecurityException   
  12.      * @throws InstantiationException   
  13.      * @throws IOException   
  14.      */   
  15.     public  <T> List<T> queryAll(T oT)  throws  IllegalArgumentException,  
  16.             IllegalAccessException, InvocationTargetException,  
  17.             SecurityException, NoSuchMethodException, InstantiationException, IOException  
  18.     {  
  19.         List<T> oTList = new  ArrayList<T>();  
  20.   
  21.         // get full text DB file name with full path   
  22.         String sFullFileName = this .getFullTableFileName(oT);  
  23.   
  24.         BufferedReader oBRead = null ;  
  25.         try   
  26.         {  
  27.             oBRead = fileProcess.getBufferedFileReader(sFullFileName);  
  28.             String sReadLine;  
  29.             String[] sColumns = null ;  
  30.             HashMap<String, String> oHM = null ;  
  31.             String[] sColumnValues = null ;  
  32.             int  iNumOfColumns;  
  33.             Method oMethod;  
  34.             while  ( null  != (sReadLine = oBRead.readLine()))  
  35.             {  
  36.                 sReadLine = sReadLine.trim();  
  37.   
  38.                 // skip comments, empty line   
  39.                 if  (sReadLine.startsWith( "#" ) ||  "" .equals(sReadLine))  
  40.                 {  
  41.                     continue ;  
  42.                 }  
  43.   
  44.                 // get set method names of the bean   
  45.                 if  (sReadLine.startsWith( "ColumnSeq" ))  
  46.                 {  
  47.                     sColumns = sReadLine.split(":" )[ 1 ].split( "\\$_\\$" );  
  48.                     oHM = this .getSetMethods(sColumns, oT);  
  49.                     continue ;  
  50.                 }  
  51.   
  52.                 // get values of the a record   
  53.                 sColumnValues = sReadLine.split("\\$_\\$" );  
  54.   
  55.                 // check the number of values is less than columns or not, the   
  56.                 // smaller one will be used in the loop to avoid out of array   
  57.                 // index exception   
  58.                 iNumOfColumns = sColumnValues.length > sColumns.length ? sColumns.length  
  59.                         : sColumnValues.length;  
  60.                 for  ( int  i =  0 ; i < iNumOfColumns; i++)  
  61.                 {  
  62.                     // get the get method   
  63.                     oMethod = oT.getClass().getMethod(oHM.get(sColumns[i]),String.class );  
  64.                     // execute the method to set the value into bean   
  65.                     oMethod.invoke(oT, sColumnValues[i]);  
  66.                 }  
  67.                 //add the bean into the bean list   
  68.                 oTList.add(oT);  
  69.                 //assign a new instance to the bean   
  70.                 oT = (T) oT.getClass().newInstance();  
  71.             }  
  72.         }  
  73.         catch  (IOException e)  
  74.         {  
  75.             // print e, and throw it, so the method which invoked it can process   
  76.             // it freely.   
  77.             e.printStackTrace();  
  78.             throw  e;  
  79.         }  
  80.         finally   
  81.         {  
  82.             if  ( null  != oBRead)  
  83.             {  
  84.                 oBRead.close();  
  85.             }  
  86.         }  
  87.         return  oTList;  
  88.     }  


 至此增删改查功能的思路算是实现了.


我们使用junit做下测试看下效果--我在4个测试方法上都打了断点, 分别看下实际效果(由于junit代码较长,我就不贴了,感兴趣的可以下载下来看):

增加一条记录到home和member表:

控制台:

 

[java] view plain copy
  1. 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.  
  2. 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 plain copy
  1. #Column Sequence  
  2. ColumnSeq: id$_$name$_$phone$_$email$_$address  
  3.   
  4. #Content Start  
  5. Ross_1$_$Ross's Home$_$252363693 $_$ross.jiangtao.he @gmail .com$_$China P.R.  
T_FamilyMember.db:

 

[java] view plain copy
  1. #Column Sequence  
  2. ColumnSeq: id$_$name$_$gender$_$mobile$_$email$_$address$_$family_id  
  3.   
  4. #content start  
  5. Yan$_$Pery$_$Female$_$252363693 $_$ross.jiangtao.he @gmail .com$_$ null $_$Ross_1  

查询home和member表的记录:
控制台:

 

[java] view plain copy
  1. Query all the home record(s) from file, totally get :  1  record(s)  
  2. Query all the family member record(s) from file, totally get : 1  record(s)  

更新home和member表的记录(可以看多了"O(∩_∩)O~~"的列) 控制台:

 

[java] view plain copy
  1. 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.  
  2. 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.  
T_Home.db:

 

[java] view plain copy
  1. #Column Sequence  
  2. ColumnSeq: id$_$name$_$phone$_$email$_$address  
  3. #Content Start  
  4. Ross_1$_$Pery's Home O(∩_∩)O~~$_$252363693 $_$ross.jiangtao.he @gmail .com$_$China P.R.  

T_FamilyMember.db:

[java] view plain copy
  1. <pre name= "code"   class = "java" >#Column Sequence  
  2. ColumnSeq: id$_$name$_$gender$_$mobile$_$email$_$address$_$family_id  
  3. #content start  
  4. Yan$_$Pery$_$Female$_$10086  O(∩_∩)O~~$_$ross.jiangtao.he @gmail .com$_$ null $_$Ross_1  

删除home和member表的一条记录 控制台:
[java] view plain copy
  1. 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.  
  2. 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_Home.db:
[java] view plain copy
  1. #Column Sequence  
  2. ColumnSeq: id$_$name$_$phone$_$email$_$address  
  3. #Content Start  
T_FamilyMember.db:

 

[java] view plain copy
  1. #Column Sequence  
  2. ColumnSeq: id$_$name$_$gender$_$mobile$_$email$_$address$_$family_id  
  3. #content start  


 至此" 文本数据库简单的实现思路 "已经完成了.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics