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