• Java学习不走弯路教程(3.从文件内容查询开始)


    一. 前言
    在前两章教程中,分别介绍了DOS环境搭建和Eclipse环境搭建。
    本章将带大家实现用简单SQL语句查询文件。
    注:
    1.本文针对初学Java的同学训练学习思路,请不要太纠结于细节问题。
    2.本文旨在达到抛砖引玉的效果,希望大家扩展本例子,以学到更多知识的精髓。

    二. 写给初学Java的同学
    在介绍本章内容之前,首先介绍一下Java的学习方法。
    相信大家在看本文的时候已经已经拿到了各种Java学习路径,大体都是一样。
    我想说的是,不要让知识的学习成为负担,Java技术种类繁多,是无论如何也学不完的。
    正确的学习方法是兴趣驱动,实例驱动。
    即通过一个简单的实例,不断加入所学知识进行扩展,最终扩展为一个大项目,达到系统学习,学以致用的效果。


    三. 步入正题
    话不多说,大家自己理解,下面步入正题:

    练习1.
    概要:本地有一个csv格式文件,用SQL语句查出结果。
    前提:本地有一个csv格式文件
      例:abc.csv放在c:/temp文件夹下,内容如下:

    id,username,password
    1,abc,aaa
    2,def,bbb
    3,xyz,ccc

    输入:文件路径和sql语句

      例:

    GetFile gf = new GetFile("c:/temp/");
    gf.queryFile("select * from abc.csv");

    输出:查询结果

      例:

    1,abc,aaa
    2,def,bbb
    3,xyz,ccc

    请先自己动手想办法实现,实在做不出来再往下看,否则失去了练习的意义。

    四. 实现步骤

    首先,我们需要解析SQL语句。是的,标准的写法是把SQL转化成语法树(AST),然后再解析这颗语法树。
    但这篇文章面对的是初学者,我的目的是训练字符串的拆分,拼接,文件读取等基本操作,以及分析问题的方法。
    所以,把问题简单化。


    首先确认程序功能的边界:
    下面是这个程序支持的最复杂的SQL语句(只支持单层的and条件):

    select id,username from abc.csv where username=abc and password=aaa

    所以,我们首先需要检查SQL的正确性:
    ・必须包含select,from
    ・可以包含where
    ・且循序必须为select,from,where
    代码如下:

        /**
         * @author http://www.java123.vip
         * @param sql
         * @return
         */
        private boolean checkSql(String sql) {
            int selectPos = sql.indexOf("select");
            int fromPos = sql.indexOf("from");
            int wherePos = sql.indexOf("where");
            
            if(selectPos != 0 
                    || fromPos <= selectPos
                    || (wherePos != -1 && wherePos <= fromPos)) {
                return false;
            }else {
                return true;
            }
        }

    然后,我们需要把上述语句的如下元素解析出来:

    查询项目:id,username
    查询文件:abc.csv
    查询条件:username=abc,password=aaa
    做一个类来存储解析结果:

    package vip.java123.fileview;
    
    /**
     * 
     * @author http://www.java123.vip
     *
     */
    public class SqlParseResult {
        public String[] fields;
        public String fileName;
        public String[] whereConditions;
        
        public void clearSpace() {
            for(int i = 0; i < fields.length; i ++) {
                fields[i] = fields[i].trim();
            }
            
            fileName = fileName.trim();
            
            for(int i = 0; i < whereConditions.length; i ++) {
                whereConditions[i] = whereConditions[i].trim();
            }
        }
    }

    解析的函数如下

        /**
         * @author http://www.java123.vip
         * @param sql
         * @return
         */
        private SqlParseResult parseSql(String sql) {
            int selectPos = sql.indexOf("select");
            int fromPos = sql.indexOf("from");
            int wherePos = sql.indexOf("where");
            
            String columnStr = sql.substring(selectPos + "select".length(), fromPos).trim();
            String fileNameStr;
            String whereStr;
            if(wherePos == -1) {
                fileNameStr = sql.substring(fromPos + "from".length());
                whereStr = "";
            }else {
                fileNameStr = sql.substring(fromPos + "from".length(),wherePos);
                whereStr = sql.substring(wherePos + "where".length());
            }
            
            
            SqlParseResult spr = new SqlParseResult();
            spr.fields = columnStr.split(",");
            spr.fileName = fileNameStr;
            if(wherePos == -1) {
                spr.whereConditions = new String[] {};
            }else {
                spr.whereConditions = whereStr.split("and");
            }
            
            spr.clearSpace();
            
            return spr;
        }
        

    (处理where后面的条件)接下来,对于读取的一行数据,我们需要检查该行数据是否符合查询条件,做个函数如下:
    header为第一行数据用逗号分割后的数组(文件头)

        /**
         * @author http://www.java123.vip
         * @param line
         * @param whereConditions
         * @param header
         * @return
         */
        private boolean checkRow(String line, String[] whereConditions, String[] header) {
            // username=abc  password=aaa
            String[] lineColumns = line.split(",");
            for(int i = 0; i < whereConditions.length; i ++) {
                String key = whereConditions[i].split("=")[0];
                String value = whereConditions[i].split("=")[1];
                
                String checkValue = lineColumns[getHeaderIndex(header,key)];
                if(!value.equals(checkValue)) {
                    return false;
                }
            }
            return true;
        }
        


    做个辅助函数,根据列名,返回列名的位置

        /**
         * @author http://www.java123.vip
         * @param header
         * @param headerName
         * @return
         */
        private int getHeaderIndex(String[] header,String headerName) {
            for(int i = 0; i < header.length; i ++) {
                if(header[i].equals(headerName)) {
                    return i;
                }
            }
            
            return -1;
        }
        

    (处理select后面的列名)如果数据符合查询条件,则根据select关键字后面的列名(fields)过滤查询结果

        /**
         * @author http://www.java123.vip
         * @param line
         * @param fields
         * @param header
         * @return
         */
        private String selectLine(String line, String[] fields, String[] header) {
            
            if(fields[0].equals("*")) {
                return line;
            }
            
            StringBuffer result = new StringBuffer();
            
            String[] lineColumns = line.split(",");
            for(int i = 0; i < fields.length; i ++) {
                int columnIndex = this.getHeaderIndex(header, fields[i]);
                result.append(lineColumns[columnIndex]);
                
                if(i != fields.length -1) {
                    result.append(",");
                }
            }
            return result.toString();
        }

    把上面的函数拼接在一起,主函数如下:

        /**
         * @author http://www.java123.vip
         * @param sql
         * @return
         * @throws Exception
         */
        public String queryFile(String sql) throws Exception{
            sql = sql.toLowerCase().trim();
            
            if(!checkSql(sql)) {
                return null;
            }
            SqlParseResult spr = parseSql(sql);
            
            File f = new File(basePath + spr.fileName);
            
            FileInputStream fis = new FileInputStream(f);
            InputStreamReader isr = new InputStreamReader(fis);
            BufferedReader br = new BufferedReader(isr);
            
            boolean readHeader = true;
            String[] header = null;
            
            StringBuffer result = new StringBuffer();
            String line = null;
            while((line = br.readLine()) != null) {
                if(readHeader) {
                    header = line.split(",");
                    readHeader = false;
                }else {
                    if(checkRow(line,spr.whereConditions,header)) {
                        
                        result.append(selectLine(line,spr.fields,header));
                        result.append("
    ");
                    }
                }
                
            }
            
            br.close();
            isr.close();
            fis.close();
            
            return result.toString();
        }

    最后,测试我们的程序:

        /**
         * @author http://www.java123.vip
         * @param args
         * @throws Exception
         */
        public static void main(String[] args) throws Exception {
            
            GetFile gf = new GetFile("c:/temp/");
            
            String sql1 = "select * from abc.csv ";
            String sql2 = "select id from abc.csv ";
            String sql3 = "select id,username from abc.csv where id=2 ";
            String sql4 = "select id,username from abc.csv where username=abc and password=aaa ";
            String sql5 = "select id,username from abc.csv where username=abc and password=bbb ";
            
            System.out.println("Execute:"+sql1);
            System.out.println(gf.queryFile(sql1));
            
            System.out.println("Execute:"+sql2);
            System.out.println(gf.queryFile(sql2));
            
            System.out.println("Execute:"+sql3);
            System.out.println(gf.queryFile(sql3));
            
            System.out.println("Execute:"+sql4);
            System.out.println(gf.queryFile(sql4));
            
            System.out.println("Execute:"+sql5);
            System.out.println(gf.queryFile(sql5));
            
        }

    输出结果如下:

    Execute:select * from abc.csv 
    1,abc,aaa
    2,def,bbb
    3,xyz,ccc
    
    Execute:select id from abc.csv 
    1
    2
    3
    
    Execute:select id,username from abc.csv where id=2 
    2,def
    
    Execute:select id,username from abc.csv where username=abc and password=aaa 
    1,abc
    
    Execute:select id,username from abc.csv where username=abc and password=bbb

    完整程序请大家从[这里]下载

    五.  后续
    本例为通过简单的SQL语句查询本地存在的文件,大家可以扩展此程序,让其支持更复杂的SQL,结果排序,索引等功能。
    后续章节我将在此程序的基础上,把CSV文件放到另外一台电脑,然后让其支持JDBC接口。
    最后换成数据库,并且一步一步实现ORM,Service,HTTP查询等功能。

    如有问题,大家来我的网站进行提问。
    https://www.java123.vip/qa

    版权声明:本教程版权归java123.vip所有,禁止任何形式的转载与引用。

    原帖发表于:https://www.cnblogs.com/java123vip/p/9719828.html

  • 相关阅读:
    基于 Docker 的 MySQL 主从复制搭建
    获取 Docker 容器的 IP 地址
    Maven 学习资料
    docker 中,修改了 mysql 配置,如何重启 mysql?
    TiDB 学习资料
    Sharding-JDBC 学习资料
    Druid(数据库连接池) 学习资料
    JWT 学习资料
    Maven 拥有三套相互独立的生命周期:clean、default、site
    Maven 生命周期的阶段与插件的目标之间的绑定关系
  • 原文地址:https://www.cnblogs.com/java123vip/p/9719828.html
Copyright © 2020-2023  润新知