posts - 262,  comments - 221,  trackbacks - 0
          【一】需求

          前面我們使用了commons io包中的DirectoryWalker和IOFileFilter來進(jìn)行復(fù)雜條件的搜索,但是這個(gè)程序有幾個(gè)問題:
           ①選項(xiàng)都是hard code在代碼里面,難以修改
           ②有些選項(xiàng)是必需的,有些選項(xiàng)是可選的
           ③有些選項(xiàng)是不帶參數(shù)的,有些選項(xiàng)是要帶參數(shù)的

          如果我們希望這個(gè)程序能夠更加靈活,根據(jù)人性化,那么我們需要提供一個(gè)界面,無論是普通的命令行、控制臺(tái)交互、GUI界面。而且還必須讓用戶自行決定是否要使用該選項(xiàng)。程序必須自動(dòng)根據(jù)已有的條件動(dòng)態(tài)組合

          【二】簡(jiǎn)單而功能強(qiáng)大的commons CLI

          Apache commons CLI是一個(gè)開源的,用于處理命令行的工具包。這個(gè)包目前的穩(wěn)定版本是1.2,他非常簡(jiǎn)單只有20個(gè)左右的class,但提供了幾乎所以可以用到的命令行功能。它的主頁在這里:Apache commons CLI

          根據(jù)CLI的邏輯,每一個(gè)命令行的處理都可以分為3個(gè)步驟:定義、解析、交互
           ①定義:定義命令行的各種選項(xiàng)屬性(包括縮寫、全寫、是否必須、是否帶參數(shù)、參數(shù)個(gè)數(shù)限制)
           ②解析:使用解析器對(duì)命令行選項(xiàng)列表進(jìn)行解析
           ③交互:從解析好的命令行查詢用戶輸入的參數(shù)值并進(jìn)行處理


          這里需要區(qū)分兩個(gè)名詞:選項(xiàng)(option)和參數(shù)(arguments)。選項(xiàng)是用來表明功能或者參數(shù)的意思的,例如“-d”這個(gè)字符串就是一個(gè)選項(xiàng),它可以表示一個(gè)日期。那么如果我們需要指定一個(gè)日期用于處理,就需要在“-d”后面再加上一個(gè)具體值,這個(gè)具體值就是參數(shù)(argument)。

          對(duì)應(yīng)于這3個(gè)過程,我們來認(rèn)識(shí)幾個(gè)重要的類:

          ①定義階段
           A.Option:這個(gè)類用于定義命令行的選項(xiàng),你可以通過構(gòu)造方法來定義一個(gè)選項(xiàng)
           B.Options:Option的容器,用于存儲(chǔ)多個(gè)Option
           C.OptionBuilder:使用描述性API來構(gòu)建Option,而非直接使用Option的構(gòu)造方法

          ②解析階段
           A.CommandLineParser:接口,定義了parse方法由實(shí)現(xiàn)類實(shí)現(xiàn)
           B.PosixParser:Posix風(fēng)格的命令行解析器
           C.GnuParser:GNU風(fēng)格的命令行解析器

          ③交互階段
           A.CommandLine:解析后的命令行對(duì)象,可以用于查詢選項(xiàng)的值

          【三】CLI快速入門

          通常情況下如果命令的選項(xiàng)比較簡(jiǎn)單我們使用構(gòu)造方法就夠了,但是當(dāng)選項(xiàng)的屬性比較復(fù)雜或者描述性文本比較長(zhǎng)時(shí),使用構(gòu)建器會(huì)令到程序的可讀性更進(jìn)一步。下面我們來看看這個(gè)需求:

          有這樣一個(gè)命令行,它具備如下的選項(xiàng)和參數(shù)組合:
           ①一個(gè)目錄選項(xiàng):-d,帶參數(shù)值,必須選項(xiàng)
           ②一個(gè)日期選項(xiàng):-D,帶參數(shù)值,全寫--date,可選項(xiàng)
           ③一個(gè)日期范圍選項(xiàng):-r,帶參數(shù)值,當(dāng)-D出現(xiàn)時(shí)為必選項(xiàng),否則該選項(xiàng)無效
           ④一個(gè)文件名前綴選項(xiàng):-p,帶參數(shù)值,可以有多個(gè)前綴名,以逗號(hào)分隔,可選項(xiàng)
           ⑤一個(gè)文件擴(kuò)展名選項(xiàng):-s,帶參數(shù)值,可以有多個(gè)擴(kuò)展名,以逗號(hào)分隔,可選項(xiàng)
           ⑥一個(gè)文件大小選項(xiàng):-S,帶參數(shù)值,全寫--file-size,可選項(xiàng)
           ⑦一個(gè)文件大小閥值選項(xiàng):-l,帶參數(shù)值,當(dāng)-S出現(xiàn)時(shí)為必選項(xiàng),否則該選項(xiàng)無效
           ⑧一個(gè)幫助信息選項(xiàng):-h,無參數(shù)值

          【四】代碼示例

          package example.io;

          import org.apache.commons.cli.CommandLine;
          import org.apache.commons.cli.CommandLineParser;
          import org.apache.commons.cli.HelpFormatter;
          import org.apache.commons.cli.Option;
          import org.apache.commons.cli.OptionBuilder;
          import org.apache.commons.cli.Options;
          import org.apache.commons.cli.ParseException;
          import org.apache.commons.cli.PosixParser;

          /**
           * <pre>
           * 用于指定各種搜索條件
           * </pre>
           
          */

          public class SearchCommandLineProcesser implements CommandLineProcesser {

              
          /**
               * <pre>
               * ①一個(gè)目錄選項(xiàng):-d,帶參數(shù)值,必須選項(xiàng) 
               * ②一個(gè)日期選項(xiàng):-D,帶參數(shù)值,全寫--date,可選項(xiàng)
               * ③一個(gè)日期范圍選項(xiàng):-r,帶參數(shù)值,當(dāng)-D出現(xiàn)時(shí)為必選項(xiàng),否則該選項(xiàng)無效
               * ④一個(gè)文件名前綴選項(xiàng):-p,帶參數(shù)值,可以有多個(gè)前綴名,以逗號(hào)分隔,可選項(xiàng) 
               * ⑤一個(gè)文件擴(kuò)展名選項(xiàng):-s,帶參數(shù)值,可以有多個(gè)擴(kuò)展名,以逗號(hào)分隔,可選項(xiàng) 
               * ⑥一個(gè)文件大小選項(xiàng):-S,帶參數(shù)值,全寫--file-size,可選項(xiàng) 
               * ⑦一個(gè)文件大小閥值選項(xiàng):-l,帶參數(shù)值,當(dāng)-S出現(xiàn)時(shí)為必選項(xiàng),否則該選項(xiàng)無效 
               * ⑧一個(gè)幫助信息選項(xiàng):-h,無參數(shù)值
               * </pre>.
               
          */


              
          private Options searchOpts = new Options();

              
          private CommandLine cl = null;

              
          /**
               * The main method.
               * 
               * 
          @param args the arguments
               
          */

              
          public static void main(String[] args) {
                  SearchCommandLineProcesser processer 
          = new SearchCommandLineProcesser();
                  processer.run(args);
                  processer.validte();
              }


              
          /**
               * Instantiates a new search command line processer.
               
          */

              
          public SearchCommandLineProcesser() {
                  String desc 
          = "Specify the directory where search start";
                  Option optStartDir 
          = OptionBuilder.withDescription(desc).isRequired(false)
                          .hasArgs().withArgName(
          "START_DIRECTORY").create('d');
                  searchOpts.addOption(optStartDir);
              }


              
          /**
               * Set rule for command line parser, run parsing process
               * 
               * 
          @param args the args
               
          */

              
          private void run(String[] args) {
                  setDate();
                  setDateRange();
                  setPrefix();
                  setSuffix();
                  setSize();
                  setSizeRange();
                  setHelp();
                  runProcess(searchOpts, args, 
          new PosixParser());
              }


              
          /**
               * Sets the date.
               
          */

              
          public void setDate() {
                  String desc 
          = "Specify the file create date time";
                  Option optDate 
          = OptionBuilder.withDescription(desc).isRequired(false)
                          .hasArgs().withArgName(
          "FILE_CREATE_DATE").withLongOpt("date")
                          .create(
          'D');
                  searchOpts.addOption(optDate);
              }


              
          /**
               * Sets the date range.
               
          */

              
          public void setDateRange() {
                  StringBuffer desc 
          = new StringBuffer(
                          
          "Specify acceptance date range for cutoff date specify by option -d");
                  desc.append(
          "if true, older files (at or before the cutoff)");
                  desc.append(
          "are accepted, else newer ones (after the cutoff)");
                  Option optDateRange 
          = null;

                  optDateRange 
          = OptionBuilder.withDescription(desc.toString())
                          .isRequired(
          false).hasArg().withArgName("DATE_RANGE")
                          .create(
          'r');
                  searchOpts.addOption(optDateRange);
              }


              
          /**
               * Sets the prefix.
               
          */

              
          public void setPrefix() {
                  String desc 
          = "Specify the prefix of file, multiple prefixes can be split by comma";
                  Option optPrefix 
          = OptionBuilder.withDescription(desc)
                          .isRequired(
          false).hasArgs().withArgName("FILE_PREFIXES")
                          .create(
          'p');
                  searchOpts.addOption(optPrefix);
              }


              
          /**
               * Sets the suffix.
               
          */

              
          public void setSuffix() {
                  String desc 
          = "Specify the suffix of file, multiple suffixes can be split by comma";
                  Option optSuffix 
          = OptionBuilder.withDescription(desc)
                          .isRequired(
          false).hasArgs().withArgName("FILE_SUFFIXES")
                          .create(
          's');
                  searchOpts.addOption(optSuffix);
              }


              
          /**
               * Sets the size.
               
          */

              
          public void setSize() {
                  String desc 
          = "Spcify the file size";
                  Option optSize 
          = OptionBuilder.withDescription(desc).isRequired(false)
                          .hasArg().withArgName(
          "FILE_SIZE_WITH_LONG_VALUE").withLongOpt(
                                  
          "file-size").create('S');
                  searchOpts.addOption(optSize);
              }


              
          /**
               * Sets the size range.
               
          */

              
          public void setSizeRange() {
                  StringBuffer desc 
          = new StringBuffer(
                          
          "Specify acceptance size threshold for file specify by option -S");
                  desc.append(
          "if true, files equal to or larger are accepted,");
                  desc.append(
          "otherwise smaller ones (but not equal to)");
                  Option optDateRange 
          = null;

                  optDateRange 
          = OptionBuilder.withDescription(desc.toString())
                          .isRequired(
          false).hasArg().withArgName("SIZE_THRESHOLD")
                          .create(
          'l');
                  searchOpts.addOption(optDateRange);
              }


              
          /**
               * Sets the help.
               
          */

              
          public void setHelp() {
                  String desc 
          = "Print help message and all options information";
                  Option optHelp 
          = OptionBuilder.withDescription(desc).isRequired(false)
                          .create(
          'h');
                  searchOpts.addOption(optHelp);
              }


              
          /**
               * Run process.
               * 
               * 
          @param opts the opts
               * 
          @param args the args
               * 
          @param parser the parser
               
          */

              
          public void runProcess(Options opts, String[] args, CommandLineParser parser) {
                  
          try {
                      cl 
          = process(searchOpts, args, parser);
                  }
           catch (ParseException e) {            
                      System.out.println(
          "Error on compile/parse command: "
                              
          + e.getMessage());
                      printHelp(opts);
                      System.exit(
          -1);
                  }

                  Option[] allOpts 
          = cl.getOptions();
                  Option opt 
          = null;
                  
          for (int i = 0; i < allOpts.length; i++{
                      opt 
          = allOpts[i];
                      
          if("h".equals(opt.getOpt())) {
                          printHelp(opts);
                          System.exit(
          0);
                      }

                      System.out.println(
          "Option name: -" + opt.getOpt()
                              
          + ", and value = " + getOptValues(opt.getOpt(), ","));
                  }

              }


              
          /*
               * (non-Javadoc)
               * 
               * @see example.io.CommandLineProcesser#process(org.apache.commons.cli.Options,
               *      java.lang.String[], org.apache.commons.cli.CommandLineParser)
               
          */

              
          public CommandLine process(Options options, String[] args,
                      CommandLineParser parser) 
          throws ParseException {                
                  
          return parser.parse(options, args);
              }


              
          /**
               * Validte required option and optional options
               
          */

              
          private void validte() {
                  
                  
          // Validate directory option
                  String directory = getOptValue("d");
                  
          if (directory == null{
                      System.out.println(
          "Missing start directory, ignore and exit");
                      System.exit(
          -1);
                  }

                  
          // Validate date option
                  String date = (getOptValue("D"== null? getOptValue("date")
                          : getOptValue(
          "D");
                  String dateRange 
          = getOptValue("r");
                  
          if(date != null && (dateRange == null)) {
                      System.out.println(
          "Missing option -D/--date, exit immediately");
                      System.exit(
          -1);
                  }
          else if (date == null && (dateRange != null)) {
                      System.out.println(
          "Date not specified, ignore option -r");
                  }

                  
          // Validate size option
                  String size = (getOptValue("S"== null? getOptValue("file-size")
                          : getOptValue(
          "S");
                  String sizeRange 
          = getOptValue("l");
                  
          if(size != null && (sizeRange == null)) {
                      System.out.println(
          "Missing option -S/--file-size, exit immediately");
                      System.exit(
          -1);
                  }
          else if (size == null && (sizeRange != null)) {
                      System.out.println(
          "File size not specified, ignore option -l");
                  }

              }


              
          /**
               * Prints the help.
               * 
               * 
          @param options the options
               
          */

              
          public void printHelp(Options options) {
                  String formatstr 
          = "java example.io.SearchCommandLineProcesser [-h][-d][-D/--date<-r>][-p][-s][-S/--size<-l>]";
                  HelpFormatter formatter 
          = new HelpFormatter();
                  formatter.printHelp(formatstr, options);
              }


              
          /*
               * (non-Javadoc)
               * 
               * @see example.io.CommandLineProcesser#getOptValue(java.lang.String)
               
          */

              
          public String getOptValue(String opt) {
                  
          return (cl != null? cl.getOptionValue(opt) : "";
              }


              
          /*
               * (non-Javadoc)
               * 
               * @see example.io.CommandLineProcesser#getOptValues(java.lang.String)
               
          */

              
          public String[] getOptValues(String opt) {
                  
          return (cl != null? cl.getOptionValues(opt) : new String[] "" };
              }


              
          /*
               * (non-Javadoc)
               * 
               * @see example.io.CommandLineProcesser#getOptValues(java.lang.String,
               *      java.lang.String)
               
          */

              
          public String getOptValues(String opt, String valueSeparater) {
                  String[] values 
          = getOptValues(opt);
                  StringBuffer sb 
          = new StringBuffer();
                  
          for (int i = 0; i < values.length; i++{
                      sb.append(values[i]).append(valueSeparater);
                  }

                  
          return sb.subSequence(0, sb.length() - 1).toString();
              }


          }

          【五】結(jié)果演示

          ①演示使用方法:

          控制臺(tái)參數(shù)為:-h




          ②正確命令格式

          控制臺(tái)命令格式為:-d E:/Other/Picture/私人/ -D "2010-01-01-01 00:00:00" -r true -p IMG_,DSMG, -s .jpg,.gif --file-size 1024*1024*2 -l true



          ③錯(cuò)誤命令格式

          控制臺(tái)命令格式為:-d E:/Other/Picture/私人/ -D "2010-01-01-01 00:00:00" -r true -p IMG_,DSMG, -s .jpg,.gif --file-size 1024*1024*2 -l true -Q




          -------------------------------------------------------------
          生活就像打牌,不是要抓一手好牌,而是要盡力打好一手爛牌。
          posted on 2010-04-02 14:20 Paul Lin 閱讀(1075) 評(píng)論(0)  編輯  收藏 所屬分類: J2SE
          <2010年4月>
          28293031123
          45678910
          11121314151617
          18192021222324
          2526272829301
          2345678

          常用鏈接

          留言簿(21)

          隨筆分類

          隨筆檔案

          BlogJava熱點(diǎn)博客

          好友博客

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 始兴县| 徐汇区| 巴彦淖尔市| 封开县| 视频| 巴马| 靖宇县| 宜宾市| 华容县| 北川| 吉林市| 蒙阴县| 韩城市| 迁安市| 陈巴尔虎旗| 华池县| 神池县| 枣强县| 开鲁县| 和田市| 安多县| 湘阴县| 安阳县| 罗甸县| 老河口市| 虞城县| 鄂托克旗| 昭通市| 始兴县| 乐亭县| 巧家县| 卢湾区| 来宾市| 孟州市| 比如县| 临汾市| 昆山市| 武隆县| 白沙| 富川| 萨嘎县|