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 */ 016package org.opengion.fukurou.model; 017 018import java.io.File; // 6.2.0.0 (2015/02/27) 019import java.io.IOException; 020import java.io.OutputStream; 021import java.io.FileOutputStream; 022import java.io.BufferedOutputStream; 023import java.util.Locale; 024import java.util.Map; // 6.0.2.3 (2014/10/10) 画像関連 025import java.util.HashMap; // 6.0.2.3 (2014/10/10) 画像関連 026import java.util.List; // 8.0.1.0 (2021/10/29) 027 028import org.apache.poi.util.Units; // 7.2.9.0 (2020/10/12) 029 030import org.apache.poi.common.usermodel.HyperlinkType; // 6.5.0.0 (2016/09/30) poi-3.15 031import org.apache.poi.ss.util.WorkbookUtil; 032import org.apache.poi.ss.usermodel.Workbook; 033import org.apache.poi.ss.usermodel.Sheet; 034import org.apache.poi.ss.usermodel.Row; 035import org.apache.poi.ss.usermodel.Cell; 036import org.apache.poi.ss.usermodel.CellType; // 6.5.0.0 (2016/09/30) poi-3.15 037import org.apache.poi.ss.usermodel.CellStyle; 038import org.apache.poi.ss.usermodel.VerticalAlignment; // 6.5.0.0 (2016/09/30) poi-3.15 039import org.apache.poi.ss.usermodel.BorderStyle; // 6.5.0.0 (2016/09/30) poi-3.15 040import org.apache.poi.ss.usermodel.Font; 041import org.apache.poi.ss.usermodel.IndexedColors; 042import org.apache.poi.ss.usermodel.RichTextString; 043import org.apache.poi.ss.usermodel.Hyperlink; 044import org.apache.poi.ss.usermodel.CreationHelper; 045import org.apache.poi.ss.usermodel.Drawing; // 6.0.2.3 (2014/10/10) 画像関連 046import org.apache.poi.ss.usermodel.ClientAnchor; // 6.0.2.3 (2014/10/10) 画像関連 047import org.apache.poi.ss.usermodel.Picture; // 6.0.2.3 (2014/10/10) 画像関連 048 049import org.apache.poi.hssf.usermodel.HSSFWorkbook; // .xls 050 051//import org.apache.poi.POIXMLDocumentPart; // 6.2.4.2 (2015/05/29) テキスト変換処理 052import org.apache.poi.ooxml.POIXMLDocumentPart; // 7.0.0.0 (2018/10/01) poi-ooxml-3.17.jar → poi-ooxml-4.0.0.jar 053 054import org.apache.poi.xssf.usermodel.XSSFDrawing; // 6.2.4.2 (2015/05/29) テキスト変換処理 055import org.apache.poi.xssf.usermodel.XSSFShape; // 6.2.4.2 (2015/05/29) テキスト変換処理 056import org.apache.poi.xssf.usermodel.XSSFSimpleShape; // 6.2.4.2 (2015/05/29) テキスト変換処理 057import org.apache.poi.xssf.usermodel.XSSFTextParagraph; // 6.2.4.2 (2015/05/29) テキスト変換処理 058import org.apache.poi.xssf.usermodel.XSSFTextRun; // 6.2.4.2 (2015/05/29) テキスト変換処理 059import org.apache.poi.xssf.streaming.SXSSFWorkbook; // .xlsx 6.3.7.0 (2015/09/04) 制限あり 高速、低メモリ消費 060 061import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29) 062import org.opengion.fukurou.system.Closer; 063import org.opengion.fukurou.util.ImageUtil; // 6.0.2.3 (2014/10/10) 画像関連 064 065import static org.opengion.fukurou.system.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 066import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring 067 068/** 069 * POI による、EXCELバイナリファイルに対する、データモデルクラスです。 070 * 071 * 共通的な EXCEL処理 を集約しています。 072 * staticメソッドによる簡易的なアクセスの他に、順次処理も可能なように 073 * 現在アクセス中の、Workbook、Sheet、Row、Cell オブジェクトを内部で管理しています。 074 * 075 * 入力形式は、openXML形式にも対応しています。 076 * ファイルの内容に応じて、.xlsと.xlsxのどちらで読み取るかは、内部的に 077 * 自動判定されます。 078 * 079 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 080 * @og.group その他 081 * 082 * @version 6.0 083 * @author Kazuhiko Hasegawa 084 * @since JDK7.0, 085 */ 086public class ExcelModel { 087 /** このプログラムのVERSION文字列を設定します。 {@value} */ 088 private static final String VERSION = "8.0.1.0 (2021/10/29)" ; 089 090 private static final String DEF_SHEET_NAME = "Sheet" ; 091 092 // 6.0.2.3 (2014/10/10) ImageUtil の Suffix と、Workbook.PICTURE_TYPE_*** の関連付けをしておきます。 093 // Suffix 候補は、[bmp, gif, jpeg, jpg, png, wbmp] だが、対応する PICTURE_TYPE は一致しない。 094 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 095 private static final Map<String,Integer> PICTURE_TYPE ; 096 static { 097 PICTURE_TYPE = new HashMap<>() ; 098 PICTURE_TYPE.put( "png" , Integer.valueOf( Workbook.PICTURE_TYPE_PNG ) ); 099 PICTURE_TYPE.put( "jpeg" , Integer.valueOf( Workbook.PICTURE_TYPE_JPEG ) ); 100 PICTURE_TYPE.put( "jpg" , Integer.valueOf( Workbook.PICTURE_TYPE_JPEG ) ); 101 } 102 103 private final String inFilename ; // エラー発生時のキーとなる、EXCELファイル名 104 private final String sufix ; // 6.1.0.0 (2014/12/26) オープンしたファイル形式を記憶(ピリオドを含む) 105 106 private final Workbook wkbook ; // 現在処理中の Workbook 107 private Sheet sheet ; // 現在処理中の Sheet 108 private Row rowObj ; // 現在処理中の Row 109 110 private int refSheetIdx = -1; // 雛形シートのインデックス 111 112 private final CreationHelper createHelper ; // poi.xssf対応 113 114 private CellStyle style ; // 共通のセルスタイル 115 private CellStyle hLinkStyle ; // Hyperlink用のセルスタイル(青文字+下線) 116 117 private int maxColCount = 5 ; // 標準セル幅の5倍を最大幅とする。 118 private int dataStartRow = -1; // データ行の開始位置。未設定時は、-1 119 private boolean isAutoCellSize ; // カラム幅の自動調整を行うかどうか(true:行う/false:行わない) 120 121 private String addTitleSheet ; // Sheet一覧を先頭Sheetに作成する場合のSheet名 122 123 private String[] recalcSheetNames ; // 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせるシート名の配列。 124 125 /** 126 * EXCELファイルのWookbookのデータ処理モデルを作成します。 127 * 128 * ここでは、既存のファイルを読み込んで、データ処理モデルを作成しますので、 129 * ファイルがオープンできなければエラーになります。 130 * 131 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 132 * @og.rev 6.2.0.0 (2015/02/27) ファイル引数を、String → File に変更 133 * 134 * @param file EXCELファイル 135 * @see #ExcelModel( File , boolean ) 136 */ 137 public ExcelModel( final File file ) { 138 this( file,true ); 139 } 140 141 /** 142 * EXCELファイルのWookbookのデータ処理モデルを作成します。 143 * 144 * isOpen条件によって、ファイルオープン(true)か、新規作成(false)が分かれます。 145 * ファイルオープンの場合は、EXCELの読み込み以外に、追記するとか、雛形参照する 146 * 場合にも、使用します。 147 * ファイルオープンの場合は、当然、ファイルがオープンできなければエラーになります。 148 * 149 * isOpen=新規作成(false) の場合は、ファイル名の拡張子で、XSSFWorkbook か HSSFWorkbook を 150 * 判定します。.xlsx の場合⇒XSSFWorkbook オブジェクトを使用します。 151 * 152 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 153 * @og.rev 6.0.2.3 (2014/10/10) POIUtil#createWorkbook( String ) を使用するように変更 154 * @og.rev 6.1.0.0 (2014/12/26) 入力ファイルの拡張子判定の対応 155 * @og.rev 6.2.0.0 (2015/02/27) ファイル引数を、String → File に変更 156 * @og.rev 6.2.2.0 (2015/03/27) マクロ付Excel(.xlsm)対応 157 * @og.rev 6.3.7.0 (2015/09/04),5.9.0.0 (2015/09/04) 標準を、SXSSFWorkbook に切り替えてみる。 158 * 159 * @param file EXCELファイル 160 * @param isOpen true:ファイルオープン/false:新規作成 161 * @see #ExcelModel( File ) 162 */ 163 public ExcelModel( final File file , final boolean isOpen ) { 164 inFilename = file.getName(); 165 166 final int idx = inFilename.lastIndexOf( '.' ); // 拡張子の位置 167 if( idx >= 0 ) { 168 sufix = inFilename.substring( idx ).toLowerCase( Locale.JAPAN ); // ピリオドを含む 169 } 170 else { 171 final String errMsg = "ファイルの拡張子が見当たりません。(.xls か .xlsx/.xlsm を指定下さい)" + CR 172 + " filename=[" + file + "]" + CR ; 173 throw new IllegalArgumentException( errMsg ); 174 } 175 176 if( isOpen ) { 177 wkbook = POIUtil.createWorkbook( file ); 178 } 179 else { 180 // 新規の場合、ファイル名に.xlsxで終了した場合⇒.xlsx形式ファイル作成、その他⇒.xls形式ファイル作成 181 if( ".xlsx".equals( sufix ) || ".xlsm".equals( sufix ) ) { // 6.2.2.0 (2015/03/27) 182 // 6.3.7.0 (2015/09/04),5.9.0.0 (2015/09/04) 標準を、SXSSFWorkbook に切り替えてみる。 183 // wkbook = new XSSFWorkbook(); 184 wkbook = new SXSSFWorkbook(); // 機能制限有:シートや行の削除や、AutoCellSize の指定ができないなど。 185 } 186 else if( ".xls".equals( sufix ) ) { 187 wkbook = new HSSFWorkbook(); 188 } 189 else { 190 final String errMsg = "ファイルの拡張子が不正です。(.xls か .xlsx/.xlsm のみ可能)" + CR 191 + " filename=[" + file + "]" + CR ; 192 throw new IllegalArgumentException( errMsg ); 193 } 194 } 195 196 createHelper = wkbook.getCreationHelper(); // poi.xssf対応 197 } 198 199 /** 200 * 内部 Workbook に、フォント名、フォントサイズを設定します。 201 * fontName(フォント名)は、"MS Pゴシック" など名称になります。 202 * fontPoint は、フォントの大きさを指定します。 203 * 内部的には、setFontHeightInPoints(short)メソッドで設定します。 204 * 205 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 206 * 207 * @param fontName フォント名 ("MS Pゴシック" など。nullの場合セットしません) 208 * @param fontPoint フォントの大きさ (0やマイナスの場合はセットしません) 209 */ 210 public void setFont( final String fontName , final short fontPoint ) { 211 // System.out.println( "FontName=" + fontName + " , Point=" + fontPoint ); 212 213 if( style == null ) { style = wkbook.createCellStyle(); } 214 215 final Font font = wkbook.createFont(); 216 // final Font font = wkbook.getFontAt( style.getFontIndex() ); // A,B などのヘッダーもフォントが 217 if( fontName != null ) { 218 font.setFontName( fontName ); // "MS Pゴシック" など 219 } 220 if( fontPoint > 0 ) { 221 font.setFontHeightInPoints( fontPoint ); 222 } 223 224 style.setFont( font ); 225 } 226 227 /** 228 * データ設定する セルに、罫線を追加します。 229 * 230 * ここで設定するのは、罫線の種類と、罫線の色ですが、内部的に固定にしています。 231 * Border=CellStyle.BORDER_THIN 232 * BorderColor=IndexedColors.BLACK 233 * 234 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 235 * @og.rev 6.5.0.0 (2016/09/30) poi-3.15 対応(Cell.CELL_TYPE_XXXX → CellType.XXXX) 236 */ 237 public void setCellStyle() { 238 if( style == null ) { style = wkbook.createCellStyle(); } 239 240 // style.setBorderBottom( CellStyle.BORDER_THIN ); // 6.5.0.0 (2016/09/30) poi-3.12 241 // style.setBorderLeft( CellStyle.BORDER_THIN ); // 6.5.0.0 (2016/09/30) poi-3.12 242 // style.setBorderRight( CellStyle.BORDER_THIN ); // 6.5.0.0 (2016/09/30) poi-3.12 243 // style.setBorderTop( CellStyle.BORDER_THIN ); // 6.5.0.0 (2016/09/30) poi-3.12 244 245 style.setBorderBottom( BorderStyle.THIN ); // 6.4.6.0 (2016/05/27) poi-3.15 246 style.setBorderLeft( BorderStyle.THIN ); // 6.5.0.0 (2016/09/30) poi-3.15 247 style.setBorderRight( BorderStyle.THIN ); // 6.5.0.0 (2016/09/30) poi-3.15 248 style.setBorderTop( BorderStyle.THIN ); // 6.5.0.0 (2016/09/30) poi-3.15 249 250 style.setBottomBorderColor( IndexedColors.BLACK.getIndex() ); 251 style.setLeftBorderColor( IndexedColors.BLACK.getIndex() ); 252 style.setRightBorderColor( IndexedColors.BLACK.getIndex() ); 253 style.setTopBorderColor( IndexedColors.BLACK.getIndex() ); 254 255 // style.setVerticalAlignment( CellStyle.VERTICAL_TOP ); // isAutoCellSize=true 文字は上寄せする。 // 6.5.0.0 (2016/09/30) poi-3.12 256 style.setVerticalAlignment( VerticalAlignment.TOP ); // isAutoCellSize=true 文字は上寄せする。 // 6.5.0.0 (2016/09/30) poi-3.15 257 // style.setWrapText( true ); // isAutoCellSize=true 折り返して表示する。 258 } 259 260 /** 261 * 全てのSheetに対して、autoSizeColumn設定を行うかどうか指定します(初期値:false)。 262 * 263 * autoSize設定で、カラム幅が大きすぎる場合、現状では、 264 * 初期カラム幅の5倍を限度にしています。 265 * 266 * なお、autoSizeColumn設定は負荷の大きな処理なので、saveFile(String)の 267 * 中で実行されます。(セーブしなければ実行されません。) 268 * よって、指定は、いつ行っても構いません。 269 * 270 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 271 * 272 * @param flag autoSizeColumn設定を行うかどうか [true:自動カラム幅設定を行う/false:行わない] 273 * @see #useAutoCellSize( boolean,int ) 274 */ 275 public void useAutoCellSize( final boolean flag ) { 276 isAutoCellSize = flag; 277 } 278 279 /** 280 * 全てのSheetに対して、autoSizeColumn設定を行うかどうか指定します(初期値:false)。 281 * 282 * autoSize設定で、カラム幅が大きすぎる場合、現状では、 283 * 初期カラム幅のcount倍を限度に設定します。 284 * ただし、count がマイナスの場合は、無制限になります。 285 * 286 * なお、autoSizeColumn設定は負荷の大きな処理なので、saveFile(String)の 287 * 中で実行されます。(セーブしなければ実行されません。) 288 * よって、指定は、いつ行っても構いません。 289 * 290 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 291 * 292 * @param flag autoSizeColumn設定を行うかどうか [true:自動カラム幅設定を行う/false:行わない] 293 * @param count 最大幅を標準セル幅の何倍にするかを指定。マイナスの場合は、無制限 294 * @see #useAutoCellSize( boolean ) 295 */ 296 public void useAutoCellSize( final boolean flag, final int count ) { 297 isAutoCellSize = flag; 298 maxColCount = count ; 299 } 300 301 /** 302 * EXCELで、出力処理の最後にセルの計算式の再計算をさせるシート名の配列を指定します。 303 * 304 * null の場合は、再計算しません。 305 * なお、再計算は、saveFile(String)の中で実行されます。(セーブしなければ実行されません。) 306 * 307 * @og.rev 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。 308 * 309 * @param sheets 対象シート名の配列 310 */ 311 public void setRecalcSheetName( final String[] sheets ){ 312 recalcSheetNames = sheets; 313 } 314 315 /** 316 * データ行の書き込み開始位置の行番号を設定します。 317 * 318 * これは、autoSize設定で、自動調整するカラムを、ヘッダーではなく、 319 * データ部で計算する場合に使用します。 320 * 321 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 322 * 323 * @param st データ行の開始位置。未設定時は、-1 324 * @see #useAutoCellSize( boolean ) 325 */ 326 public void setDataStartRow( final int st ) { 327 dataStartRow = st; 328 } 329 330 /** 331 * Sheet一覧を先頭Sheetに作成する場合のSheet名を指定します。 332 * 333 * これは、Workbook に含まれる Sheet 一覧を作成する場合に、利用可能です。 334 * 335 * この処理は、#saveFile( File ) 処理時に、実行されます。 336 * 337 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 338 * 339 * @param shtName Sheet一覧のSheet名 340 * @see #makeAddTitleSheet() 341 */ 342 public void setAddTitleSheet( final String shtName ) { 343 addTitleSheet = shtName; 344 } 345 346 /** 347 * 内部 Workbookの Sheet数を返します。 348 * 349 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 350 * 351 * @return シート数 352 */ 353 public int getNumberOfSheets() { 354 return wkbook.getNumberOfSheets(); 355 } 356 357 /** 358 * 内部 Workbookより、雛形Sheetをセットします。 359 * 360 * これは、雛形シートを使用する場合に、使います。このメソッドが呼ばれると、 361 * 雛形シートを使用すると判定されます。 362 * 雛形シート名が、内部 Workbook に存在しない場合は、エラーになります。 363 * ただし、null をセットした場合は、最初のシートを雛形シートとして使用すると 364 * 判定します。 365 * 366 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 367 * 368 * @param refSheetName 参照シート名(nullの場合、参照シート使用する場合は、先頭のシート) 369 */ 370 public void setRefSheetName( final String refSheetName ) { 371 // 参照シート名の指定がない場合は、最初のシート 372 refSheetIdx = ( refSheetName == null ) ? 0 : wkbook.getSheetIndex( refSheetName ); 373 374 if( refSheetIdx < 0 ) { // 参照シート名が存在しなかった。 375 final String errMsg = "指定の参照シート名は存在しませんでした。" + CR 376 + " inFilename=[" + inFilename + "] , refSheetName=[" + refSheetName + "]" + CR ; 377 throw new IllegalArgumentException( errMsg ); 378 } 379 } 380 381 /** 382 * 内部 Workbookより、新しいSheetを作ります。 383 * 384 * 先に雛形シートを指定している場合は、その雛形シートから作成します。 385 * 指定していない場合は、新しいシートを作成します。 386 * 雛形シートを参照する場合は、雛形シートそのものを返します。 387 * また、雛形シートの枚数を超える場合は、前の雛形シートをコピーします。 388 * 雛形シートが存在しない場合は、新しいシートを作成します。 389 * 390 * シート名は、重複チェックを行い、同じ名前のシートの場合は、(1),(2)が付けられます。 391 * shtName が null の場合は、"Sheet" が割り振られます。 392 * 393 * この処理を行うと、内部の Sheet にも、ここで作成された Sheet が設定されます。 394 * 395 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 396 * @og.rev 6.2.2.3 (2015/04/10) 雛形シートにそのままデータを書き込んでいく。 397 * @og.rev 6.5.0.0 (2016/09/30) 雛形シート名をそのまま使用する場合は、isOverwrite に、true を指定します。 398 * 399 * @param shtName シート名 (重複する場合は、(2)、(3)のような文字列を追加 、nullの場合は、"Sheet") 400 * @param isOverwrite 雛形シート名をそのまま使用する場合は、true を指定します。 401 */ 402 public void createSheet( final String shtName , final boolean isOverwrite ) { 403 // 参照シートを使う場合(整合性の問題で、両方ともチェックしておきます) 404 405 // 6.2.2.3 (2015/04/10) 雛形シートにそのままデータを書き込んでいく。 406 final int shtNo ; 407 if( refSheetIdx < 0 ) { // 雛形シートを使用しない。 408 sheet = wkbook.createSheet(); 409 shtNo = wkbook.getNumberOfSheets() - 1; 410 } 411 else if( refSheetIdx >= wkbook.getNumberOfSheets() ) { // シート数が雛形より超えている。 412 sheet = wkbook.cloneSheet( refSheetIdx-1 ); // 最後の雛形シートをコピーします。 413 shtNo = wkbook.getNumberOfSheets() - 1; 414 refSheetIdx++ ; 415 } 416 else { 417 sheet = wkbook.getSheetAt( refSheetIdx ); // 雛形シートをそのまま使用 418 shtNo = refSheetIdx; 419 refSheetIdx++ ; 420 } 421 422 // 6.5.0.0 (2016/09/30) 雛形シート名をそのまま使用する場合。 423 if( !isOverwrite ) { 424 setSheetName( shtNo , shtName ); 425 } 426 } 427 428 /** 429 * 内部 Workbook の指定のシート番号の Sheet の名前を設定します。 430 * 431 * 指定のシート名が、既存のシートになければ、そのまま設定します。 432 * すでに、同じ名前のシートが存在する場合は、そのシート名の後に 433 * (1)、(2)、(3)のような文字列を追加します。 434 * shtName が null の場合は、"Sheet" が割り振られます。 435 * 436 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 437 * @og.rev 6.2.5.1 (2015/06/12) シート名重複が自分自身の場合は、(1)等の追加は行わない。 438 * 439 * @param shtNo シート番号 440 * @param shtName シート名 (重複する場合は、(1)、(2)のような文字列を追加 、nullの場合は、"Sheet") 441 */ 442 public void setSheetName( final int shtNo, final String shtName ) { 443 String tempName = ( shtName == null ) ? DEF_SHEET_NAME : WorkbookUtil.createSafeSheetName( shtName ) ; 444 int cnt = 1; 445 446 // 6.2.5.1 (2015/06/12) シート名重複が自分自身の場合は、(1)等の追加は行わない。 447 // ※ EXCELのシート名は、大文字、小文字だけでなく、全角半角の区別もしない。 448 final String nowName = wkbook.getSheetName( shtNo ); 449 if( tempName != null && !tempName.equals( nowName ) ) { // 全く同一の場合は、何もしない。 450 if( shtNo == wkbook.getSheetIndex( tempName ) ) { // シート名判定が、自身の場合 451 wkbook.setSheetName( shtNo,tempName ); 452 } 453 else { 454 while( wkbook.getSheetIndex( tempName ) >= 0 ) { // シート名が存在している場合 455 tempName = WorkbookUtil.createSafeSheetName( shtName + "(" + cnt + ")" ); 456 if( tempName.length() >= 31 ) { // 重複時の追加文字分を減らす。 457 tempName = tempName.substring( 0,26 ) + "(" + cnt + ")" ; // cnt3桁まで可能 458 } 459 cnt++; 460 } 461 wkbook.setSheetName( shtNo,tempName ); 462 } 463 } 464 } 465 466 /** 467 * 内部 Workbook の 指定のSheet番号のシート名前を返します。 468 * 469 * シートが存在しない場合は、null を返します。 470 * 471 * この処理を行うと、内部の Sheet にも、ここで見つけた Sheet が設定されます。 472 * 473 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 474 * 475 * @param shtNo シート番号 476 * 477 * @return shtName シート名 478 */ 479 public String getSheetName( final int shtNo ) { 480 final int shLen = wkbook.getNumberOfSheets(); 481 482 String shtName = null; 483 if( shtNo < shLen ) { 484 sheet = wkbook.getSheetAt( shtNo ); // 現在の sheet に設定する。 485 shtName = sheet.getSheetName(); 486 } 487 488 return shtName ; 489 } 490 491 /** 492 * 内部 Workbook の 指定のSheet名のシート番号を返します。 493 * 494 * シートが存在しない場合は、-1 を返します。 495 * この処理を行うと、内部の Sheet にも、ここで見つけた Sheet が設定されます。 496 * シートが存在しない場合、内部の Sheet オブジェクトも null がセットされますのでご注意ください。 497 * 498 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 499 * 500 * @param shtName シート名 501 * 502 * @return シート番号(名前のシートがなければ、-1) 503 */ 504 public int getSheetNo( final String shtName ) { 505 sheet = wkbook.getSheet( shtName ); // シート名がマッチしなければ、null 506 507 return wkbook.getSheetIndex( shtName ) ; // シート名がマッチしなければ、-1 508 } 509 510 /** 511 * Excelの指定Sheetオブジェクトを削除します。 512 * 513 * 削除するシートは、シート番号でFrom-To形式で指定します。 514 * Fromも Toも、削除するシート番号を含みます。 515 * 例えば、0,3 と指定すると、0,1,2,3 の 4シート分を削除します。 516 * 517 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 518 * 519 * @param fromNo 削除する開始シート番号(含む) 520 * @param toNo 削除する終了シート番号(含む) 521 */ 522 public void removeSheet( final int fromNo,final int toNo ) { 523 for( int shtNo=toNo; shtNo>=fromNo; shtNo-- ) { // 逆順に処理します。 524 wkbook.removeSheetAt( shtNo ); 525 } 526 } 527 528 /** 529 * 内部 Workbookの 現在Sheet の最初の行番号を返します。 530 * 531 * 行は、0 から始まります。 532 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。 533 * 534 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 535 * 536 * @return 最初の行番号 537 */ 538 public int getFirstRowNum() { 539 return sheet.getFirstRowNum(); 540 } 541 542 /** 543 * 内部 Workbookの 現在Sheet の最後の行番号を返します。 544 * 545 * 最終行は、含みます。よって、行数は、getLastRowNum()+1になります。 546 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。 547 * 548 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 549 * 550 * @return 最後の行番号 551 */ 552 public int getLastRowNum() { 553 return sheet.getLastRowNum(); 554 } 555 556 /** 557 * Excelの指定行のRowオブジェクトを作成します。 558 * 559 * 指定行の Row オブジェクトが存在しない場合は、新規作成します。 560 * この処理を実行すると、指定行の Rowオブジェクトが内部 Row に設定されます。 561 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。 562 * 563 * この処理を行うと、内部の Rowオブジェクトが設定されます。 564 * 565 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 566 * 567 * @param rowNo 行の番号 568 */ 569 public void createRow( final int rowNo ) { 570 rowObj = sheet.getRow( rowNo ); 571 if( rowObj == null ) { rowObj = sheet.createRow( rowNo ); } 572 } 573 574 /** 575 * Excelの指定行以降の余計なRowオブジェクトを削除します。 576 * 577 * 指定行の Row オブジェクトから、getLastRowNum() までの行を、削除します。 578 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。 579 * 580 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 581 * 582 * @param startRowNum 指定以降の余計な行を削除 583 */ 584 public void removeRow( final int startRowNum ) { 585 final int stR = startRowNum; 586 final int edR = sheet.getLastRowNum(); 587 588 for( int rowNo=edR; rowNo>=stR && rowNo>=0; rowNo-- ) { // 逆順に処理します。 589 final Row rowObj = sheet.getRow( rowNo ); 590 if( rowObj != null ) { sheet.removeRow( rowObj ); } 591 } 592 } 593 594 /** 595 * Excelの処理中のRowオブジェクトの指定カラム以降の余計なCellオブジェクトを削除します。 596 * 597 * 指定行の Row オブジェクトから、getLastCellNum() までのカラムを、削除します。 598 * この処理は、内部Rowが作成されているか、null でない場合のみ実行できます。 599 * 600 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 601 * 602 * @param startCellNum 指定以降の余計なカラムを削除 603 */ 604 public void removeCell( final int startCellNum ) { 605 final int stC = startCellNum; 606 final int edC = rowObj.getLastCellNum(); 607 608 for( int colNo=edC; colNo>=stC; colNo-- ) { // 逆順に処理します。 609 final Cell colObj = rowObj.getCell( colNo ); 610 if( colObj != null ) { rowObj.removeCell( colObj ); } 611 } 612 } 613 614 /** 615 * row にあるセルのオブジェクト値を設定します。 616 * 617 * 行が存在しない場合、行を追加します。 618 * この処理を行うと、内部の Rowオブジェクトがなければ新規作成されます。 619 * 620 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 621 * 622 * @param vals 新しい配列値。 623 * @param rowNo 値が変更される行(無視されます) 624 */ 625 public void setValues( final String[] vals,final int rowNo ) { 626 if( rowObj == null ) { createRow( rowNo ); } 627 628 if( vals != null ) { 629 for( int colNo=0; colNo<vals.length; colNo++ ) { 630 setCellValue( vals[colNo],colNo ); 631 } 632 } 633 } 634 635 /** 636 * row にあるセルのオブジェクト値を設定します。 637 * 638 * 行が存在しない場合、行を追加します。 639 * 引数に、カラムがNUMBER型かどうかを指定することが出来ます。 640 * この処理を行うと、内部の Rowオブジェクトがなければ新規作成されます。 641 * 642 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 643 * 644 * @param vals 新しい配列値。 645 * @param rowNo 値が変更される行(無視されます) 646 * @param isNums セルが、NUMBER型の場合は、true/それ以外は、false 647 */ 648 public void setValues( final String[] vals,final int rowNo,final boolean[] isNums ) { 649 if( rowObj == null ) { createRow( rowNo ); } 650 651 if( vals != null ) { 652 for( int colNo=0; colNo<vals.length; colNo++ ) { 653 setCellValue( vals[colNo],colNo,isNums[colNo] ); 654 } 655 } 656 } 657 658 /** 659 * Excelの指定セルにデータを設定します。 660 * 661 * ここで設定する行は、現在の内部 Row です。 662 * Row を切り替えたい場合は、#createRow( int ) を呼び出してください。 663 * このメソッドでは、データを文字列型として設定します。 664 * この処理は、内部Rowが作成されているか、null でない場合のみ実行できます。 665 * 666 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 667 * 668 * @param dataVal String文字列 669 * @param colNo セルの番号(0,1,2・・・・) 670 * @see #setCellValue( String,int,boolean ) 671 */ 672 public void setCellValue( final String dataVal , final int colNo ) { 673 setCellValue( dataVal,colNo,false ); 674 } 675 676 /** 677 * Excelの指定セルにデータを設定します。 678 * 679 * ここで設定する行は、現在の内部 Row です。 680 * Row を切り替えたい場合は、#createRow( int ) を呼び出してください。 681 * このメソッドでは、引数のデータ型をNUMBER型の場合は、doubleに変換して、 682 * それ以外は文字列としてとして設定します。 683 * この処理は、内部Rowが作成されているか、null でない場合のみ実行できます。 684 * 685 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 686 * 687 * @param dataVal String文字列 688 * @param colNo セルの番号(0,1,2・・・・) 689 * @param isNumber セルが、NUMBER型の場合は、true/それ以外は、false 690 * @see #createRow( int ) 691 * @see #setCellValue( String,int ) 692 */ 693 public void setCellValue( final String dataVal , final int colNo , final boolean isNumber ) { 694 Cell colObj = rowObj.getCell( colNo ); 695 if( colObj == null ) { colObj = rowObj.createCell( colNo ); } 696 697 if( style != null ) { colObj.setCellStyle(style); } 698 699 // CELL_TYPE_NUMERIC 以外は、String扱いします。 700 if( isNumber ) { 701 final Double dbl = parseDouble( dataVal ); 702 if( dbl != null ) { 703 colObj.setCellValue( dbl.doubleValue() ); 704 return ; // Double 変換できた場合は、即抜けます。 705 } 706 } 707 708 final RichTextString richText = createHelper.createRichTextString( dataVal ); 709 colObj.setCellValue( richText ); 710 } 711 712 /** 713 * Excelの指定セルにHyperlinkを設定します。 714 * 715 * ここで設定する行は、現在の内部 Row です。 716 * Row を切り替えたい場合は、#createRow( int ) を呼び出してください。 717 * このメソッドで設定するHyperlinkは、Sheetに対する LINK_DOCUMENT です。 718 * 先に、セルに対する値をセットしておいてください。 719 * Hyperlinkは、文字に対して、下線 と 青字 のスタイル設定を行います。 720 * 721 * Link文字列(シート名) が、null や ゼロ文字列の場合は、処理を行いません。 722 * 723 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 724 * @og.rev 6.5.0.0 (2016/09/30) poi-3.15 対応(Hyperlink.LINK_XXXX → HyperlinkType.XXXX) 725 * 726 * @param linkVal Link文字列(シート名) 727 * @param colNo セルの番号(0,1,2・・・・) 728 * @see #setCellValue( String,int ) 729 */ 730 public void setCellLink( final String linkVal , final int colNo ) { 731 if( linkVal == null || linkVal.isEmpty() ) { return; } 732 733 Cell colObj = rowObj.getCell( colNo ); 734 if( colObj == null ) { colObj = rowObj.createCell( colNo ); } 735 736 if( hLinkStyle == null ) { 737 hLinkStyle = wkbook.createCellStyle(); 738 if( style != null ) { hLinkStyle.cloneStyleFrom(style); } 739 740 final Font font = wkbook.createFont(); 741 font.setColor( IndexedColors.BLUE.getIndex() ); // リンクは青文字 742 font.setUnderline( Font.U_SINGLE ); // 下線付 743 744 hLinkStyle.setFont( font ); 745 } 746 colObj.setCellStyle(hLinkStyle); 747 748 // final Hyperlink hLink = createHelper.createHyperlink( Hyperlink.LINK_DOCUMENT ); // 6.5.0.0 (2016/09/30) poi-3.12 749 final Hyperlink hLink = createHelper.createHyperlink( HyperlinkType.DOCUMENT ); // 6.5.0.0 (2016/09/30) poi-3.15 750 hLink.setAddress( "'" + linkVal + "'!A1" ); 751 colObj.setHyperlink( hLink ); 752 } 753 754 /** 755 * 現在のRow にあるセルの属性値を配列で返します。 756 * 757 * Rowオブジェクトが存在しない場合は、長さ0の配列を返します。 758 * また、Rowオブジェクトの中の セルオブジェクトが存在しない場合は、 759 * null がセットされます。 760 * 761 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。 762 * この処理を実行すると、指定行の Rowオブジェクトが内部 Row に設定されます。 763 * 764 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 765 * @og.rev 6.3.9.0 (2015/11/06) ExcelModel#getValues(int) では、nullは返さない。 766 * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の1か所にすべきです(PMD)。 767 * 768 * @param rowNo 行の番号 769 * @return 指定されたセルの属性値。Rowがnullの場合は、長さ0の配列を返します。 770 * @og.rtnNotNull 771 */ 772 public String[] getValues( final int rowNo ) { 773 rowObj = sheet.getRow( rowNo ); 774 775 final int len = rowObj == null ? 0 : rowObj.getLastCellNum(); // 含まないので、length と同じ意味になる。 776 final String[] vals = new String[len]; // 6.3.9.1 (2015/11/27) メソッドの出口 777 778 for( int colNo=0; colNo<len; colNo++ ) { 779 final Cell colObj = rowObj.getCell( colNo ); 780 vals[colNo] = POIUtil.getValue( colObj ); 781 } 782 783 return vals ; 784 } 785 786 /** 787 * 現在のrow にあるセルの属性値を返します。 788 * 789 * セルオブジェクトが存在しない場合は、null を返します。 790 * 791 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。 792 * この処理を実行すると、指定行の Rowオブジェクトが内部 Row に設定されます。 793 * 794 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 795 * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の1か所にすべきです(PMD)。 796 * 797 * @param rowNo 値が参照される行 798 * @param colNo 値が参照される列 799 * 800 * @return 指定されたセルの値 T 801 */ 802 public String getValue( final int rowNo, final int colNo ) { 803 rowObj = sheet.getRow( rowNo ); 804 805 return rowObj == null ? null : POIUtil.getValue( rowObj.getCell( colNo ) ); 806 } 807 808 /** 809 * 指定のシートの行・列の箇所に、イメージファイルを挿入します。 810 * 811 * ここでは、セル範囲ではなく、指定の行列の箇所に、アンカーを設定して、画像ファイルを 812 * 挿入します。一応、リサイズして、元の大きさ近くに戻しますが、縦横比が変わってしまいます。 813 * 正確に挿入する場合は、セル範囲の指定と、マージンを指定しなければなりませんが、 814 * 微調整が必要です。 815 * 816 * この処理で使用される Sheetオブジェクトは一時的に作成されます。(キャッシュされません) 817 * 一連処理のどのタイミングで実行しても、内部の状態には影響はありません。 818 * 819 * @og.rev 6.0.2.3 (2014/10/10) 新規作成 820 * 821 * @param imgFile 挿入するイメージファイル名 822 * @param shtNo シート番号 823 * @param rowNo 挿入する行 824 * @param colNo 挿入する列 825 */ 826 public void addImageFile( final String imgFile, final int shtNo, final int rowNo, final int colNo ) { 827 addImageFile( imgFile,shtNo,rowNo,colNo,rowNo,colNo,0,0,0,0 ); 828 } 829 830 /** 831 * 指定のシートの行・列の箇所に、イメージファイルを挿入します。 832 * 833 * ここでは、セル範囲ではなく、指定の行列の箇所に、アンカーを設定して、画像ファイルを 834 * 挿入します。一応、リサイズして、元の大きさ近くに戻しますが、縦横比が変わってしまいます。 835 * 正確に挿入する場合は、セル範囲の指定と、マージンを指定しなければなりませんが、 836 * 微調整が必要です。 837 * 838 * この処理で使用される Sheetオブジェクトは一時的に作成されます。(キャッシュされません) 839 * 一連処理のどのタイミングで実行しても、内部の状態には影響はありません。 840 * 841 * @og.rev 6.0.2.3 (2014/10/10) 新規作成 842 * @og.rev 6.4.6.0 (2016/05/27) poi-3.15 準備 843 * @og.rev 6.8.2.4 (2017/11/20) poi-3.17 で、警告: [rawtypes] raw型が見つかりました対応 844 * @og.rev 7.2.9.0 (2020/10/12) ClientAnchorのオフセット指定は、Units.EMU_PER_PIXEL が単位 845 * 846 * @param imgFile 挿入するイメージファイル名 847 * @param shtNo シート番号 848 * @param row1 挿入する行(開始) 849 * @param col1 挿入する列(開始) 850 * @param row2 挿入する行(終了-含まず) 851 * @param col2 挿入する列(終了-含まず) 852 * @param dx1 開始セルのX軸座標のオフセット(ピクセル) 853 * @param dy1 開始セルのY軸座標のオフセット(ピクセル) 854 * @param dx2 終了セルのX軸座標のオフセット(ピクセル) 855 * @param dy2 終了セルのY軸座標のオフセット(ピクセル) 856 */ 857 public void addImageFile( final String imgFile , final int shtNo , 858 final int row1 , final int col1 , final int row2 , final int col2 , 859 final int dx1 , final int dy1 , final int dx2 , final int dy2 ) { 860 final String suffix = ImageUtil.getSuffix( imgFile ); 861 final Integer picType = PICTURE_TYPE.get( suffix ); 862 863 // 実験した結果、bmp,gif,tif については、PICTURE_TYPE_PNG で、挿入できた。 864 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..; 865 final int pictureType = picType == null ? Workbook.PICTURE_TYPE_PNG : picType.intValue() ; 866 867 final byte[] imgs = ImageUtil.byteImage( imgFile ); 868 869 final int pictureIdx = wkbook.addPicture( imgs, pictureType ); 870 871 final Sheet sheet = wkbook.getSheetAt( shtNo ); 872 // 6.8.2.4 (2017/11/20) poi-3.17 で、警告: [rawtypes] raw型が見つかりました対応 873 final Drawing<?> patriarch = sheet.createDrawingPatriarch(); // 昔は一度しか実行できなかったようです。 874 // final Drawing patriarch = sheet.createDrawingPatriarch(); // 昔は一度しか実行できなかったようです。 875 876// final ClientAnchor anchor = patriarch.createAnchor( dx1,dy1,dx2,dy2,col1,row1,col2,row2 ); 877 final int px = Units.EMU_PER_PIXEL; // 7.2.9.0 (2020/10/12) 878 final ClientAnchor anchor = patriarch.createAnchor( px*dx1,px*dy1,px*dx2,px*dy2,col1,row1,col2,row2 ); 879 880 // ClientAnchor anchor = createHelper.createClientAnchor(); でも作成可能。 881 882 // MOVE_AND_RESIZE, MOVE_DONT_RESIZE, DONT_MOVE_AND_RESIZE から、決め打ち。 883 // anchor.setAnchorType( ClientAnchor.MOVE_DONT_RESIZE ); // 6.4.6.0 (2016/05/27) poi-3.12 884 anchor.setAnchorType( ClientAnchor.AnchorType.MOVE_DONT_RESIZE ); // 6.4.6.0 (2016/05/27) poi-3.15 885 886 final Picture pic = patriarch.createPicture( anchor, pictureIdx ); 887 // セルの範囲指定がゼロの場合、画像サイズもゼロになる為、リサイズしておく。 888 if( row1 == row2 || col1 == col2 ) { pic.resize(); } // resize すると、anchor のマージンが無視されるようです。 889 } 890 891 /** 892 * 内部 Workbook オブジェクトをファイルに書き出します。 893 * 894 * Excelの形式は、ここで指定する出力ファイルの拡張子ではなく、コンストラクタで 895 * 指定したファイルの拡張子で決まります。 896 * 異なる形式の拡張子を持つファイルを指定した場合、強制的に、オープンした 897 * Workbook の形式の拡張子を追加します。 898 * 899 * 拡張子は、Excel 2007以降の形式(.xlsx)か、Excel 2003以前の形式(.xls) が指定できます。 900 * 拡張子が未設定の場合は、オープンした Workbook の形式に合わせた拡張子を付与します。 901 * 902 * isAutoCellSize=true の場合は、ここで全Sheetに対してCell幅の自動調整が行われます。 903 * 904 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 905 * @og.rev 6.1.0.0 (2014/12/26) 入力ファイルの拡張子判定の対応 906 * @og.rev 6.2.0.0 (2015/02/27) ファイル引数を、String → File に変更 907 * @og.rev 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。 908 * 909 * @param file セーブするファイル 910 */ 911 public void saveFile( final File file ) { 912 final File saveFile ; 913 String fname = file.getName(); 914 if( fname.toLowerCase(Locale.JAPAN).endsWith( sufix ) ) { 915 saveFile = file; 916 } 917 else { 918 final int idx = fname.lastIndexOf( '.' ); 919 if( idx >= 0 ) { fname = fname.substring( 0,idx ); } 920 saveFile = new File( file.getParent() , fname + sufix ); 921 } 922 923 if( isAutoCellSize ) { POIUtil.autoCellSize( wkbook, maxColCount, dataStartRow ); } 924 925 // 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。 926 if( recalcSheetNames != null && recalcSheetNames.length > 0 ) { 927 for( final String shtName : recalcSheetNames ) { 928 final Sheet sht = wkbook.getSheet( shtName ); // シート名がマッチしなければ、null 929 if( sht != null ) { sht.setForceFormulaRecalculation(true); } 930 } 931 } 932 933 // こちらの都合で、TitleSheet は、autoCellSize ではなく、Sheet#autoSizeColumn(int) を使用して、自動計算させる。 934 if( addTitleSheet != null ) { makeAddTitleSheet(); } 935 936 OutputStream fileOut = null ; 937 try { 938 fileOut = new BufferedOutputStream( new FileOutputStream( saveFile ) ); // 6.1.0.0 (2014/12/26) 939 wkbook.write( fileOut ); 940 } 941 catch( final IOException ex ) { 942 final String errMsg = "ファイルへ書込み中にエラーが発生しました。" + CR 943 + " File=" + saveFile + CR 944 + ex.getMessage() ; 945 throw new OgRuntimeException( errMsg,ex ); 946 } 947 finally { 948 Closer.ioClose( fileOut ); 949 } 950 } 951 952 /** 953 * 内部 Workbook オブジェクトのSheet一覧のSheetを、先頭に追加します。 954 * 955 * これは、Workbook に含まれる Sheet 一覧を作成する場合に、利用可能です。 956 * 957 * この処理は、内部のWorkbook、Sheetオブジェクトに依存して実行されます。 958 * また、単独ではなく、#saveFile( File ) 実行時に、addTitleSheet が 959 * 設定されている場合のみ、実行されます。 960 * 961 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 962 * 963 * @see #saveFile( File ) 964 * @see #setAddTitleSheet( String ) 965 */ 966 private void makeAddTitleSheet() { 967 sheet = wkbook.createSheet(); 968 final String shtNm = sheet.getSheetName(); // Sheet名の取得 969 wkbook.setSheetOrder( shtNm,0 ); // そのSheetを先頭に移動 970 setSheetName( 0,addTitleSheet ); // そのSheet名を変更 → これが、TitleSheet 971 972 int rowNo = 0; 973 createRow( rowNo++ ); // 先頭行(インスタンス共通のRowオブジェクト)作成 974 setCellValue( "No" , 0 ); 975 setCellValue( "Sheet", 1 ); 976 977 final int shCnt = wkbook.getNumberOfSheets(); 978 for( int shtNo=1; shtNo<shCnt; shtNo++,rowNo++ ) { 979 final String nm = wkbook.getSheetName( shtNo ); 980 981 createRow( rowNo ); // 行の追加作成 982 setCellValue( String.valueOf( rowNo ),0,true ); // 行番号として、数字型で登録 983 setCellValue( nm , 1 ); // シートの値を書き込む 984 setCellLink( nm , 1 ); // シートへのリンクを作成する。 985 } 986 987 sheet.autoSizeColumn( 0 ); 988 sheet.autoSizeColumn( 1 ); 989 } 990 991 /** 992 * 指定の Workbook の全Sheetを対象に、実際の有効行と有効カラムを取得します。 993 * 994 * ※ 現在、唯一LibreOfficeでのみ、xslx 変換できますが、有効行とカラムが 995 * シュリンクされず、無駄な行とカラムが存在します。 996 * これは、xsl で出力されたファイルから有効な値を取得して、xslxに適用させるための 997 * 機能で、本来きちんとした有効範囲の xslx が生成されれば、不要な処理です。 998 * 999 * 配列は、[0]=行の最大値(Sheet#getLastRowNum())と、[1]は有効行の中の列の 1000 * 最大値(Row#getLastCellNum())を、シートごとにListに追加していきます。 1001 * 1002 * @og.rev 8.0.1.0 (2021/10/29) 全Sheetを対象に、実際の有効行と有効カラムを取得 1003 * 1004 * @return シートごとの有効行の配列リスト 1005 * @see #activeWorkbook( List<int[]> ) 1006 */ 1007 public List<int[]> getLastRowCellNum() { 1008 return POIUtil.getLastRowCellNum( wkbook ); 1009 } 1010 1011 /** 1012 * Workbook の全Sheetを対象に、空行を取り除き、全体をシュリンクします。 1013 * 1014 * この処理は、#saveFile( File ) の直前に行うのがよいでしょう。 1015 * 1016 * ここでは、Row を逆順にスキャンし、Cellが 存在しない間は、行を削除します。 1017 * 途中の空行の削除ではなく、最終行からの連続した空行の削除です。 1018 * 1019 * isCellDel=true を指定すると、Cellの末尾削除を行います。 1020 * 有効行の最後のCellから空セルを削除していきます。 1021 * 表形式などの場合は、Cellのあるなしで、レイアウトが崩れる場合がありますので 1022 * 処理が不要な場合は、isCellDel=false を指定してください。 1023 * 1024 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 1025 * 1026 * @param isCellDel Cellの末尾削除を行うかどうか(true:行う/false:行わない) 1027 */ 1028 public void activeWorkbook( final boolean isCellDel ) { 1029 POIUtil.activeWorkbook( wkbook, isCellDel ); 1030 } 1031 1032 /** 1033 * 指定の Workbook の全Sheetを対象に、実際の有効行と有効カラムを元に全体をシュリンクします。 1034 * 1035 * ※ 現在、唯一LibreOfficeでのみ、xslx 変換できますが、有効行とカラムが 1036 * シュリンクされず、無駄な行とカラムが存在します。 1037 * これは、xsl で出力されたファイルから有効な値を取得して、xslxに適用させるための 1038 * 機能で、本来きちんとした有効範囲の xslx が生成されれば、不要な処理です。 1039 * 1040 * 引数のListオブジェクトに従って、無条件に処理を行います。 1041 * 1042 * @og.rev 8.0.1.0 (2021/10/29) 全Sheetを対象に、実際の有効行と有効カラムを取得 1043 * 1044 * @param rcList シートごとの有効行の配列リスト 1045 * @see #getLastRowCellNum() 1046 * @see #activeWorkbook( boolean ) 1047 */ 1048 public void activeWorkbook( final List<int[]> rcList ) { 1049 POIUtil.activeWorkbook( wkbook, rcList ); 1050 } 1051 1052 /** 1053 * Workbook の全Sheetを対象に、テキスト変換処理を行います(XSLX限定)。 1054 * 1055 * この処理は、#saveFile( File ) の直前に行うのがよいでしょう。 1056 * #activeWorkbook( boolean ) との順番は構いません。 1057 * 1058 * ・シート名の一覧をピックアップします。 1059 * ・セル値を、セル単位にピックアップします。 1060 * ・オブジェクト文字列を、改行単位にピックアップし、結果を合成します。 1061 * 1062 * ここでは、内部的に、TextConverterインターフェースを作成して処理します。 1063 * 1064 * @og.rev 6.2.4.2 (2015/05/29) テキスト変換処理 1065 * @og.rev 6.3.1.0 (2015/06/28) TextConverterに、引数(cmnt)を追加 1066 * @og.rev 6.3.9.0 (2015/11/06) Java 8 ラムダ式に変更 1067 * 1068 * @param convMap 変換対象を管理するMapオブジェクト 1069 * @see #textConverter( TextConverter ) 1070 */ 1071 public void textConverter( final Map<String,String> convMap ) { 1072 textConverter( 1073 ( val,cmnt ) -> convMap.get( val ) 1074 ); 1075 1076 // textConverter( 1077 // new TextConverter<String,String>() { 1078 // /** 1079 // * 入力文字列を、変換します。 1080 // * 1081 // * @param val 入力文字列 1082 // * @param cmnt コメント 1083 // * @return 変換文字列(変換されない場合は、null) 1084 // */ 1085 // @Override 1086 // public String change( final String val , final String cmnt ) { 1087 // return convMap.get( val ); 1088 // } 1089 // } 1090 // ); 1091 } 1092 1093 /** 1094 * Workbook の全Sheetを対象に、テキスト変換処理を行います(XSLX限定)。 1095 * 1096 * この処理は、#saveFile( File ) の直前に行うのがよいでしょう。 1097 * #activeWorkbook( boolean ) との順番は構いません。 1098 * 1099 * ・シート名の一覧をピックアップします。 1100 * ・セル値を、セル単位内の改行単位にピックアップし、結果を合成ます。 1101 * ・オブジェクト文字列を、改行単位にピックアップし、結果を合成します。 1102 * 1103 * ここでは、シート名、セルテキスト、SimpleShapeオブジェクトのテキストを 1104 * input に、TextConverterインターフェース の change メソッドを呼び出します。 1105 * 戻り値が、null でないなら、元のデータと置き換えます。 1106 * 戻り値が、null の場合は、そのまま読み飛ばします。(なにもしません) 1107 * EXCELへの書き戻しが発生しますので、万一、ファイル破損で、開けなくなる場合を 1108 * 想定して、バックアップファイルは、各自で準備してください。 1109 * 1110 * @og.rev 6.2.4.2 (2015/05/29) テキスト変換処理 1111 * @og.rev 6.2.5.0 (2015/06/05) xsl形式のオブジェクト取得…はできなかった。 1112 * @og.rev 6.3.1.0 (2015/06/28) TextConverterに、引数(cmnt)を追加 1113 * @og.rev 6.3.9.0 (2015/11/06) セルに値をセットするときに、セルタイプを考慮する。 1114 * 1115 * @param conv TextConverterインターフェース 1116 * @see #textConverter( Map ) 1117 */ 1118 @SuppressWarnings(value={"deprecation"}) // poi-3.15 1119 public void textConverter( final TextConverter<String,String> conv ) { 1120 // if( ".xlsx".equals( sufix ) || ".xlsm".equals( sufix ) ) { 1121 final int shCnt = wkbook.getNumberOfSheets(); 1122 for( int shtNo=0; shtNo<shCnt; shtNo++ ) { 1123 final Sheet sht = wkbook.getSheetAt( shtNo ); 1124 // シート名の変換 1125 final String shtNm = conv.change( sht.getSheetName() , "Sheet" ); 1126 if( shtNm != null ) { 1127 setSheetName( shtNo,shtNm ); // 同一シート対策済みのメソッドを呼び出す。 1128 } 1129 1130 // セル値の変換 1131 final int stR = Math.max( sht.getFirstRowNum(),0 ); // stR が、マイナスのケースがある。 1132 final int edR = sht.getLastRowNum(); 1133 1134 for( int rowNo=stR; rowNo<=edR; rowNo++ ) { 1135 final Row rowObj = sht.getRow( rowNo ); 1136 if( rowObj != null ) { 1137 final int stC = Math.max( rowObj.getFirstCellNum(),0 ); // stC が、マイナスのケースがある。 1138 final int edC = rowObj.getLastCellNum(); 1139 for( int colNo=stC; colNo<=edC; colNo++ ) { 1140 final Cell colObj = rowObj.getCell( colNo ); 1141// if( colObj != null && colObj.getCellType() != Cell.CELL_TYPE_BLANK ) { // 6.5.0.0 (2016/09/30) poi-3.12 1142// if( colObj != null && colObj.getCellTypeEnum() != CellType.BLANK ) { // 6.5.0.0 (2016/09/30) poi-3.15 1143 if( colObj != null && colObj.getCellType() != CellType.BLANK ) { // 8.0.0.0 (2021/07/31) poi-4.1.2.jar → poi-5.0.0.jar 1144 final String cmnt= "Sht" + shtNo + ":" + POIUtil.getCelKigo( rowNo,colNo ); 1145 final String val = crConv( conv, POIUtil.getValue( colObj ),cmnt ); // 改行対応 1146 if( val != null ) { 1147 POIUtil.setValue( colObj,val ); // 6.3.9.0 (2015/11/06) 1148 // colObj.setCellValue( val ); 1149 } 1150 } 1151 } 1152 } 1153 } 1154 1155 // オブジェクト文字列の変換 1156 if( sht instanceof POIXMLDocumentPart ) { 1157 for( final POIXMLDocumentPart pxdp : ((POIXMLDocumentPart)sht).getRelations() ) { 1158 if( pxdp instanceof XSSFDrawing ) { 1159 for( final XSSFShape shape : ((XSSFDrawing)pxdp).getShapes() ) { 1160 final org.apache.poi.xssf.usermodel.XSSFAnchor anc = shape.getAnchor(); 1161 final String ancSt = "XY(" + anc.getDx1() + "-" + anc.getDy1() + ")" ; 1162 int cnt = 0; 1163 if( shape instanceof XSSFSimpleShape ) { 1164 for( final XSSFTextParagraph para : ((XSSFSimpleShape)shape).getTextParagraphs() ) { 1165 for( final XSSFTextRun text : para.getTextRuns() ) { 1166 final String cmnt= "Sht" + shtNo + ":" + ancSt + ":Tb(" + cnt++ + ")" ; 1167 final String val = crConv( conv,text.getText() , cmnt ); 1168 if( val != null ) { 1169 text.setText( val ); 1170 } 1171 } 1172 } 1173 } 1174 } 1175 } 1176 } 1177 } 1178 // 6.2.5.0 (2015/06/05) xsl形式のオブジェクト取得…はできなかった。 1179 // else if( sht instanceof HSSFSheet ) { 1180 // HSSFPatriarch patri = ((HSSFSheet)sht).getDrawingPatriarch(); 1181 // for( final HSSFShape shape : patri.getChildren() ) { 1182 // if( shape instanceof HSSFTextbox ) { 1183 // HSSFRichTextString rts = ((HSSFSimpleShape)shape).getString(); 1184 // if( rts != null ) { 1185 // final String val = crConv( conv,rts.getString() ); 1186 // if( val != null ) { 1187 // HSSFRichTextString rts2 = new HSSFRichTextString( val ); 1188 // ((HSSFSimpleShape)shape).setString( rts2 ); 1189 // } 1190 // } 1191 // } 1192 // } 1193 // } 1194 } 1195 // } 1196 } 1197 1198 /** 1199 * 現在のシートを選択済み(true)か、非選択済み(false)に設定します。 1200 * 1201 * 通常は、シートは、先頭シート以外は、非選択状態になっています。 1202 * シートを選択済みにすることで、印刷範囲を指定する事ができます。 1203 * 1204 * @og.rev 6.3.9.0 (2015/11/06) 新規追加 1205 * 1206 * @param isSelect true:シート選択/false:非選択 1207 */ 1208 public void sheetSelected( final boolean isSelect ) { 1209 sheet.setSelected( isSelect ); 1210 } 1211 1212 /** 1213 * Workbook の雛形シートのTextConverter した、新しいSheetを作成します。 1214 * 1215 * 正確には、 1216 * 1.雛形シートを、コピーして、新しいSheet(shtName)を、作成します。 1217 * 2.雛形シートが指定されていない場合は、一番最後のシートをコピーします。 1218 * 2.そのシートに対して、TextConverter を行い、文字列変換します。 1219 * 1220 * @og.rev 6.3.9.0 (2015/11/06) 新規追加 1221 * @og.rev 6.5.0.0 (2016/09/30) poi-3.15 対応(Cell.CELL_TYPE_XXXX → CellType.XXXX) 1222 * 1223 * @param conv TextConverterインターフェース 1224 * @param shtName シート名 1225 * @see #textConverter( Map ) 1226 */ 1227 @SuppressWarnings(value={"deprecation"}) // poi-3.15 1228 public void sheetCopy( final TextConverter<String,String> conv , final String shtName ) { 1229 int shtNo = wkbook.getNumberOfSheets() - 1; 1230 if( refSheetIdx >= 0 && refSheetIdx < shtNo ) { // 雛形シートをコピーする。 1231 sheet = wkbook.cloneSheet( refSheetIdx ); 1232 } 1233 else { 1234 sheet = wkbook.cloneSheet( shtNo ); // 最後のシートをコピーします。 1235 } 1236 shtNo++ ; // シート番号を増やしておく。 1237 1238 // シート名の変換 1239 setSheetName( shtNo,shtName ); // 同一シート対策済みのメソッドを呼び出す。 1240 1241 // セル値の変換 1242 final int stR = Math.max( sheet.getFirstRowNum(),0 ); // stR が、マイナスのケースがある。 1243 final int edR = sheet.getLastRowNum(); 1244 1245 for( int rowNo=stR; rowNo<=edR; rowNo++ ) { 1246 final Row rowObj = sheet.getRow( rowNo ); 1247 if( rowObj != null ) { 1248 final int stC = Math.max( rowObj.getFirstCellNum(),0 ); // stC が、マイナスのケースがある。 1249 final int edC = rowObj.getLastCellNum(); 1250 for( int colNo=stC; colNo<=edC; colNo++ ) { 1251 final Cell colObj = rowObj.getCell( colNo ); 1252// if( colObj != null && colObj.getCellType() != Cell.CELL_TYPE_BLANK ) { // 6.5.0.0 (2016/09/30) poi-3.12 1253// if( colObj != null && colObj.getCellTypeEnum() != CellType.BLANK ) { // 6.5.0.0 (2016/09/30) poi-3.15 1254 if( colObj != null && colObj.getCellType() != CellType.BLANK ) { // 8.0.0.0 (2021/07/31) poi-4.1.2.jar → poi-5.0.0.jar 1255 final String val = crConv( conv, POIUtil.getValue( colObj ),null ); // 改行対応 1256 if( val != null ) { 1257 POIUtil.setValue( colObj,val ); 1258 // colObj.setCellValue( val ); 1259 } 1260 } 1261 } 1262 } 1263 } 1264 1265 // オブジェクト文字列の変換 1266 if( sheet instanceof POIXMLDocumentPart ) { 1267 for( final POIXMLDocumentPart pxdp : ((POIXMLDocumentPart)sheet).getRelations() ) { 1268 if( pxdp instanceof XSSFDrawing ) { 1269 for( final XSSFShape shape : ((XSSFDrawing)pxdp).getShapes() ) { 1270 // final org.apache.poi.xssf.usermodel.XSSFAnchor anc = shape.getAnchor(); 1271 if( shape instanceof XSSFSimpleShape ) { 1272 for( final XSSFTextParagraph para : ((XSSFSimpleShape)shape).getTextParagraphs() ) { 1273 for( final XSSFTextRun text : para.getTextRuns() ) { 1274 final String val = crConv( conv,text.getText() , null ); 1275 if( val != null ) { 1276 text.setText( val ); 1277 } 1278 } 1279 } 1280 } 1281 } 1282 } 1283 } 1284 } 1285 } 1286 1287 /** 1288 * Workbook の全Sheetを対象に、テキスト変換処理を行います(XSLX限定)。 1289 * 1290 * この処理は、#saveFile( File ) の直前に行うのがよいでしょう。 1291 * #activeWorkbook( boolean ) との順番は構いません。 1292 * 1293 * ・シート名の一覧をピックアップします。 1294 * ・セル値を、セル単位内の改行単位にピックアップし、結果を合成ます。 1295 * ・オブジェクト文字列を、改行単位にピックアップし、結果を合成します。 1296 * 1297 * ここでは、シート名、セルテキスト、SimpleShapeオブジェクトのテキストを 1298 * input に、TextConverterインターフェース の change メソッドを呼び出します。 1299 * 戻り値が、null でないなら、元のデータと置き換えます。 1300 * 戻り値が、null の場合は、そのまま読み飛ばします。(なにもしません) 1301 * EXCELへの書き戻しが発生しますので、万一、ファイル破損で、開けなくなる場合を 1302 * 想定して、バックアップファイルは、各自で準備してください。 1303 * 1304 * @og.rev 6.2.4.2 (2015/05/29) テキスト変換処理 1305 * @og.rev 6.3.1.0 (2015/06/28) TextConverterに、引数(cmnt)を追加 1306 * 1307 * @param conv TextConverterインターフェース 1308 * @param val 改行処理を行う元の値 1309 * @param cmnt コメント 1310 * @return 改行処理の結果の値(対象が無ければ、null) 1311 * @see #textConverter( Map ) 1312 */ 1313 private String crConv( final TextConverter<String,String> conv , final String val , final String cmnt ) { 1314 String rtn = null; 1315 if( val != null ) { 1316 if( val.contains( "\n" ) ) { // 改行がある場合(EXCEL のセル内改行コードは、LF(0A)=\n のみ。 1317 final String[] val2 = val.split( "\\n" ); // 改行で分割する。 1318 boolean flag = false; 1319 for( int i=0; i<val2.length; i++ ) { 1320 final String val3 = conv.change( val2[i],cmnt ); // 6.3.1.0 (2015/06/28) 1321 if( val3 != null ) { val2[i] = val3; flag = true; } 1322 } 1323 if( flag ) { 1324 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 1325 buf.append( val2[0] ); 1326 for( int i=1; i<val2.length; i++ ) { 1327 buf.append( '\n' ).append( val2[i] ); // LF(\n)で、セパレートしているので、LF のみ追加する。 1328 } 1329 rtn = buf.toString(); 1330 } 1331 } 1332 else { // 改行がない場合 1333 rtn = conv.change( val,cmnt ); // 6.3.1.0 (2015/06/28) 1334 } 1335 } 1336 return rtn; 1337 } 1338 1339 /** 1340 * シート一覧を、内部の Workbook から取得します。 1341 * 1342 * 取得元が、Workbook なので、xls , xlsx どちらの形式でも取り出せます。 1343 * 1344 * EXCEL上のシート名を、配列で返します。 1345 * 1346 * @og.rev 6.2.6.0 (2015/06/19) 新規作成 1347 * 1348 * @return シート名の配列 1349 * @see POIUtil#getSheetNames( Workbook ) 1350 */ 1351 public String[] getSheetNames() { 1352 return POIUtil.getSheetNames( wkbook ); 1353 } 1354 1355 /** 1356 * 名前定義一覧を内部の Workbook から取得します。 1357 * 1358 * EXCEL上に定義された名前を、配列で返します。 1359 * ここでは、名前とFormulaをタブで連結した文字列を配列で返します。 1360 * Name オブジェクトを削除すると、EXCELが開かなくなったりするので、 1361 * 取りあえず一覧を作成して、手動で削除してください。 1362 * なお、名前定義には、非表示というのがありますので、ご注意ください。 1363 * 1364 * @og.rev 6.2.6.0 (2015/06/19) 新規作成 1365 * 1366 * @return 名前定義(名前+TAB+Formula)の配列 1367 * @see POIUtil#getNames( Workbook ) 1368 * @og.rtnNotNull 1369 */ 1370 public String[] getNames() { 1371 return POIUtil.getNames( wkbook ); 1372 } 1373 1374 /** 1375 * 書式のスタイル一覧を内部の Workbook から取得します。 1376 * 1377 * EXCEL上に定義された書式のスタイルを、配列で返します。 1378 * 書式のスタイルの名称は、CellStyle にメソッドが定義されていません。 1379 * 実クラスである HSSFCellStyle にキャストして使用する 1380 * 必要があります。(XSSFCellStyle にも名称を取得するメソッドがありません。) 1381 * 1382 * ※ EXCEL2010 ホームタブ→セルのスタイル は、一つづつしか削除できません。 1383 * マクロは、開発タブ→Visual Basic で、挿入→標準モジュール を開き 1384 * テキストを張り付けてください。 1385 * 実行は、開発タブ→マクロ で、マクロ名を選択して、実行します。 1386 * 最後は、削除してください。 1387 * 1388 * @og.rev 6.2.6.0 (2015/06/19) 新規作成 1389 * 1390 * @return 書式のスタイル一覧 1391 * @see POIUtil#getStyleNames( Workbook ) 1392 * @og.rtnNotNull 1393 */ 1394 public String[] getStyleNames() { 1395 return POIUtil.getStyleNames( wkbook ); 1396 } 1397 1398 /** 1399 * 文字列を Double オブジェクトに変換します。 1400 * 1401 * これは、引数の カンマ(,) を削除した文字列から、Double オブジェクトを生成します。 1402 * 処理中に、文字列が解析可能な double を含まない場合(NumberFormatException) 1403 * また、引数が、null,ゼロ文字列,'_', エラー の時には、null を返します。 1404 * 1405 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 1406 * @og.rev 6.3.9.0 (2015/11/06) もう少し判りやすくする。(処理速度は落ちてます。) 1407 * 1408 * @param value Doubleに変換する元の文字列 1409 * 1410 * @return 変換後のDoubleオブジェクト(エラー発生時や変換不可の場合は、null) 1411 */ 1412 private Double parseDouble( final String value ) { 1413 Double rtn = null ; 1414 1415 try { 1416 if( value == null || value.isEmpty() || value.equals( "_" ) ) { 1417 rtn = null; 1418 } 1419 else if( value.indexOf( ',' ) < 0 ) { 1420 rtn = Double.valueOf( value ); // 6.0.2.4 (2014/10/17) メソッドが非効率だった。 1421 } 1422 else { 1423 // 6.3.9.0 (2015/11/06) もう少し判りやすくする。(処理速度は落ちてます。) 1424 rtn = Double.valueOf( value.replaceAll( ",","" ) ); 1425 } 1426 } 1427 catch( final NumberFormatException ex ) { // 文字列が解析可能な数値を含まない場合 1428 final String errMsg = "Double変換できませんでした。" + CR 1429 + ex.getMessage() + CR 1430 + " value=" + value; 1431 System.err.println( errMsg ); 1432 rtn = null; 1433 } 1434 1435 return rtn ; 1436 } 1437 1438 /** 1439 * アプリケーションのサンプルです。 1440 * 1441 * Usage: java org.opengion.fukurou.model.ExcelModel 入力ファイル名 [出力ファイル名] ・・・ 1442 * 通常は標準出力に行単位に、セルをタブ区切り出力します。 1443 * 出力ファイル名 を指定すると、EXCEL ファイルとしてセーブし直します。 1444 * その場合は、以下のパラメータも使用できます。 1445 * -CS CellStyleを 設定します。 1446 * -AS useAutoCellSizeを 設定します。 1447 * -FN=*** FontNameを 設定します。 1448 * -FP=** FontPointを 設定します。 1449 * -IMG 画像ファイルを挿入します。(-IMG 画像ファイル名 シート番号 行 列)をスペース区切りで続けます。 1450 * 1451 * @og.rev 6.0.2.0 (2014/09/19) 新規作成 1452 * 1453 * @param args コマンド引数配列 1454 */ 1455 public static void main( final String[] args ) { 1456 if( args.length == 0 ) { 1457 final String usage = "Usage: java org.opengion.fukurou.model.ExcelModel 入力ファイル名 [出力ファイル名] ・・・\n" + 1458 "\t-CS CellStyleを 設定します。 \n" + 1459 "\t-TC TextConverterを実行します。 \n" + 1460 "\t-AS useAutoCellSizeを 設定します。 \n" + 1461 "\t-FN=*** FontNameを 設定します。 \n" + 1462 "\t-FP=** FontPointを 設定します。 \n" + 1463 "\t-IMG 画像ファイルを挿入します。 \n" + 1464 "\t (-IMG ファイル名 シート番号 行 列) \n" ; 1465 System.err.println( usage ); 1466 return ; 1467 } 1468 1469 final ExcelModel excel = new ExcelModel( new File( args[0] ) , true ); 1470 1471 excel.activeWorkbook( true ); // 余計な行を削除します。 1472 1473 if( args.length > 1 ) { 1474 final File outFile = new File( args[1] ); // 6.2.0.0 (2015/02/27) 1475 boolean isCS = false; 1476 boolean isAS = false; 1477 boolean isTC = false; // 6.2.4.2 (2015/05/29) テキスト変換処理 1478 String fn = null; 1479 short fp = -1; 1480 1481 for( int i=2; i<args.length; i++ ) { 1482 final String prm = args[i]; 1483 1484 if( "-CS".equalsIgnoreCase( prm ) ) { isCS = true; } // 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase. 1485 if( "-AS".equalsIgnoreCase( prm ) ) { isAS = true; } // 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase. 1486 if( "-TC".equalsIgnoreCase( prm ) ) { isTC = true; } // 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase. 1487 if( prm.startsWith( "-FN" ) ) { fn = prm.substring( 3 ); } 1488 if( prm.startsWith( "-FP" ) ) { fp = Short.parseShort( prm.substring( 3 ) ); } 1489 if( "-IMG".equalsIgnoreCase( prm ) ) { // 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase. 1490 final String img = args[++i]; 1491 final int shtNo = Integer.parseInt( args[++i] ); 1492 final int rowNo = Integer.parseInt( args[++i] ); 1493 final int colNo = Integer.parseInt( args[++i] ); 1494 1495 excel.addImageFile( img,shtNo,rowNo,colNo ); 1496 } 1497 } 1498 1499 if( isCS ) { excel.setCellStyle(); } 1500 excel.useAutoCellSize( isAS ); 1501 excel.setFont( fn,fp ); 1502 1503 // 6.2.4.2 (2015/05/29) テキスト変換処理 1504 if( isTC ) { 1505 // 6.3.9.0 (2015/11/06) Java 8 ラムダ式に変更 1506 // 処理が複数行に別れるのは判りにくいので良くない。 1507 excel.textConverter( 1508 ( val,cmnt ) -> { 1509 System.out.println( val ); // すべてのテキストを読み取る。 1510 return null; // 変換せず。 1511 } 1512 ); 1513 } 1514 1515 excel.saveFile( outFile ); 1516 } 1517 else { 1518 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 1519 1520 final int shLen = excel.getNumberOfSheets(); 1521 for( int shtNo=0; shtNo<shLen; shtNo++ ) { 1522 final String shtName = excel.getSheetName( shtNo ); 1523 1524 final int stRow = excel.getFirstRowNum(); 1525 final int edRow = excel.getLastRowNum(); 1526 for( int rowNo=stRow; rowNo<=edRow; rowNo++ ) { 1527 buf.setLength(0); // Clearの事 1528 buf.append( shtName ).append( '\t' ).append( rowNo ); 1529 final String[] vals = excel.getValues( rowNo ); 1530 if( vals != null ) { 1531 for( int colNo=0; colNo<vals.length; colNo++ ) { 1532 final String val = vals[colNo] == null ? "" : vals[colNo]; 1533 buf.append( '\t' ).append( val ); 1534 } 1535 } 1536 System.out.println( buf ); 1537 } 1538 System.out.println(); 1539 } 1540 } 1541 } 1542}