001 /* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016 package org.opengion.fukurou.process; 017 018 import org.opengion.fukurou.util.Argument; 019 import org.opengion.fukurou.util.StringUtil; 020 import org.opengion.fukurou.util.FileUtil; 021 import org.opengion.fukurou.util.Closer ; 022 import org.opengion.fukurou.util.LogWriter; 023 024 import java.util.Map ; 025 import java.util.LinkedHashMap ; 026 027 import java.io.File; 028 import java.io.BufferedReader; 029 import java.io.IOException; 030 031 /** 032 * Process_TableReaderは、ファイルから読み取った?容を?LineModel に設定後? 033 * 下流に渡す?FirstProcess インターフェースの実?ラスです? 034 * 035 * DBTableModel 形式?ファイルを読み取って、各行を LineModel にセ?して? 036 * 下?プロセスチェインの??タは上流から下流に渡されます?)に渡します? 037 * 038 * columns 属?は?NAME で列カラ?外部から?する?合に使用します? 039 * こ?属?とuseNumber属?は独立して?すが、?には?NAME を指? 040 * する場合?、useNumber="true"として、行番号??使用しますし、外部から 041 * ?する?合?、useNumber="false"にして先?から読み取ります? 042 * (自動セ?ではな??で、?に応じて設定してください) 043 * useNumber の初期値は?true" です? 044 * 045 * ※ 注? 046 * Process_TableReader では、セパレータ??で区?て読み込???、前後???゚ー?? 047 * 削除して?す? 048 * 049 * 引数??中にスペ?スを含??合?、ダブルコー??ション("") で括って下さ?? 050 * 引数??の ?』?前後には、スペ?スは挟めません。??key=value の様に 051 * 繋げてください? 052 * 053 * @og.formSample 054 * Process_TableReader -infile=INFILE -sep=, -encode=UTF-8 -columns=AA,BB,CC 055 * 056 * -infile=入力ファイル? ??力ファイル? 057 * [-existCheck=存在確? ] ?ファイルが存在しな??合エラーにする(初期値:true) 058 * [-sep=セパレータ?? ] ?区???初期値:タ? 059 * [-encode=?エンコー? ] ??力ファイルのエンコードタイ? 060 * [-columns=読み取りカラ?] ??力カラ?(カンマ区?) 061 * [-useNumber=[true/false] ] ?行番号を使用する(true)か使用しな?false)か? 062 * [-display=[false/true] ] ?結果を標準?力に表示する(true)かしな?false)?初期値:false[表示しない]) 063 * [-debug=[false/true] ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない]) 064 * 065 * @version 4.0 066 * @author Kazuhiko Hasegawa 067 * @since JDK5.0, 068 */ 069 public class Process_TableReader extends AbstractProcess implements FirstProcess { 070 private String separator = TAB; // ?区??? 071 private String infile = null; 072 private BufferedReader reader = null; 073 private LineModel model = null; 074 private String line = null; 075 private int[] clmNos = null; // ファイルのヘッ??のカラ?号 076 private boolean useNumber = true; // 5.2.2.0 (2010/11/01) 行番号を使用する(true)か使用しな?false)? 077 private boolean nameNull = false; // ?件??タ?true 078 private boolean display = false; // 表示しな? 079 private boolean debug = false; // 5.7.3.0 (2014/02/07) ???? 080 081 private int inCount = 0; 082 private int outCount = 0; 083 084 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map 085 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map 086 087 static { 088 mustProparty = new LinkedHashMap<String,String>(); 089 mustProparty.put( "infile", "入力ファイル?(??)" ); 090 091 usableProparty = new LinkedHashMap<String,String>(); 092 usableProparty.put( "existCheck", "ファイルが存在しな??合エラーにする(初期値:true)" ); 093 usableProparty.put( "sep", "区???初期値:タ?" ); 094 usableProparty.put( "encode", "入力ファイルのエンコードタイ? ); 095 usableProparty.put( "columns", "入力カラ?(カンマ区?)" ); 096 usableProparty.put( "useNumber", "行番号を使用する(true)か使用しな?false)? ); // 5.2.2.0 (2010/11/01) 097 usableProparty.put( "display", "結果を標準?力に表示する(true)かしな?false)? + 098 CR + " (初期値:false:表示しな?" ); 099 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? + 100 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ???? 101 } 102 103 /** 104 * ?ォルトコンストラクター? 105 * こ?クラスは、動??されます??ォルトコンストラクターで? 106 * super クラスに対して、?な初期化を行っておきます? 107 * 108 */ 109 public Process_TableReader() { 110 super( "org.opengion.fukurou.process.Process_TableReader",mustProparty,usableProparty ); 111 } 112 113 /** 114 * プロセスの初期化を行います?初めに??、呼び出されます? 115 * 初期処?ファイルオープン??オープン?に使用します? 116 * 117 * @og.rev 5.2.2.0 (2010/11/01) useNumber属?の追? 118 * 119 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク? 120 */ 121 public void init( final ParamProcess paramProcess ) { 122 Argument arg = getArgument(); 123 124 infile = arg.getProparty("infile"); 125 boolean existCheck = arg.getProparty("existCheck",true); 126 String encode = arg.getProparty("encode",System.getProperty("file.encoding")); 127 separator = arg.getProparty("sep",separator ); 128 String clms = arg.getProparty("columns" ); 129 useNumber = arg.getProparty("useNumber",useNumber); // 5.2.2.0 (2010/11/01) 130 display = arg.getProparty("display",display); 131 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ???? 132 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ???? 133 134 if( infile == null ) { 135 String errMsg = "ファイル名が?されて?せん? ; 136 throw new RuntimeException( errMsg ); 137 } 138 139 File file = new File( infile ); 140 141 if( ! file.exists() ) { 142 if( existCheck ) { 143 String errMsg = "ファイルが存在しません?ile=[" + file + "]" ; 144 throw new RuntimeException( errMsg ); 145 } 146 else { 147 nameNull = true; return ; 148 } 149 } 150 151 if( ! file.isFile() ) { 152 String errMsg = "ファイル名を?してください?ile=[" + file + "]" ; 153 throw new RuntimeException( errMsg ); 154 } 155 156 reader = FileUtil.getBufferedReader( file,encode ); 157 158 // 5.2.2.0 (2010/11/01) names の外部??処?先に行う? 159 // String[] clmNames = readName( reader ); // ファイルのカラ?配? 160 // if( clmNames == null || clmNames.length == 0 ) { nameNull = true; return ; } 161 162 final String[] names ; 163 if( clms != null ) { 164 names = StringUtil.csv2Array( clms ); // ??カラ?配? 165 } 166 else { 167 // 5.2.2.0 (2010/11/01) names の外部??処?先に行う? 168 String[] clmNames = readName( reader ); // ファイルのカラ?配? 169 if( clmNames == null || clmNames.length == 0 ) { nameNull = true; return ; } 170 names = clmNames; 171 } 172 173 model = new LineModel(); 174 model.init( names ); 175 176 if( display ) { println( model.nameLine() ); } 177 178 // clmNos = new int[names.length]; 179 // for( int i=0; i<clmNames.length; i++ ) { 180 // int no = model.getColumnNo( clmNames[i] ); 181 // if( no >= 0 ) { clmNos[no] = i+1; } // 行番号??1しておく? 182 // } 183 clmNos = new int[names.length]; 184 for( int i=0; i<names.length; i++ ) { 185 int no = model.getColumnNo( names[i] ); 186 // 5.2.2.0 (2010/11/01) useNumber="true"の場合?、行番号??1しておく? 187 if( no >= 0 ) { clmNos[no] = (useNumber) ? i+1 : i ; } 188 } 189 } 190 191 /** 192 * プロセスの終?行います??に??、呼び出されます? 193 * 終???ファイルクローズ??クローズ?に使用します? 194 * 195 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗] 196 */ 197 public void end( final boolean isOK ) { 198 Closer.ioClose( reader ); 199 reader = null; 200 } 201 202 /** 203 * こ???タの処?おいて、次の処?出来るかど?を問?わせます? 204 * こ?呼び出し1回毎に、次の??タを取得する準備を行います? 205 * 206 * @og.rev 5.2.2.0 (2010/11/01) ""で囲われて???タに改行が入って?場合?対? 207 * 208 * @return 処?きる:true / 処?きな?false 209 */ 210 public boolean next() { 211 if( nameNull ) { return false; } 212 213 boolean flag = false; 214 try { 215 while((line = reader.readLine()) != null) { 216 inCount++ ; 217 if( line.length() == 0 || line.charAt( 0 ) == '#' ) { continue; } 218 else { 219 // 5.2.2.0 (2010/11/01) findbugs 対???の + 連結と、?判定ロジ?) 220 int quotCount = StringUtil.countChar( line, '"' ); 221 if( quotCount % 2 != 0 ) { 222 String addLine = null; 223 StringBuilder buf = new StringBuilder( line ); 224 while(quotCount % 2 != 0 && (addLine = reader.readLine()) != null) { 225 if( addLine.length() == 0 || addLine.charAt( 0 ) == '#' ) { continue; } 226 buf.append( CR ).append( addLine ); 227 quotCount += StringUtil.countChar( addLine, '"' ); 228 } 229 line = buf.toString(); 230 } 231 flag = true; 232 break; 233 } 234 } 235 } 236 catch (IOException ex) { 237 String errMsg = "ファイル読込みエラー[" + reader.toString() + "]" ; 238 throw new RuntimeException( errMsg,ex ); 239 } 240 if( debug ) { println( line ); } // 5.7.3.0 (2014/02/07) ???? 241 return flag; 242 } 243 244 /** 245 * ??に?行データである LineModel を作?しま? 246 * FirstProcess は、次?処?チェインして???の行データ? 247 * 作?して、後続? ChainProcess クラスに処?ータを渡します? 248 * 249 * ファイルより読み込んだ?行???タ???ブルモ?に 250 * セ?するように?しま? 251 * なお?読込みは?NAME??読み込みます???タ件数が少な??合?? 252 * "" をセ?しておきます? 253 * 254 * @param rowNo 処?の行番号 255 * 256 * @return 処?換後?LineModel 257 */ 258 public LineModel makeLineModel( final int rowNo ) { 259 outCount++ ; 260 String[] vals = StringUtil.csv2Array( line ,separator.charAt(0) ); 261 262 int len = vals.length; 263 for( int clmNo=0; clmNo<model.size(); clmNo++ ) { 264 int no = clmNos[clmNo]; 265 if( len > no ) { 266 model.setValue( clmNo,vals[no] ); 267 } 268 else { 269 // EXCEL が?終端TABを削除してしま?め?少な??合?埋める? 270 model.setValue( clmNo,"" ); 271 } 272 } 273 model.setRowNo( rowNo ) ; 274 275 if( display ) { println( model.dataLine() ); } 276 277 return model; 278 } 279 280 /** 281 * BufferedReader より?NAME 行??名情報を読み取ります? 282 * ??タカラ?り前に??目名情報を示?"#Name" が存在する仮定で取り込みます? 283 * こ?行?、ファイルの形式に無関係に、TAB で区?れて?す? 284 * 285 * @param reader PrintWriterオブジェク? 286 * 287 * @return カラ?配?(存在しな??合?、サイズ??配?) 288 */ 289 private String[] readName( final BufferedReader reader ) { 290 try { 291 // 4.0.0 (2005/01/31) line 変数名変更 292 String line1; 293 while((line1 = reader.readLine()) != null) { 294 inCount++ ; 295 if( line1.length() == 0 ) { continue; } 296 if( line1.charAt(0) == '#' ) { 297 String key = line1.substring( 0,5 ); 298 if( key.equalsIgnoreCase( "#NAME" ) ) { 299 // ?レギュラー処???の TAB 以前???無視する? 300 String line2 = line1.substring( line1.indexOf( TAB )+1 ); 301 return StringUtil.csv2Array( line2 ,TAB.charAt(0) ); 302 } 303 else { continue; } 304 } 305 else { 306 String errMsg = "#NAME が見つかる前に??タが見つかりました?; 307 throw new RuntimeException( errMsg ); 308 } 309 } 310 } 311 catch (IOException ex) { 312 String errMsg = "ファイル読込みエラー[" + reader.toString() + "]" ; 313 throw new RuntimeException( errMsg,ex ); 314 } 315 return new String[0]; 316 } 317 318 /** 319 * プロセスの処?果のレポ?ト表現を返します? 320 * 処??ログラ?、?力件数、?力件数などの??です? 321 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ? 322 * 形式で出してください? 323 * 324 * @return 処?果のレポ?? 325 */ 326 public String report() { 327 String report = "[" + getClass().getName() + "]" + CR 328 + TAB + "Input File : " + infile + CR 329 + TAB + "Input Count : " + inCount + CR 330 + TAB + "Output Count : " + outCount ; 331 332 return report ; 333 } 334 335 /** 336 * こ?クラスの使用方法を返します? 337 * 338 * @og.rev 5.2.2.0 (2010/11/01) useNumber属?のコメント追? 339 * 340 * @return こ?クラスの使用方? 341 */ 342 public String usage() { 343 StringBuilder buf = new StringBuilder(); 344 345 buf.append( "Process_TableReaderは、ファイルから読み取った?容を?LineModel に設定後?" ).append( CR ); 346 buf.append( "下流に渡す?FirstProcess インターフェースの実?ラスです?" ).append( CR ); 347 buf.append( CR ); 348 buf.append( "DBTableModel 形式?ファイルを読み取って、各行を LineModel にセ?して? ).append( CR ); 349 buf.append( "下?プロセスチェインの??タは上流から下流に渡されます?)に渡します?" ).append( CR ); 350 buf.append( CR ); 351 buf.append( "columns 属?は?NAME で列カラ?外部から?する?合に使用します?" ).append( CR ); 352 buf.append( "こ?属?とuseNumber属?は独立して?すが、?には?NAME を指? ).append( CR ); 353 buf.append( "する場合?、useNumber=\"true\"として、行番号??使用しますし、外部から" ).append( CR ); 354 buf.append( "?する?合?、useNumber=\"false\"にして先?から読み取ります?" ).append( CR ); 355 buf.append( "(自動セ?ではな??で、?に応じて設定してください)" ).append( CR ); 356 buf.append( "useNumber の初期値は、\"true\" です?" ).append( CR ); 357 buf.append( CR ); 358 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR ); 359 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR ); 360 buf.append( "繋げてください? ).append( CR ); 361 buf.append( CR ).append( CR ); 362 363 buf.append( getArgument().usage() ).append( CR ); 364 365 return buf.toString(); 366 } 367 368 /** 369 * こ?クラスは、main メソ?から実行できません? 370 * 371 * @param args コマンド引数配? 372 */ 373 public static void main( final String[] args ) { 374 LogWriter.log( new Process_TableReader().usage() ); 375 } 376 }