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("\n"); } } } 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查詢等功能。
版權宣告:本教程版權歸java123.vip所有,禁止任何形式的轉載與引用。
原帖發表於:https://www.cnblogs.com/java123vip/p/9719828.html