`

文本数据库的简单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  


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

分享到:
评论

相关推荐

    文本数据库数据库操纵JAVA实现版本

    - 使用Java设计并实现了一个简单的文本数据库系统。 - 数据的存储和检索通过Hashtable或类似数据结构(如TreeMap)实现,以键值对形式存储数据。 - 应用程序支持多线程环境,可能采用了线程安全的数据结构或同步机制...

    java纯文本数据库

    一个Java纯文本数据库模型系统,正在开发中,有兴趣的话希望大家能帮助小弟改进。

    java把文本文件内容导入到数据库

    在这个场景下,"java把文本文件内容导入到数据库"是一个典型的应用,它涉及到文本解析、数据库连接以及数据持久化等关键知识点。 首先,我们需要理解文本文件的格式。描述中提到文件内容的字段由“,”分隔,这种...

    java实现读取word文件并且上传到数据库

    本项目关注的是如何使用Java来实现读取Microsoft Word文件,并将其中的数据上传到数据库,以此提升数据录入的效率。这一过程涉及到多个技术点,包括文件I/O、Word文档解析、数据库操作以及可能的数据转换。 首先,...

    自动备份数据库java源码

    标题中的“自动备份数据库java源码”指的是使用Java编程语言编写的一种程序,它的主要功能是自动化执行数据库的备份任务。数据库备份是数据保护的重要环节,它可以在数据丢失或系统故障时恢复数据,确保业务连续性。...

    java实现文本数据读取到数据库表

    将本地硬盘中的文本数据读取到mysql的数据库表中。 1. 文件保存在本地目录下,按照固定的格式保存,每一行对应着数据库中的一条记录,属性用空格隔开。 2. 创建数据库表,字段需要和文本文件的数据逐列对应。 3. ...

    随机出题系统的java实现,使用java GUI和MySql数据库!

    内容概要:通过程序注释带着读者了解GUI界面构建过程,初步了解 java GUI的使用,理解GUI框架中的核心逻辑,简化代码实现过程,保留核心功能,例如:登陆确认、随机出题、题目文本导入等内容实现。 适合人群:具备...

    java 读取txt数据并保存到数据库中源代码

    java 读取txt文本文件中的数据并保存到数据库中源代码,假设txt已有格式,并以","分隔。其中的sql包需要自己去微软官网下载。

    国产达梦数据库对应java-jdbc相关jar包

    标题中的“国产达梦数据库对应java-jdbc相关jar包”表明了这个压缩包包含的是用于连接达梦数据库的Java JDBC驱动程序。Java JDBC(Java Database Connectivity)是Java平台上的一个标准API,允许Java应用程序与各种...

    java学生管理系统(没用数据库)

    【Java学生管理系统】是一个基于文本文件的简单应用,它不依赖任何数据库系统,而是通过读写TXT文件来存储和检索学生信息。这个管理系统的核心概念主要围绕着Java编程语言的文件操作、数据序列化和简单的数据结构。 ...

    java 富文本编辑器demo

    本文将深入探讨如何在Java环境中实现一个富文本编辑器的Demo,并讲解如何将编辑的数据存储到数据库以及在JSP中进行配置的修改。 首先,富文本编辑器的实现通常依赖于JavaScript库,如TinyMCE、CKEditor或Quill。...

    JAVA读取CSV到数据库表中

    本人以JAVA来实现以支付宝的账单表为例,实现JAVA读取CSV..csv是一种文件格式(如.txt、.doc等),也可理解.csv文件就是一种特殊格式的纯文本文件。即是一组字符序列,字符之间已英文字符的逗号或制表符(Tab)分隔。

    java 程序打包成jar文件后 连接数据库出错(教程方法)

    至于`文档.txt`,这可能是包含打包或数据库连接相关说明的文本文件。确保在发布程序时一并提供,以便用户参考。 总之,打包Java程序至JAR文件并连接MySQL数据库,需要正确管理依赖,选择合适的打包工具,如Eclipse...

    SERVLET技术实现数据库查询

    在本项目中,"SERVLET技术实现数据库查询",意味着我们将探讨如何利用Servlet来与数据库进行交互,特别是MySQL数据库。SpringMVC是一个基于Spring框架的轻量级Web MVC框架,它简化了在Servlet中处理请求和响应的过程...

    源代码:读写文本,把文本当数据库使用

    本主题探讨的是如何利用编程语言来读写文本文件,将其作为一种简易的数据库使用。这种方式虽然没有传统数据库那样复杂的功能,但在某些场景下却足够高效且易于实现。 首先,我们了解基本的文本文件操作。在大多数...

    java编写的数据库自动备份源码

    Java编写的数据库自动备份源码是一种实用的工具,它能够帮助数据库管理员定期、高效地创建数据库的备份,确保数据的安全性。在IT行业中,数据库管理是至关重要的,因为任何数据丢失都可能导致重大的业务损失。数据库...

    java数据库设计持久化操作实现

    此外,BufferedReader和PrintWriter类可以用于读写文本文件,如SQL脚本,这些脚本可能包含创建数据库表结构或插入初始数据的命令。 XML(Extensible Markup Language)则常用于存储和传输结构化数据。在Java中,...

    html与java交互实现数据库连接和发送消息 Chat

    HTML(超文本标记语言)和Java是两种不同的技术,但它们在Web开发中常常结合使用,以实现丰富的交互性。本项目"html与java交互实现数据库连接和发送消息 Chat"显然是一个基于Web的聊天应用程序,它利用HTML作为前端...

    csv导入数据库 java源代码

    这种格式简单易读,可以用任何文本编辑器打开,并且可以方便地导入到各种数据库系统中。Java作为一种流行的编程语言,提供了处理CSV文件并将其导入数据库的强大能力。 在标题“csv导入数据库 java源代码”中,我们...

Global site tag (gtag.js) - Google Analytics