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
代码如下:

 1 /**
 2      * @author http://www.java123.vip
 3      * @param sql
 4      * @return
 5      */
 6     private boolean checkSql(String sql) {
 7         int selectPos = sql.indexOf("select");
 8         int fromPos = sql.indexOf("from");
 9         int wherePos = sql.indexOf("where");
10
11         if(selectPos != 0
12                 || fromPos <= selectPos
13                 || (wherePos != -1 && wherePos <= fromPos)) {
14             return false;
15         }else {
16             return true;
17         }
18     }

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

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

 1 package vip.java123.fileview;
 2
 3 /**
 4  *
 5  * @author http://www.java123.vip
 6  *
 7  */
 8 public class SqlParseResult {
 9     public String[] fields;
10     public String fileName;
11     public String[] whereConditions;
12
13     public void clearSpace() {
14         for(int i = 0; i < fields.length; i ++) {
15             fields[i] = fields[i].trim();
16         }
17
18         fileName = fileName.trim();
19
20         for(int i = 0; i < whereConditions.length; i ++) {
21             whereConditions[i] = whereConditions[i].trim();
22         }
23     }
24 }

解析的函数如下

 1 /**
 2      * @author http://www.java123.vip
 3      * @param sql
 4      * @return
 5      */
 6     private SqlParseResult parseSql(String sql) {
 7         int selectPos = sql.indexOf("select");
 8         int fromPos = sql.indexOf("from");
 9         int wherePos = sql.indexOf("where");
10
11         String columnStr = sql.substring(selectPos + "select".length(), fromPos).trim();
12         String fileNameStr;
13         String whereStr;
14         if(wherePos == -1) {
15             fileNameStr = sql.substring(fromPos + "from".length());
16             whereStr = "";
17         }else {
18             fileNameStr = sql.substring(fromPos + "from".length(),wherePos);
19             whereStr = sql.substring(wherePos + "where".length());
20         }
21
22
23         SqlParseResult spr = new SqlParseResult();
24         spr.fields = columnStr.split(",");
25         spr.fileName = fileNameStr;
26         if(wherePos == -1) {
27             spr.whereConditions = new String[] {};
28         }else {
29             spr.whereConditions = whereStr.split("and");
30         }
31
32         spr.clearSpace();
33
34         return spr;
35     }

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

 1 /**
 2      * @author http://www.java123.vip
 3      * @param line
 4      * @param whereConditions
 5      * @param header
 6      * @return
 7      */
 8     private boolean checkRow(String line, String[] whereConditions, String[] header) {
 9         // username=abc  password=aaa
10         String[] lineColumns = line.split(",");
11         for(int i = 0; i < whereConditions.length; i ++) {
12             String key = whereConditions[i].split("=")[0];
13             String value = whereConditions[i].split("=")[1];
14
15             String checkValue = lineColumns[getHeaderIndex(header,key)];
16             if(!value.equals(checkValue)) {
17                 return false;
18             }
19         }
20         return true;
21     }

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

 1 /**
 2      * @author http://www.java123.vip
 3      * @param header
 4      * @param headerName
 5      * @return
 6      */
 7     private int getHeaderIndex(String[] header,String headerName) {
 8         for(int i = 0; i < header.length; i ++) {
 9             if(header[i].equals(headerName)) {
10                 return i;
11             }
12         }
13
14         return -1;
15     }

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

 1 /**
 2      * @author http://www.java123.vip
 3      * @param line
 4      * @param fields
 5      * @param header
 6      * @return
 7      */
 8     private String selectLine(String line, String[] fields, String[] header) {
 9
10         if(fields[0].equals("*")) {
11             return line;
12         }
13
14         StringBuffer result = new StringBuffer();
15
16         String[] lineColumns = line.split(",");
17         for(int i = 0; i < fields.length; i ++) {
18             int columnIndex = this.getHeaderIndex(header, fields[i]);
19             result.append(lineColumns[columnIndex]);
20
21             if(i != fields.length -1) {
22                 result.append(",");
23             }
24         }
25         return result.toString();
26     }

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

 1 /**
 2      * @author http://www.java123.vip
 3      * @param sql
 4      * @return
 5      * @throws Exception
 6      */
 7     public String queryFile(String sql) throws Exception{
 8         sql = sql.toLowerCase().trim();
 9
10         if(!checkSql(sql)) {
11             return null;
12         }
13         SqlParseResult spr = parseSql(sql);
14
15         File f = new File(basePath + spr.fileName);
16
17         FileInputStream fis = new FileInputStream(f);
18         InputStreamReader isr = new InputStreamReader(fis);
19         BufferedReader br = new BufferedReader(isr);
20
21         boolean readHeader = true;
22         String[] header = null;
23
24         StringBuffer result = new StringBuffer();
25         String line = null;
26         while((line = br.readLine()) != null) {
27             if(readHeader) {
28                 header = line.split(",");
29                 readHeader = false;
30             }else {
31                 if(checkRow(line,spr.whereConditions,header)) {
32
33                     result.append(selectLine(line,spr.fields,header));
34                     result.append("\n");
35                 }
36             }
37
38         }
39
40         br.close();
41         isr.close();
42         fis.close();
43
44         return result.toString();
45     }

最后,测试我们的程序:

 1 /**
 2      * @author http://www.java123.vip
 3      * @param args
 4      * @throws Exception
 5      */
 6     public static void main(String[] args) throws Exception {
 7
 8         GetFile gf = new GetFile("c:/temp/");
 9
10         String sql1 = "select * from abc.csv ";
11         String sql2 = "select id from abc.csv ";
12         String sql3 = "select id,username from abc.csv where id=2 ";
13         String sql4 = "select id,username from abc.csv where username=abc and password=aaa ";
14         String sql5 = "select id,username from abc.csv where username=abc and password=bbb ";
15
16         System.out.println("Execute:"+sql1);
17         System.out.println(gf.queryFile(sql1));
18
19         System.out.println("Execute:"+sql2);
20         System.out.println(gf.queryFile(sql2));
21
22         System.out.println("Execute:"+sql3);
23         System.out.println(gf.queryFile(sql3));
24
25         System.out.println("Execute:"+sql4);
26         System.out.println(gf.queryFile(sql4));
27
28         System.out.println("Execute:"+sql5);
29         System.out.println(gf.queryFile(sql5));
30
31     }

输出结果如下:

Execute:select * from abc.csv
1,abc,aaa
2,def,bbb
3,xyz,ccc

Execute:select id from abc.csv
2

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/java123-vip/p/9740186.html

时间: 2024-10-09 05:03:26

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

Java学习不走弯路教程(1.DOS环境搭建)

DOS环境搭建在开始写第一个Java程序之前,我们需要做一些简单的准备工作. 1.1 还记得DOS吗我们可以通过图形界面来操作我们的电脑.但作为程序员,你首先需要学会用命令行的方式来操作电脑,因为不是所有的电脑都提供图形界面的.Windows环境下可以通过DOS来执行命令.你只需要记住大概5个命令,即可完成电脑的基本操作. 我们首先启动DOS环境:在文件浏览器的地址栏中输入cmd,回车,如下图所示. 光标左边显示的是当前所在目录.本教程实例均在C盘下操作,所以如果不是C盘,输入c:回车,切换到C

Java学习不走弯路教程(11 单例模式2(单实例类))

单例模式2(单实例类) 一. 前言 在前上一章教程中,介绍了静态方法的伪单例模式.本章将在上一章的基础上,进一步扩展程序. 注:1.本文针对初学Java的同学训练学习思路,请不要太纠结于细节问题.2.本文旨在达到抛砖引玉的效果,希望大家扩展本例子,以学到更多知识的精髓. 学习本章需要准备的知识:1.读完本系列教程的前面章节.2.理解单例模式. 二. 步入正题话不多说,大家自己理解,下面步入正题: 静态方法虽然能满足我们的需求,但他牺牲了面向对象对程序带来的扩展性,比如AOP等.本章我们讨论对单实

Java学习不走弯路教程(14 代码结构整理)

代码结构整理 一. 前言 在前上一章教程中,介绍了和浏览器的通讯.本章将在上一章的基础上,进一步扩展程序. 注:1.本文针对初学Java的同学训练学习思路,请不要太纠结于细节问题.2.本文旨在达到抛砖引玉的效果,希望大家扩展本例子,以学到更多知识的精髓. 学习本章需要准备的知识:1.读完本系列教程的前面章节.二. 步入正题 话不多说,大家自己理解,下面步入正题: 为了在后面的课程中走的更远,我们来整理一下代码的结构. 首先我们把业务逻辑都放在app包下,并且将这个包分为三层,web,servic

Java开发手册 Java学习手册教程(MtJava开发手册)

本文档的版权归MtJava文档小组所有,本文档及其描述的内容受有关法律的版权保护,对本文档内容的任何形式的非法复制,泄露或散布,将导致相应的法律责任. MtJava只是一个学习Java的简化版本,适合有一些Java基础的人学习参考,主要是为了辅助MtAndroid的学习者学习的文档 Java开发手册 Java学习手册教程(MtJava开发手册),布布扣,bubuko.com

java 使用Reader和Writer对文件内容的拷贝

package com.hc.fileio; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; /**对文件内容的拷贝 * @author MaskedMen *Reader和Writer只能读写字符流 */ public class ReaderWr

java 学习笔记之 流、文件的操作

ava 学习笔记之 流.文件的操作 对于一些基础的知识,这里不再过多的解释, 简单的文件查询过滤操作 package com.wfu.ch08; import java.io.File; import java.io.FilenameFilter; public class Test1 { public static void main(String[] args) { File file=new File("F:\\2017-2018-1\\javase"); // //获取该目录下

Java之扫描目录,修改文件内容

扫描目录下文件,修改文件中指定内容 1 package org.utils.tools.fileoper; 2 3 import java.io.*; 4 import java.util.ArrayList; 5 import java.util.List; 6 7 /* 8 * 修改文件中的内容 9 * 替换properties文件中的ip 10 * */ 11 public class EditFile { 12 public static void main(String args[])

云计算学习路线教程大纲课件:客户端查询

云计算学习路线教程大纲课件客户端查询: ==================================================================================== nslookup,host,dig 客户端指定本地DNS [[email protected] ~]# cat /etc/resolv.conf nameserver 192.168.2.115 [[email protected] ~]# dig www.baidu.com [[emai

Java使用jxl修改现有Excel文件内容,并验证其是否对公式的结果产生影响

jxl的maven坐标: <!-- https://mvnrepository.com/artifact/net.sourceforge.jexcelapi/jxl --> <dependency> <groupId>net.sourceforge.jexcelapi</groupId> <artifactId>jxl</artifactId> <version>2.6.12</version> </de