Handwritten txt simulation database simple framework

1. Foreword

Previously, the school asked us to write the console Ele.me project. At that time, the progress did not reach the database, so we used text files txt to simulate the implementation of the database. In fact, it is essentially a file reading and writing, but simple file reading and writing cannot cover what we want. functions, such as conditional query, paging query, etc., so out of curiosity, I hand-written a simple txt text database framework

Second .txt file preparation

Let’s first prepare a few txt text files and take a look at their format.

1.shops.txt merchant list

Id Merchant name Merchant rating Merchant address Merchant profile Merchant phone number
1001 Lijia Baozi 5 No. 102, Makino District Very delicious 123212312
1002 Yang Mingyu Braised Chicken and Rice 4 Opposite Henan Normal University So delicious 21312311
1003 Wang Xingyao Braised Chicken and Rice 4 Opposite Henan Normal University So delicious 21312311
1004 Zhaojia Porridge Shop 4 Opposite Henan Normal University It’s so delicious 21312311
1005 Mixue Bingcheng 4 Opposite Henan Normal University It’s so delicious 21312311
1006 Taiwanese Braised Pork Rice 4 Opposite Henan Normal University It’s so delicious 21312311
1007 Ground Pot Chicken 4 Opposite Henan Normal University It’s so delicious 21312311
1008 Delicious Snacks 4 Opposite Henan Normal University So delicious 21312311
1009 Lanzhou Beef Ramen 4 Opposite Henan Normal University So delicious 21312311
1010 KFC 4 Opposite Henan Normal University It’s so delicious 21312311
1011 Dicos 4 Opposite Henan Normal University It’s so delicious 21312311
1012 McDonald's 4 Opposite Henan Normal University It's so delicious 21312311
1013 Yang Mingyu Braised Chicken and Rice 4 Opposite Henan Normal University It’s so delicious 21312311
1014 Yang Mingyu Braised Chicken and Rice 4 Opposite Henan Normal University So delicious 21312311
1015 Yang Mingyu Braised Chicken and Rice 4 Opposite Henan Normal University So delicious 21312311
1016 Yang Mingyu Braised Chicken and Rice 4 Opposite Henan Normal University It’s so delicious 21312311

2.dishes.txt menu list

dID shopID Dishes name Introduction Sales volume Number of copies Price
101 1002 Cai Xukun Not delicious 11 10 12.3
102 1001 Steamed Bun None 312 12 12.5
103 1001 Big buns None 312 31 12.50
104 1001 Small buns None 312 31 12.50
105 1001 Medium buns None 312 31 12.50
106 1001 Meat buns None 312 31 12.50
107 1001 Meat buns None 312 31 12.50
108 1001 Meat buns None 312 31 12.50
109 1001 Meat buns None 312 31 12.50
110 1001 Meat Bun None 312 31 12.50
111 1001 Meat buns None 312 31 12.50
112 1002 Cai Xukun Not delicious 112 10 12.3 

3.users.txt user table

ID Username Password Age Phone Address
1001 jjh123 123456 22 1241241234 Left hand door, 12th floor, Building 3, Tiantang Community
1002 jfsf 123456 12 1241241234 Left-hand tenant on the 12th floor, Building 3, Junk Community
681373 zhangsan 123456 123 3123134 Left hand door on the 12th floor of Building 3 of the regional community
899803 lisi 12345 18 13123123111 Opposite Henan Normal University, Muye District, Xinxiang City, Henan Province
663714 lisi123 12345 20 13212331231 Opposite Henan Normal University 

4.orders.txt order form

ID shopId dishId userId name count singlePrice allPrice address desc time
001 1001 102 1001 Baozi 2 12.50 25.00 Left-hand door on the 12th floor of Building 3, Tiantang Community. Try to hurry up 2023-10-06T14:43:42.982695700
622975 1001 102 0 Baozi 1 12.5 12.5 Left door on the 12th floor of Building 3 in Tiantang Community Add more sugar 2023-10-06T14:43:42.982695700
708911 1001 102 0 Baozi 1 12.5 12.5 0 None 2023-10-06T19:45:08.918948500
955207 1001 102 0 Baozi 2 12.5 25.0 Left door on the 12th floor of Building 3, Tiantang Community None 2023-10-25T17:59:15.207836800
570959 1001 102 0 Baozi 10 12.5 125.0 Left-hand door on the 12th floor of Building 3, Tiantang Community. Deliver it quickly 2023-10-25T18:26:10.996829600
543529 1001 102 0 Steamed buns 2 12.5 25.0 Opposite Henan Normal University, Muye District, Xinxiang City, Henan Province More spicy 2023-10-29T11:35:43.542230100
711960 1001 102 0 Steamed buns 2 12.5 25.0 Opposite Henan Normal University, put more pepper 2023-10-29T11:55:11.967471800 

We make its format look as similar as possible to that in MySQL, and then we implement these query functions

3. Conditional constructor

We know that there is a condition constructor in mybatisplus, querywrapper. You can construct various conditions and then query

Let’s imitate this conditional constructor and implement our own constructor

(1)QueryBody

public class QueryBody {

    private String key;

    private String value;

    public QueryBody() {
    }

    public QueryBody(String key, String value) {
        this.key = key;
        this.value = value;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "QueryBody{" +
                "key='" + key + '\'' +
                ", value='" + value + '\'' +
                '}';
    }
}

In fact, it is a key and the corresponding value, and then we build the conditions

(2)QueryWrapper

/**
 * Query conditions
 */
public class QueryWrapper {

    /**
     * Parameter set
     */
    private List<QueryBody> queryArgs = new ArrayList<>();

    public QueryWrapper(){}

    /**
     *Equal conditions
     */
    public QueryWrapper eq(String key,String arg){
        QueryBody queryBody = new QueryBody(key,arg);
        queryArgs.add(queryBody);
        return this;
    }

    public List<QueryBody> getQueryArgs() {
        return queryArgs;
    }

For the sake of simplicity here, I only implemented the equivalent condition query eq(),

Note: What we return is this, the object itself, so that chain programming can be realized

4. Pagination result class PageBody

/**
 * Encapsulation of paging
 */
public class PageBody {
    /**
     *Total number of items
     */
    private int total;
    /**
     *Current page number
     */
    private int currntPage;
    /**
     * Current size of each page
     */
    private int size;
    /**
     * total pages
     */
    private int pageSize;
    /**
     * Result set
     */
    private List<Object> results;

    public PageBody() {
    }

    public PageBody(int total, int currntPage, int size, int pageSize, List<Object> results) {
        this.total = total;
        this.currntPage = currntPage;
        this.size = size;
        this.pageSize = pageSize;
        this.results = results;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
        //Set the total number of pages
        if(size!=0){
            this.pageSize = total / size + 1;
        }

    }

    public int getCurrntPage() {
        return currntPage;
    }

    public void setCurrntPage(int currntPage) {
        this.currntPage = currntPage;
    }

    public int getSize() {
        return size;
    }

    public void setSize(int size) {
        this.size = size;
    }

    public int getPageSize() {
        return pageSize;
    }

// public void setPageSize(int pageSize) {
// this.pageSize = pageSize;
// }

    public List<Object> getResults() {
        return results;
    }

    public void setResults(List<Object> results) {
        this.results = results;
    }

    @Override
    public String toString() {
        return "PageBody{" +
                "total=" + total +
                ", currntPage=" + currntPage +
                ", size=" + size +
                ", pageSize=" + pageSize +
                ", results=" + results +
                '}';
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;

    }
}

Roughly similar to the page object of mybatispllus

5.FileUtils tool class

The framework is actually a tool class that implements a large number of methods

/**
 *File tool class
 * @author JJH
 */
public class FileUtils {

  ...
}

We intercept each method and analyze it one by one.

Utility method that returns the attribute get method

 private static String getXxx(String name){

     return "get" + name.substring(0,1).toUpperCase()
               + name.substring(1);

  }

1. Return the file content as a collection according to the file path

 /**
     * Return file contents as a collection based on file path
     * @param path file path
     * @param clazz The type of object to be returned
     * @return object collection
     */
 public static List<Object> fileToList(String path, Class<?> clazz) {

      List<Object> list = new ArrayList<>();

      BufferedReader br = null;
      try {
          br = new BufferedReader(new FileReader(path));
          //Read the first row of data (header)
          br.readLine();
          String row;
          while ((row=br.readLine()) != null) {
              //Create the object first
              Object obj = clazz.newInstance();
              //Get each element
              String[] s = row.split(" ");
              //Get attribute collection
              Field[] fields = clazz.getDeclaredFields();
              for (int i=0;i<fields.length;i + + ) {
                  //Get the type of attribute
                  Class<?> type = fields[i].getType();
                  String name = fields[i].getName();
                String setXxx="set" + name.substring(0,1).toUpperCase() + name.substring(1);
                 //Get set method
                  Method setMethod = clazz.getDeclaredMethod(setXxx,type);
                  //Convert the parameter type
                  String s1 = s[i];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //Call the set method to assign a value to the property
                  setMethod.invoke(obj,arg);
              }
               //Load into the collection
              list.add(obj);
          }
          return list;
      } catch (IOException | InvocationTargetException | NoSuchMethodException | InstantiationException |
               IllegalAccessException e) {
          throw new RuntimeException(e);
      } finally {
          try {
              assert br != null;
              br.close();
          } catch (IOException e) {
              throw new RuntimeException(e);
          }
      }


  }

Mainly using reflection, passing in the path of the file and the type of object in the collection to be returned, so that the properties can be obtained based on reflection and then assigned to the properties.

2. Save the collection to a file

 /**
     * Save the collection to a file
     * @param list combinations to be saved
     * @param path file path
     * @param clazz object type
     * @return Whether the save was successful
     * @param
     */
 public static boolean ListToFile(List<Object> list, String path, Class<?> clazz){

      BufferedWriter bw = null;
      try {
          //The second parameter is to allow additional writing
         bw = new BufferedWriter(new FileWriter(path,true));

          StringBuilder sb = new StringBuilder();
          for (Object obj : list) {

              //Get the properties of the object first
              Field[] fields = clazz.getDeclaredFields();
              for (Field field : fields) {
                 //Convert the first letter to uppercase
                  String name = field.getName();
                  String getXxx = "get" + name.substring(0, 1).toUpperCase()
                           + name.substring(1);
                 //Call the get method to get the attribute value
                  Method getMethod = clazz.getDeclaredMethod(getXxx);
                  String str = getMethod.invoke(obj).toString();
                  sb.append(str).append(" ");
              }
                sb.append("\\
");
          }
             bw.write(sb.toString());

      } catch (Exception e) {
          throw new RuntimeException(e);
      } finally {
          try {
              assert bw != null;
              bw.close();
          } catch (IOException e) {
              throw new RuntimeException(e);
          }
      }


      return true;
  }

3. Return the number of lines in the file

 /**
     * Return the number of lines in the file
     * @param path file path
     * @return number of rows
     * @throwsIOException
     */
  public static int getFileRow(String path) throws IOException {
     BufferedReader br = new BufferedReader(new FileReader(path));
     int sum =0;
     while (true){
         String str = br.readLine();
         if(str!=null){
             sum + + ;
         }else {
             break;
         }
     }
     return sum-1; //The first line does not count
  }

4. Simulate paging query

 /**
     * Simulate paging query
     * @param page page number
     * @param size size
     * @param path file path
     * @param clazz returns the type of objects in the collection
     * @return object collection
     */
  public static List<Object> pageList(int page,int size,String path, Class<?> clazz) {

      /*
          Calculate the starting position, the first line is not counted, so it starts from the second line
          2-11 is the first page.
          12-22 is the second page
          23-33 is the third page
          start = 2 + (page-1)*size
          When our last page is not full, if we want to use the remaining part of this page
          If you find out, direct query will report an error. We need to determine how many pages are left on the last page.
          Margin, let our last loop count be equal to this margin, don't let it go out of bounds
       */

      List<Object> list = new ArrayList<>();
      try {
          //Get the total number of items first, not counting the first row
          int total = getFileRow(path) - 1;
          //Calculate how much is left on the last page (find the remainder)
          int leastSize = total % size;

          BufferedReader br = new BufferedReader(new FileReader(path));
          //Let it read start first
          int start = 2 + (page - 1) * size;
          for (int i = 1; i < start; i + + ) {
              br.readLine();
          }
          //Judge the number of loops to see if it is full or the last page is remaining.
          int num = total - (page-1) * size;
          int loop; //Number of loops
          if(leastSize==0||num>=10){
              loop = size;
          }else {
              loop = leastSize-1;
          }
          //Then let it read size times, the default is 10
          for (int i = 0; i < loop; i + + ) {
              String row = br.readLine();
              //Create the object first
              Object obj = clazz.newInstance();
              //Get each element
              String[] s = row.split(" ");
              //Get attribute collection
              Field[] fields = clazz.getDeclaredFields();
              for (int j = 0; j < fields.length; j + + ) {
                  //Get the type of attribute
                  Class<?> type = fields[j].getType();
                  String name = fields[j].getName();
                  String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                  //Get set method
                  Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                  //Convert the parameter type
                  String s1 = s[j];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //Call the set method to assign a value to the property
                  setMethod.invoke(obj, arg);
              }
              //Load into the collection
              list.add(obj);
          }
      }catch (Exception e){
          e.printStackTrace();
      }
      return list;
  }

5. Paging query based on equal conditions

 /**
     * Paging query based on equal conditions
     * @param page page number
     * @param size size
     * @param path file path
     * @param clazz collection object type
     * @param wrapper conditional constructor
     * @return object collection
     */
  public static List<Object> pageQueryList(int page, int size, String path, Class<?> clazz, QueryWrapper wrapper){
         //Take out the conditions in the conditional constructor
      List<QueryBody> querybodys = wrapper.getQueryArgs();


      List<Object> list = new ArrayList<>();
      List<Object> resList = new ArrayList<>();
      try {
          BufferedReader br = new BufferedReader(new FileReader(path));
          br.readLine(); // Read the first line first

          int rows = getFileRow(path);
          for(int i=0;i<rows-1;i + + ){
              String str = br.readLine();
              //Create the object first
              Object obj = clazz.newInstance();
              //Get each element
              String[] s = str.split(" ");
              //Get attribute collection
              Field[] fields = clazz.getDeclaredFields();
              for (int j = 0; j < fields.length; j + + ) {
                  //Get the type of attribute
                  Class<?> type = fields[j].getType();
                  String name = fields[j].getName();
                  String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                  //Get set method
                  Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                  //Convert the parameter type
                  String s1 = s[j];
                  Object arg = TypeUtils.getInstanceByType(s1, type);
                  //Call the set method to assign a value to the property
                  setMethod.invoke(obj, arg);
              }
              //Load into the collection
              list.add(obj);
          }
      }catch (Exception e){
          e.printStackTrace();
      }
        // list.forEach(System.out::println);
      //The above is to get all the elements. Now let’s filter the elements first.
      try {
          for (QueryBody querybody : querybodys) {
              //Filter for each condition
              String key = querybody.getKey();
              String value = querybody.getValue();
              //Clear first every time
              resList.removeAll(resList);
              for (Object obj:list) {
                      String getXxx = getXxx(key);
                      //Call the get method to get the attribute value
                      Method getMethod = clazz.getDeclaredMethod(getXxx);
                      String res = getMethod.invoke(obj).toString();
                      //Check whether the comparison conditions are equal
                  if(res.equals(value)){
                      resList.add(obj);
                  }
              }

          }
      } catch (Exception e) {
          throw new RuntimeException(e);
      }
    // resList.forEach(System.out::println);
     // If page and size are not passed, all will be searched by default.
      if(Objects.isNull(page) & amp; & Objects.isNull(size)){
          return resList;
      }
      ArrayList<Object> pageList = new ArrayList<>();
      //Paging query
      /**
       * 0-9 first page
       * 10-19 Page 2
       * 20-21 Page 3
       * You still have to judge the remaining questions on the last page first
       *
       */
      int start = (page-1)*size;
      for(int i = 0;i<resList.size();i + + ){
              if(i==start){


                  if(resList.size()<=size){
                      size = resList.size();
                  }else {
                      //More than one page, calculate the margin
                      int mod = resList.size()%size;
                      if(mod>0){
                          //Calculate the current page
                          int currentPage = start/size + 1;
                          //Calculate whether the total amount of data before
                          if(mod + (currentPage*size-1) < currentPage*size){
                              size = mod;
                          }
                      }
                  }

                  for(int j = start; j < (start + size); j + + ){
                      pageList.add(resList.get(j));
                      //pageList.forEach(System.out::println);
                  }
                  break;
              }
      }
     // pageList.forEach(System.out::println);
      return pageList;
  }

6. Default full search form of paging query, method overloading

/**
     * The default full search form of paging query, method overloading
     * @param path file path
     * @param clazz object type
     * @param wrapper conditional constructor
     * @return object collection
     */
    public static List<Object> pageQueryList(String path, Class<?> clazz, QueryWrapper wrapper){
        //Take out the conditions in the conditional constructor
        List<QueryBody> querybodys = wrapper.getQueryArgs();

        List<Object> list = new ArrayList<>();
        List<Object> resList = new ArrayList<>();
        try {
            BufferedReader br = new BufferedReader(new FileReader(path));
            br.readLine(); // Read the first line first

            String row;
            while ((row=br.readLine())!=null){
                //Create the object first
                Object obj = clazz.newInstance();
                //Get each element
                String[] s = row.split(" ");
                //Get attribute collection
                Field[] fields = clazz.getDeclaredFields();
                for (int j = 0; j < fields.length; j + + ) {
                    //Get the type of attribute
                    Class<?> type = fields[j].getType();
                    String name = fields[j].getName();
                    String setXxx = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
                    //Get set method
                    Method setMethod = clazz.getDeclaredMethod(setXxx, type);
                    //Convert the parameter type
                    String s1 = s[j];
                    Object arg = TypeUtils.getInstanceByType(s1, type);
                    //Call the set method to assign a value to the property
                    setMethod.invoke(obj, arg);
                }
                //Load into the collection
                list.add(obj);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        //The above is to get all the elements. Let's filter the elements first.
        try {
            for (QueryBody querybody : querybodys) {
                //Filter for each condition
                String key = querybody.getKey();
                String value = querybody.getValue();
               // System.out.println(key + ":" + value);
                //Clear first every time
                resList.removeAll(resList);
                for (Object obj:list) {
                    String getXxx = getXxx(key);
                    //Call the get method to get the attribute value
                    Method getMethod = clazz.getDeclaredMethod(getXxx);
                    Object res = getMethod.invoke(obj);
                    //Check whether the comparison conditions are equal
                    if(res.toString().equals(value)){
                        resList.add(obj);
                    }
                }

            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return resList;
    }

7. Modify row data based on primary key

 /**
     * Modify and change row data based on primary key
     * @param
     * @param
     */
    public static boolean updateOne(String path, Object obj) {

        Class<?> aClass = obj.getClass();
        StringBuilder updateRow = new StringBuilder();
        Method getMethod = null;
        String str = null;
        String id = null;

        Field[] fields = aClass.getDeclaredFields();
        for (int i = 0;i<fields.length;i + + ) {
            try {
                getMethod = aClass.getDeclaredMethod(getXxx(fields[i].getName()));
                str = getMethod.invoke(obj).toString();
                updateRow.append(str).append(" ");
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if(i==0){
                id = str;
            }
        }


        StringBuilder sb = new StringBuilder();
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get(path))));
            //Add the header first
            String head = reader.readLine();
            sb.append(head).append("\r\\
");

            int rows = getFileRow(path);

            for (int i = 0; i <rows ; i + + ) {
                String row = reader.readLine();
                String Id = row.split(" ")[0];
                if(id.equals(Id)) {
                   sb.append(updateRow).append("\r\\
");
                }else {
                    sb.append(row).append("\r\\
");
                }
            }
            //Write the file back again
            BufferedWriter writer = new BufferedWriter(new FileWriter(path));

            writer.write(sb.toString());

           reader.close();
           writer.close();

        } catch (IOException e) {
            throw new RuntimeException(e);
        }


         return true;

    }

6. Test data

Let’s test the query effect

As you can see, all the default query methods at this time are:

As you can see, this is an equivalent condition query, and the dishes of the steamed bun shop are found.

To sum up, we have implemented our own simple framework of txt text database. Of course, there are still many imperfect functions. Next time, we hope to simulate SQL statements to implement queries, or simulate the implementation of transactions.

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Java skill treeUsing JDBC to operate the databaseDatabase operation 139165 people are learning the system