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

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

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

          【二】簡單而功能強大的commons CLI

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

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


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

          對應于這3個過程,我們來認識幾個重要的類:

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

          ②解析階段
           A.CommandLineParser:接口,定義了parse方法由實現類實現
           B.PosixParser:Posix風格的命令行解析器
           C.GnuParser:GNU風格的命令行解析器

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

          【三】CLI快速入門

          通常情況下如果命令的選項比較簡單我們使用構造方法就夠了,但是當選項的屬性比較復雜或者描述性文本比較長時,使用構建器會令到程序的可讀性更進一步。下面我們來看看這個需求:

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

          【四】代碼示例

          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>
               * ①一個目錄選項:-d,帶參數值,必須選項 
               * ②一個日期選項:-D,帶參數值,全寫--date,可選項
               * ③一個日期范圍選項:-r,帶參數值,當-D出現時為必選項,否則該選項無效
               * ④一個文件名前綴選項:-p,帶參數值,可以有多個前綴名,以逗號分隔,可選項 
               * ⑤一個文件擴展名選項:-s,帶參數值,可以有多個擴展名,以逗號分隔,可選項 
               * ⑥一個文件大小選項:-S,帶參數值,全寫--file-size,可選項 
               * ⑦一個文件大小閥值選項:-l,帶參數值,當-S出現時為必選項,否則該選項無效 
               * ⑧一個幫助信息選項:-h,無參數值
               * </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();
              }


          }

          【五】結果演示

          ①演示使用方法:

          控制臺參數為:-h




          ②正確命令格式

          控制臺命令格式為:-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



          ③錯誤命令格式

          控制臺命令格式為:-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 閱讀(1081) 評論(0)  編輯  收藏 所屬分類: J2SE
          <2010年4月>
          28293031123
          45678910
          11121314151617
          18192021222324
          2526272829301
          2345678

          常用鏈接

          留言簿(21)

          隨筆分類

          隨筆檔案

          BlogJava熱點博客

          好友博客

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 阿拉善左旗| 洪湖市| 中江县| 招远市| 黄石市| 星座| 大同县| 榆林市| 孝昌县| 鄂托克前旗| 玉环县| 加查县| 大城县| 韶山市| 林芝县| 铁力市| 濮阳市| 宣威市| 嫩江县| 禹州市| 嘉善县| 汝南县| 千阳县| 孝感市| 东阳市| 海门市| 福安市| 万州区| 福贡县| 洛川县| 滨州市| 沁阳市| 五寨县| 禄劝| 华阴市| 古田县| 周口市| 宝山区| 碌曲县| 咸宁市| 佛冈县|