2 * Copyright (c) 2009 The openGion Project.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 * either express or implied. See the License for the specific language
14 * governing permissions and limitations under the License.
16 package org.opengion.fukurou.model;
18 import java.io.File; // 6.2.0.0 (2015/02/27)
19 import java.io.IOException;
20 import java.io.OutputStream;
21 import java.io.FileOutputStream;
22 import java.io.BufferedOutputStream;
23 import java.util.Locale;
24 import java.util.Map; // 6.0.2.3 (2014/10/10) 画像関連
25 import java.util.HashMap; // 6.0.2.3 (2014/10/10) 画像関連
26 import java.util.List; // 8.0.1.0 (2021/10/29)
27 import java.util.function.BiConsumer; // 8.1.0.1 (2022/01/07)
29 import org.apache.poi.util.Units; // 7.2.9.0 (2020/10/12)
31 import org.apache.poi.common.usermodel.HyperlinkType; // 6.5.0.0 (2016/09/30) poi-3.15
32 import org.apache.poi.ss.util.WorkbookUtil;
33 import org.apache.poi.ss.usermodel.Workbook;
34 import org.apache.poi.ss.usermodel.Sheet;
35 import org.apache.poi.ss.usermodel.Row;
36 import org.apache.poi.ss.usermodel.Cell;
37 import org.apache.poi.ss.usermodel.CellType; // 6.5.0.0 (2016/09/30) poi-3.15
38 import org.apache.poi.ss.usermodel.CellStyle;
39 import org.apache.poi.ss.usermodel.VerticalAlignment; // 6.5.0.0 (2016/09/30) poi-3.15
40 import org.apache.poi.ss.usermodel.BorderStyle; // 6.5.0.0 (2016/09/30) poi-3.15
41 import org.apache.poi.ss.usermodel.Font;
42 import org.apache.poi.ss.usermodel.IndexedColors;
43 import org.apache.poi.ss.usermodel.RichTextString;
44 import org.apache.poi.ss.usermodel.Hyperlink;
45 import org.apache.poi.ss.usermodel.CreationHelper;
46 import org.apache.poi.ss.usermodel.Drawing; // 6.0.2.3 (2014/10/10) 画像関連
47 import org.apache.poi.ss.usermodel.Shape; // 8.0.3.1 (2021/12/28) 画像関連
48 import org.apache.poi.ss.usermodel.ClientAnchor; // 6.0.2.3 (2014/10/10) 画像関連
49 import org.apache.poi.ss.usermodel.Picture; // 6.0.2.3 (2014/10/10) 画像関連
51 import org.apache.poi.hssf.usermodel.HSSFWorkbook; // .xls
53 // import org.apache.poi.POIXMLDocumentPart; // 6.2.4.2 (2015/05/29) テキスト変換処理 8.1.2.3 (2022/05/20) 復活
54 import org.apache.poi.ooxml.POIXMLDocumentPart; // 7.0.0.0 (2018/10/01) poi-ooxml-3.17.jar → poi-ooxml-4.0.0.jar 8.1.2.3 (2022/05/20) 復活
56 import org.apache.poi.xssf.usermodel.XSSFDrawing; // 6.2.4.2 (2015/05/29) テキスト変換処理 8.1.2.3 (2022/05/20) 復活
57 import org.apache.poi.xssf.usermodel.XSSFShape; // 6.2.4.2 (2015/05/29) テキスト変換処理
58 import org.apache.poi.xssf.usermodel.XSSFSimpleShape; // 6.2.4.2 (2015/05/29) テキスト変換処理
59 import org.apache.poi.xssf.usermodel.XSSFShapeGroup; // 8.0.3.1 (2021/12/28)
60 import org.apache.poi.xssf.usermodel.XSSFTextParagraph; // 6.2.4.2 (2015/05/29) テキスト変換処理 8.1.2.3 (2022/05/20) 復活
61 import org.apache.poi.xssf.usermodel.XSSFTextRun; // 6.2.4.2 (2015/05/29) テキスト変換処理 8.1.2.3 (2022/05/20) 復活
62 import org.apache.poi.xssf.usermodel.XSSFAnchor; // .xslx 8.1.2.3 (2022/05/20)
63 import org.apache.poi.xssf.usermodel.XSSFClientAnchor; // 8.5.0.0 (2023/04/21) XSSFAnchor オブジェクトの NullPointerException 対策
64 import org.apache.poi.xssf.streaming.SXSSFWorkbook; // .xlsx 6.3.7.0 (2015/09/04) 制限あり 高速、低メモリ消費
66 import org.opengion.fukurou.system.OgRuntimeException ; // 6.4.2.0 (2016/01/29)
67 import org.opengion.fukurou.system.Closer;
68 import org.opengion.fukurou.util.ImageUtil; // 6.0.2.3 (2014/10/10) 画像関連
70 import static org.opengion.fukurou.system.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring
71 import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.1.0.0 (2014/12/26) refactoring
74 * POI による、EXCELバイナリファイルに対する、データモデルクラスです。
76 * 共通的な EXCEL処理 を集約しています。
77 * staticメソッドによる簡易的なアクセスの他に、順次処理も可能なように
78 * 現在アクセス中の、Workbook、Sheet、Row、Cell オブジェクトを内部で管理しています。
80 * 入力形式は、openXML形式にも対応しています。
81 * ファイルの内容に応じて、.xlsと.xlsxのどちらで読み取るかは、内部的に
84 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
85 * @og.rev 8.1.2.3 (2022/05/20) テキスト変換処理 復活
89 * @author Kazuhiko Hasegawa
92 public class ExcelModel {
93 /** このプログラムのVERSION文字列を設定します。 {@value} */
94 private static final String VERSION = "8.5.0.0 (2023/04/21)" ;
96 private static final String DEF_SHEET_NAME = "Sheet" ;
98 // 6.0.2.3 (2014/10/10) ImageUtil の Suffix と、Workbook.PICTURE_TYPE_*** の関連付けをしておきます。
99 // Suffix 候補は、[bmp, gif, jpeg, jpg, png, wbmp] だが、対応する PICTURE_TYPE は一致しない。
100 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
101 private static final Map<String,Integer> PICTURE_TYPE ;
103 PICTURE_TYPE = new HashMap<>() ;
104 PICTURE_TYPE.put( "png" , Integer.valueOf( Workbook.PICTURE_TYPE_PNG ) );
105 PICTURE_TYPE.put( "jpeg" , Integer.valueOf( Workbook.PICTURE_TYPE_JPEG ) );
106 PICTURE_TYPE.put( "jpg" , Integer.valueOf( Workbook.PICTURE_TYPE_JPEG ) );
109 private final String inFilename ; // エラー発生時のキーとなる、EXCELファイル名
110 private final String sufix ; // 6.1.0.0 (2014/12/26) オープンしたファイル形式を記憶(ピリオドを含む)
112 private final Workbook wkbook ; // 現在処理中の Workbook
113 private Sheet sheet ; // 現在処理中の Sheet
114 private Row rowObj ; // 現在処理中の Row
116 private int refSheetIdx = -1; // 雛形シートのインデックス
118 private final CreationHelper createHelper ; // poi.xssf対応
120 private CellStyle style ; // 共通のセルスタイル
121 private CellStyle hLinkStyle ; // Hyperlink用のセルスタイル(青文字+下線)
123 private int maxColCount = 5 ; // 標準セル幅の5倍を最大幅とする。
124 private int dataStartRow = -1; // データ行の開始位置。未設定時は、-1
125 private boolean isAutoCellSize ; // カラム幅の自動調整を行うかどうか(true:行う/false:行わない)
127 private String addTitleSheet ; // Sheet一覧を先頭Sheetに作成する場合のSheet名
129 private String[] recalcSheetNames ; // 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせるシート名の配列。
132 * EXCELファイルのWookbookのデータ処理モデルを作成します。
134 * ここでは、既存のファイルを読み込んで、データ処理モデルを作成しますので、
135 * ファイルがオープンできなければエラーになります。
137 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
138 * @og.rev 6.2.0.0 (2015/02/27) ファイル引数を、String → File に変更
140 * @param file EXCELファイル
141 * @see #ExcelModel( File , boolean )
143 public ExcelModel( final File file ) {
148 * EXCELファイルのWookbookのデータ処理モデルを作成します。
150 * isOpen条件によって、ファイルオープン(true)か、新規作成(false)が分かれます。
151 * ファイルオープンの場合は、EXCELの読み込み以外に、追記するとか、雛形参照する
153 * ファイルオープンの場合は、当然、ファイルがオープンできなければエラーになります。
155 * isOpen=新規作成(false) の場合は、ファイル名の拡張子で、XSSFWorkbook か HSSFWorkbook を
156 * 判定します。.xlsx の場合⇒XSSFWorkbook オブジェクトを使用します。
158 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
159 * @og.rev 6.0.2.3 (2014/10/10) POIUtil#createWorkbook( String ) を使用するように変更
160 * @og.rev 6.1.0.0 (2014/12/26) 入力ファイルの拡張子判定の対応
161 * @og.rev 6.2.0.0 (2015/02/27) ファイル引数を、String → File に変更
162 * @og.rev 6.2.2.0 (2015/03/27) マクロ付Excel(.xlsm)対応
163 * @og.rev 6.3.7.0 (2015/09/04),5.9.0.0 (2015/09/04) 標準を、SXSSFWorkbook に切り替えてみる。
165 * @param file EXCELファイル
166 * @param isOpen true:ファイルオープン/false:新規作成
167 * @see #ExcelModel( File )
169 public ExcelModel( final File file , final boolean isOpen ) {
170 inFilename = file.getName();
172 final int idx = inFilename.lastIndexOf( '.' ); // 拡張子の位置
174 sufix = inFilename.substring( idx ).toLowerCase( Locale.JAPAN ); // ピリオドを含む
177 final String errMsg = "ファイルの拡張子が見当たりません。(.xls か .xlsx/.xlsm を指定下さい)" + CR
178 + " filename=[" + file + "]" + CR ;
179 throw new IllegalArgumentException( errMsg );
183 wkbook = POIUtil.createWorkbook( file );
186 // 新規の場合、ファイル名に.xlsxで終了した場合⇒.xlsx形式ファイル作成、その他⇒.xls形式ファイル作成
187 if( ".xlsx".equals( sufix ) || ".xlsm".equals( sufix ) ) { // 6.2.2.0 (2015/03/27)
188 // 6.3.7.0 (2015/09/04),5.9.0.0 (2015/09/04) 標準を、SXSSFWorkbook に切り替えてみる。
189 // wkbook = new XSSFWorkbook();
190 wkbook = new SXSSFWorkbook(); // 機能制限有:シートや行の削除や、AutoCellSize の指定ができないなど。
192 else if( ".xls".equals( sufix ) ) {
193 wkbook = new HSSFWorkbook();
196 final String errMsg = "ファイルの拡張子が不正です。(.xls か .xlsx/.xlsm のみ可能)" + CR
197 + " filename=[" + file + "]" + CR ;
198 throw new IllegalArgumentException( errMsg );
202 createHelper = wkbook.getCreationHelper(); // poi.xssf対応
206 * 内部 Workbook に、フォント名、フォントサイズを設定します。
207 * fontName(フォント名)は、"MS Pゴシック" など名称になります。
208 * fontPoint は、フォントの大きさを指定します。
209 * 内部的には、setFontHeightInPoints(short)メソッドで設定します。
211 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
213 * @param fontName フォント名 ("MS Pゴシック" など。nullの場合セットしません)
214 * @param fontPoint フォントの大きさ (0やマイナスの場合はセットしません)
216 public void setFont( final String fontName , final short fontPoint ) {
217 // System.out.println( "FontName=" + fontName + " , Point=" + fontPoint );
219 if( style == null ) { style = wkbook.createCellStyle(); }
221 final Font font = wkbook.createFont();
222 // final Font font = wkbook.getFontAt( style.getFontIndex() ); // A,B などのヘッダーもフォントが
223 if( fontName != null ) {
224 font.setFontName( fontName ); // "MS Pゴシック" など
226 if( fontPoint > 0 ) {
227 font.setFontHeightInPoints( fontPoint );
230 style.setFont( font );
234 * データ設定する セルに、罫線を追加します。
236 * ここで設定するのは、罫線の種類と、罫線の色ですが、内部的に固定にしています。
237 * Border=CellStyle.BORDER_THIN
238 * BorderColor=IndexedColors.BLACK
240 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
241 * @og.rev 6.5.0.0 (2016/09/30) poi-3.15 対応(Cell.CELL_TYPE_XXXX → CellType.XXXX)
243 public void setCellStyle() {
244 if( style == null ) { style = wkbook.createCellStyle(); }
246 // style.setBorderBottom( CellStyle.BORDER_THIN ); // 6.5.0.0 (2016/09/30) poi-3.12
247 // style.setBorderLeft( CellStyle.BORDER_THIN ); // 6.5.0.0 (2016/09/30) poi-3.12
248 // style.setBorderRight( CellStyle.BORDER_THIN ); // 6.5.0.0 (2016/09/30) poi-3.12
249 // style.setBorderTop( CellStyle.BORDER_THIN ); // 6.5.0.0 (2016/09/30) poi-3.12
251 style.setBorderBottom( BorderStyle.THIN ); // 6.4.6.0 (2016/05/27) poi-3.15
252 style.setBorderLeft( BorderStyle.THIN ); // 6.5.0.0 (2016/09/30) poi-3.15
253 style.setBorderRight( BorderStyle.THIN ); // 6.5.0.0 (2016/09/30) poi-3.15
254 style.setBorderTop( BorderStyle.THIN ); // 6.5.0.0 (2016/09/30) poi-3.15
256 style.setBottomBorderColor( IndexedColors.BLACK.getIndex() );
257 style.setLeftBorderColor( IndexedColors.BLACK.getIndex() );
258 style.setRightBorderColor( IndexedColors.BLACK.getIndex() );
259 style.setTopBorderColor( IndexedColors.BLACK.getIndex() );
261 // style.setVerticalAlignment( CellStyle.VERTICAL_TOP ); // isAutoCellSize=true 文字は上寄せする。 // 6.5.0.0 (2016/09/30) poi-3.12
262 style.setVerticalAlignment( VerticalAlignment.TOP ); // isAutoCellSize=true 文字は上寄せする。 // 6.5.0.0 (2016/09/30) poi-3.15
263 // style.setWrapText( true ); // isAutoCellSize=true 折り返して表示する。
267 * 全てのSheetに対して、autoSizeColumn設定を行うかどうか指定します(初期値:false)。
269 * autoSize設定で、カラム幅が大きすぎる場合、現状では、
270 * 初期カラム幅の5倍を限度にしています。
272 * なお、autoSizeColumn設定は負荷の大きな処理なので、saveFile(String)の
273 * 中で実行されます。(セーブしなければ実行されません。)
274 * よって、指定は、いつ行っても構いません。
276 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
278 * @param flag autoSizeColumn設定を行うかどうか [true:自動カラム幅設定を行う/false:行わない]
279 * @see #useAutoCellSize( boolean,int )
281 public void useAutoCellSize( final boolean flag ) {
282 isAutoCellSize = flag;
286 * 全てのSheetに対して、autoSizeColumn設定を行うかどうか指定します(初期値:false)。
288 * autoSize設定で、カラム幅が大きすぎる場合、現状では、
289 * 初期カラム幅のcount倍を限度に設定します。
290 * ただし、count がマイナスの場合は、無制限になります。
292 * なお、autoSizeColumn設定は負荷の大きな処理なので、saveFile(String)の
293 * 中で実行されます。(セーブしなければ実行されません。)
294 * よって、指定は、いつ行っても構いません。
296 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
298 * @param flag autoSizeColumn設定を行うかどうか [true:自動カラム幅設定を行う/false:行わない]
299 * @param count 最大幅を標準セル幅の何倍にするかを指定。マイナスの場合は、無制限
300 * @see #useAutoCellSize( boolean )
302 public void useAutoCellSize( final boolean flag, final int count ) {
303 isAutoCellSize = flag;
304 maxColCount = count ;
308 * EXCELで、出力処理の最後にセルの計算式の再計算をさせるシート名の配列を指定します。
311 * なお、再計算は、saveFile(String)の中で実行されます。(セーブしなければ実行されません。)
313 * @og.rev 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。
315 * @param sheets 対象シート名の配列
317 public void setRecalcSheetName( final String[] sheets ){
318 recalcSheetNames = sheets;
322 * データ行の書き込み開始位置の行番号を設定します。
324 * これは、autoSize設定で、自動調整するカラムを、ヘッダーではなく、
325 * データ部で計算する場合に使用します。
327 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
329 * @param st データ行の開始位置。未設定時は、-1
330 * @see #useAutoCellSize( boolean )
332 public void setDataStartRow( final int st ) {
337 * Sheet一覧を先頭Sheetに作成する場合のSheet名を指定します。
339 * これは、Workbook に含まれる Sheet 一覧を作成する場合に、利用可能です。
341 * この処理は、#saveFile( File ) 処理時に、実行されます。
343 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
345 * @param shtName Sheet一覧のSheet名
346 * @see #makeAddTitleSheet()
348 public void setAddTitleSheet( final String shtName ) {
349 addTitleSheet = shtName;
353 * 内部 Workbookの Sheet数を返します。
355 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
359 public int getNumberOfSheets() {
360 return wkbook.getNumberOfSheets();
364 * 内部 Workbookより、雛形Sheetをセットします。
366 * これは、雛形シートを使用する場合に、使います。このメソッドが呼ばれると、
368 * 雛形シート名が、内部 Workbook に存在しない場合は、エラーになります。
369 * ただし、null をセットした場合は、最初のシートを雛形シートとして使用すると
372 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
374 * @param refSheetName 参照シート名(nullの場合、参照シート使用する場合は、先頭のシート)
376 public void setRefSheetName( final String refSheetName ) {
377 // 参照シート名の指定がない場合は、最初のシート
378 refSheetIdx = ( refSheetName == null ) ? 0 : wkbook.getSheetIndex( refSheetName );
380 if( refSheetIdx < 0 ) { // 参照シート名が存在しなかった。
381 final String errMsg = "指定の参照シート名は存在しませんでした。" + CR
382 + " inFilename=[" + inFilename + "] , refSheetName=[" + refSheetName + "]" + CR ;
383 throw new IllegalArgumentException( errMsg );
388 * 内部 Workbookより、新しいSheetを作ります。
390 * 先に雛形シートを指定している場合は、その雛形シートから作成します。
391 * 指定していない場合は、新しいシートを作成します。
392 * 雛形シートを参照する場合は、雛形シートそのものを返します。
393 * また、雛形シートの枚数を超える場合は、前の雛形シートをコピーします。
394 * 雛形シートが存在しない場合は、新しいシートを作成します。
396 * シート名は、重複チェックを行い、同じ名前のシートの場合は、(1),(2)が付けられます。
397 * shtName が null の場合は、"Sheet" が割り振られます。
399 * この処理を行うと、内部の Sheet にも、ここで作成された Sheet が設定されます。
401 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
402 * @og.rev 6.2.2.3 (2015/04/10) 雛形シートにそのままデータを書き込んでいく。
403 * @og.rev 6.5.0.0 (2016/09/30) 雛形シート名をそのまま使用する場合は、isOverwrite に、true を指定します。
405 * @param shtName シート名 (重複する場合は、(2)、(3)のような文字列を追加 、nullの場合は、"Sheet")
406 * @param isOverwrite 雛形シート名をそのまま使用する場合は、true を指定します。
408 public void createSheet( final String shtName , final boolean isOverwrite ) {
409 // 参照シートを使う場合(整合性の問題で、両方ともチェックしておきます)
411 // 6.2.2.3 (2015/04/10) 雛形シートにそのままデータを書き込んでいく。
413 if( refSheetIdx < 0 ) { // 雛形シートを使用しない。
414 sheet = wkbook.createSheet();
415 shtNo = wkbook.getNumberOfSheets() - 1;
417 else if( refSheetIdx >= wkbook.getNumberOfSheets() ) { // シート数が雛形より超えている。
418 sheet = wkbook.cloneSheet( refSheetIdx-1 ); // 最後の雛形シートをコピーします。
419 shtNo = wkbook.getNumberOfSheets() - 1;
423 sheet = wkbook.getSheetAt( refSheetIdx ); // 雛形シートをそのまま使用
428 // 6.5.0.0 (2016/09/30) 雛形シート名をそのまま使用する場合。
430 setSheetName( shtNo , shtName );
435 * 内部 Workbook の指定のシート番号の Sheet の名前を設定します。
437 * 指定のシート名が、既存のシートになければ、そのまま設定します。
438 * すでに、同じ名前のシートが存在する場合は、そのシート名の後に
439 * (1)、(2)、(3)のような文字列を追加します。
440 * shtName が null の場合は、"Sheet" が割り振られます。
442 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
443 * @og.rev 6.2.5.1 (2015/06/12) シート名重複が自分自身の場合は、(1)等の追加は行わない。
446 * @param shtName シート名 (重複する場合は、(1)、(2)のような文字列を追加 、nullの場合は、"Sheet")
448 public void setSheetName( final int shtNo, final String shtName ) {
449 String tempName = ( shtName == null ) ? DEF_SHEET_NAME : WorkbookUtil.createSafeSheetName( shtName ) ;
452 // 6.2.5.1 (2015/06/12) シート名重複が自分自身の場合は、(1)等の追加は行わない。
453 // ※ EXCELのシート名は、大文字、小文字だけでなく、全角半角の区別もしない。
454 final String nowName = wkbook.getSheetName( shtNo );
455 if( tempName != null && !tempName.equals( nowName ) ) { // 全く同一の場合は、何もしない。
456 if( shtNo == wkbook.getSheetIndex( tempName ) ) { // シート名判定が、自身の場合
457 wkbook.setSheetName( shtNo,tempName );
460 while( wkbook.getSheetIndex( tempName ) >= 0 ) { // シート名が存在している場合
461 tempName = WorkbookUtil.createSafeSheetName( shtName + "(" + cnt + ")" );
462 if( tempName.length() >= 31 ) { // 重複時の追加文字分を減らす。
463 tempName = tempName.substring( 0,26 ) + "(" + cnt + ")" ; // cnt3桁まで可能
467 wkbook.setSheetName( shtNo,tempName );
473 * 内部 Workbook の 指定のSheet番号のシート名前を返します。
475 * シートが存在しない場合は、null を返します。
477 * この処理を行うと、内部の Sheet にも、ここで見つけた Sheet が設定されます。
479 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
483 * @return shtName シート名
485 public String getSheetName( final int shtNo ) {
486 final int shLen = wkbook.getNumberOfSheets();
488 String shtName = null;
489 if( shtNo < shLen ) {
490 sheet = wkbook.getSheetAt( shtNo ); // 現在の sheet に設定する。
491 shtName = sheet.getSheetName();
498 * 内部 Workbook の 指定のSheet名のシート番号を返します。
500 * シートが存在しない場合は、-1 を返します。
501 * この処理を行うと、内部の Sheet にも、ここで見つけた Sheet が設定されます。
502 * シートが存在しない場合、内部の Sheet オブジェクトも null がセットされますのでご注意ください。
504 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
506 * @param shtName シート名
508 * @return シート番号(名前のシートがなければ、-1)
510 public int getSheetNo( final String shtName ) {
511 sheet = wkbook.getSheet( shtName ); // シート名がマッチしなければ、null
513 return wkbook.getSheetIndex( shtName ) ; // シート名がマッチしなければ、-1
517 * Excelの指定Sheetオブジェクトを削除します。
519 * 削除するシートは、シート番号でFrom-To形式で指定します。
520 * Fromも Toも、削除するシート番号を含みます。
521 * 例えば、0,3 と指定すると、0,1,2,3 の 4シート分を削除します。
523 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
525 * @param fromNo 削除する開始シート番号(含む)
526 * @param toNo 削除する終了シート番号(含む)
528 public void removeSheet( final int fromNo,final int toNo ) {
529 for( int shtNo=toNo; shtNo>=fromNo; shtNo-- ) { // 逆順に処理します。
530 wkbook.removeSheetAt( shtNo );
535 * 内部 Workbookの 現在Sheet の最初の行番号を返します。
538 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。
540 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
544 public int getFirstRowNum() {
545 return sheet.getFirstRowNum();
549 * 内部 Workbookの 現在Sheet の最後の行番号を返します。
551 * 最終行は、含みます。よって、行数は、getLastRowNum()+1になります。
552 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。
554 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
558 public int getLastRowNum() {
559 return sheet.getLastRowNum();
563 * Excelの指定行のRowオブジェクトを作成します。
565 * 指定行の Row オブジェクトが存在しない場合は、新規作成します。
566 * この処理を実行すると、指定行の Rowオブジェクトが内部 Row に設定されます。
567 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。
569 * この処理を行うと、内部の Rowオブジェクトが設定されます。
571 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
575 public void createRow( final int rowNo ) {
576 rowObj = sheet.getRow( rowNo );
577 if( rowObj == null ) { rowObj = sheet.createRow( rowNo ); }
581 * Excelの指定行以降の余計なRowオブジェクトを削除します。
583 * 指定行の Row オブジェクトから、getLastRowNum() までの行を、削除します。
584 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。
586 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
588 * @param startRowNum 指定以降の余計な行を削除
590 public void removeRow( final int startRowNum ) {
591 final int stR = startRowNum;
592 final int edR = sheet.getLastRowNum();
594 for( int rowNo=edR; rowNo>=stR && rowNo>=0; rowNo-- ) { // 逆順に処理します。
595 final Row rowObj = sheet.getRow( rowNo );
596 if( rowObj != null ) { sheet.removeRow( rowObj ); }
601 * Excelの処理中のRowオブジェクトの指定カラム以降の余計なCellオブジェクトを削除します。
603 * 指定行の Row オブジェクトから、getLastCellNum() までのカラムを、削除します。
604 * この処理は、内部Rowが作成されているか、null でない場合のみ実行できます。
606 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
608 * @param startCellNum 指定以降の余計なカラムを削除
610 public void removeCell( final int startCellNum ) {
611 final int stC = startCellNum;
612 final int edC = rowObj.getLastCellNum();
614 for( int colNo=edC; colNo>=stC; colNo-- ) { // 逆順に処理します。
615 final Cell colObj = rowObj.getCell( colNo );
616 if( colObj != null ) { rowObj.removeCell( colObj ); }
621 * row にあるセルのオブジェクト値を設定します。
624 * この処理を行うと、内部の Rowオブジェクトがなければ新規作成されます。
626 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
628 * @param vals 新しい配列値。
629 * @param rowNo 値が変更される行(無視されます)
631 public void setValues( final String[] vals,final int rowNo ) {
632 if( rowObj == null ) { createRow( rowNo ); }
635 for( int colNo=0; colNo<vals.length; colNo++ ) {
636 setCellValue( vals[colNo],colNo );
642 * row にあるセルのオブジェクト値を設定します。
645 * 引数に、カラムがNUMBER型かどうかを指定することが出来ます。
646 * この処理を行うと、内部の Rowオブジェクトがなければ新規作成されます。
648 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
650 * @param vals 新しい配列値。
651 * @param rowNo 値が変更される行(無視されます)
652 * @param isNums セルが、NUMBER型の場合は、true/それ以外は、false
654 public void setValues( final String[] vals,final int rowNo,final boolean[] isNums ) {
655 if( rowObj == null ) { createRow( rowNo ); }
658 for( int colNo=0; colNo<vals.length; colNo++ ) {
659 setCellValue( vals[colNo],colNo,isNums[colNo] );
665 * Excelの指定セルにデータを設定します。
667 * ここで設定する行は、現在の内部 Row です。
668 * Row を切り替えたい場合は、#createRow( int ) を呼び出してください。
669 * このメソッドでは、データを文字列型として設定します。
670 * この処理は、内部Rowが作成されているか、null でない場合のみ実行できます。
672 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
674 * @param dataVal String文字列
675 * @param colNo セルの番号(0,1,2・・・・)
676 * @see #setCellValue( String,int,boolean )
678 public void setCellValue( final String dataVal , final int colNo ) {
679 setCellValue( dataVal,colNo,false );
683 * Excelの指定セルにデータを設定します。
685 * ここで設定する行は、現在の内部 Row です。
686 * Row を切り替えたい場合は、#createRow( int ) を呼び出してください。
687 * このメソッドでは、引数のデータ型をNUMBER型の場合は、doubleに変換して、
688 * それ以外は文字列としてとして設定します。
689 * この処理は、内部Rowが作成されているか、null でない場合のみ実行できます。
691 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
693 * @param dataVal String文字列
694 * @param colNo セルの番号(0,1,2・・・・)
695 * @param isNumber セルが、NUMBER型の場合は、true/それ以外は、false
696 * @see #createRow( int )
697 * @see #setCellValue( String,int )
699 public void setCellValue( final String dataVal , final int colNo , final boolean isNumber ) {
700 Cell colObj = rowObj.getCell( colNo );
701 if( colObj == null ) { colObj = rowObj.createCell( colNo ); }
703 if( style != null ) { colObj.setCellStyle(style); }
705 // CELL_TYPE_NUMERIC 以外は、String扱いします。
707 final Double dbl = parseDouble( dataVal );
709 colObj.setCellValue( dbl.doubleValue() );
710 return ; // Double 変換できた場合は、即抜けます。
714 final RichTextString richText = createHelper.createRichTextString( dataVal );
715 colObj.setCellValue( richText );
719 * Excelの指定セルにHyperlinkを設定します。
721 * ここで設定する行は、現在の内部 Row です。
722 * Row を切り替えたい場合は、#createRow( int ) を呼び出してください。
723 * このメソッドで設定するHyperlinkは、Sheetに対する LINK_DOCUMENT です。
724 * 先に、セルに対する値をセットしておいてください。
725 * Hyperlinkは、文字に対して、下線 と 青字 のスタイル設定を行います。
727 * Link文字列(シート名) が、null や ゼロ文字列の場合は、処理を行いません。
729 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
730 * @og.rev 6.5.0.0 (2016/09/30) poi-3.15 対応(Hyperlink.LINK_XXXX → HyperlinkType.XXXX)
732 * @param linkVal Link文字列(シート名)
733 * @param colNo セルの番号(0,1,2・・・・)
734 * @see #setCellValue( String,int )
736 public void setCellLink( final String linkVal , final int colNo ) {
737 if( linkVal == null || linkVal.isEmpty() ) { return; }
739 Cell colObj = rowObj.getCell( colNo );
740 if( colObj == null ) { colObj = rowObj.createCell( colNo ); }
742 if( hLinkStyle == null ) {
743 hLinkStyle = wkbook.createCellStyle();
744 if( style != null ) { hLinkStyle.cloneStyleFrom(style); }
746 final Font font = wkbook.createFont();
747 font.setColor( IndexedColors.BLUE.getIndex() ); // リンクは青文字
748 font.setUnderline( Font.U_SINGLE ); // 下線付
750 hLinkStyle.setFont( font );
752 colObj.setCellStyle(hLinkStyle);
754 // final Hyperlink hLink = createHelper.createHyperlink( Hyperlink.LINK_DOCUMENT ); // 6.5.0.0 (2016/09/30) poi-3.12
755 final Hyperlink hLink = createHelper.createHyperlink( HyperlinkType.DOCUMENT ); // 6.5.0.0 (2016/09/30) poi-3.15
756 hLink.setAddress( "'" + linkVal + "'!A1" );
757 colObj.setHyperlink( hLink );
761 * 現在のRow にあるセルの属性値を配列で返します。
763 * Rowオブジェクトが存在しない場合は、長さ0の配列を返します。
764 * また、Rowオブジェクトの中の セルオブジェクトが存在しない場合は、
767 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。
768 * この処理を実行すると、指定行の Rowオブジェクトが内部 Row に設定されます。
770 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
771 * @og.rev 6.3.9.0 (2015/11/06) ExcelModel#getValues(int) では、nullは返さない。
772 * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の1か所にすべきです(PMD)。
775 * @return 指定されたセルの属性値。Rowがnullの場合は、長さ0の配列を返します。
778 public String[] getValues( final int rowNo ) {
779 rowObj = sheet.getRow( rowNo );
781 final int len = rowObj == null ? 0 : rowObj.getLastCellNum(); // 含まないので、length と同じ意味になる。
782 final String[] vals = new String[len]; // 6.3.9.1 (2015/11/27) メソッドの出口
784 for( int colNo=0; colNo<len; colNo++ ) {
785 final Cell colObj = rowObj.getCell( colNo );
786 vals[colNo] = POIUtil.getValue( colObj );
793 * 現在のrow にあるセルの属性値を返します。
795 * セルオブジェクトが存在しない場合は、null を返します。
797 * この処理は、内部Sheetが作成されているか、null でない場合のみ実行できます。
798 * この処理を実行すると、指定行の Rowオブジェクトが内部 Row に設定されます。
800 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
801 * @og.rev 6.3.9.1 (2015/11/27) メソッドの出口は、最後の1か所にすべきです(PMD)。
803 * @param rowNo 値が参照される行
804 * @param colNo 値が参照される列
806 * @return 指定されたセルの値 T
808 public String getValue( final int rowNo, final int colNo ) {
809 rowObj = sheet.getRow( rowNo );
811 return rowObj == null ? null : POIUtil.getValue( rowObj.getCell( colNo ) );
815 * 指定のシートの行・列の箇所に、イメージファイルを挿入します。
817 * ここでは、セル範囲ではなく、指定の行列の箇所に、アンカーを設定して、画像ファイルを
818 * 挿入します。一応、リサイズして、元の大きさ近くに戻しますが、縦横比が変わってしまいます。
819 * 正確に挿入する場合は、セル範囲の指定と、マージンを指定しなければなりませんが、
822 * この処理で使用される Sheetオブジェクトは一時的に作成されます。(キャッシュされません)
823 * 一連処理のどのタイミングで実行しても、内部の状態には影響はありません。
825 * @og.rev 6.0.2.3 (2014/10/10) 新規作成
827 * @param imgFile 挿入するイメージファイル名
832 public void addImageFile( final String imgFile, final int shtNo, final int rowNo, final int colNo ) {
833 addImageFile( imgFile,shtNo,rowNo,colNo,rowNo,colNo,0,0,0,0 );
837 * 指定のシートの行・列の箇所に、イメージファイルを挿入します。
839 * ここでは、セル範囲ではなく、指定の行列の箇所に、アンカーを設定して、画像ファイルを
840 * 挿入します。一応、リサイズして、元の大きさ近くに戻しますが、縦横比が変わってしまいます。
841 * 正確に挿入する場合は、セル範囲の指定と、マージンを指定しなければなりませんが、
844 * この処理で使用される Sheetオブジェクトは一時的に作成されます。(キャッシュされません)
845 * 一連処理のどのタイミングで実行しても、内部の状態には影響はありません。
847 * @og.rev 6.0.2.3 (2014/10/10) 新規作成
848 * @og.rev 6.4.6.0 (2016/05/27) poi-3.15 準備
849 * @og.rev 6.8.2.4 (2017/11/20) poi-3.17 で、警告: [rawtypes] raw型が見つかりました対応
850 * @og.rev 7.2.9.0 (2020/10/12) ClientAnchorのオフセット指定は、Units.EMU_PER_PIXEL が単位
852 * @param imgFile 挿入するイメージファイル名
854 * @param row1 挿入する行(開始)
855 * @param col1 挿入する列(開始)
856 * @param row2 挿入する行(終了-含まず)
857 * @param col2 挿入する列(終了-含まず)
858 * @param dx1 開始セルのX軸座標のオフセット(ピクセル)
859 * @param dy1 開始セルのY軸座標のオフセット(ピクセル)
860 * @param dx2 終了セルのX軸座標のオフセット(ピクセル)
861 * @param dy2 終了セルのY軸座標のオフセット(ピクセル)
863 public void addImageFile( final String imgFile , final int shtNo ,
864 final int row1 , final int col1 , final int row2 , final int col2 ,
865 final int dx1 , final int dy1 , final int dx2 , final int dy2 ) {
866 final String suffix = ImageUtil.getSuffix( imgFile );
867 final Integer picType = PICTURE_TYPE.get( suffix );
869 // 実験した結果、bmp,gif,tif については、PICTURE_TYPE_PNG で、挿入できた。
870 // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
871 final int pictureType = picType == null ? Workbook.PICTURE_TYPE_PNG : picType.intValue() ;
873 final byte[] imgs = ImageUtil.byteImage( imgFile );
875 final int pictureIdx = wkbook.addPicture( imgs, pictureType );
877 final Sheet sheet = wkbook.getSheetAt( shtNo );
878 // 6.8.2.4 (2017/11/20) poi-3.17 で、警告: [rawtypes] raw型が見つかりました対応
879 final Drawing<?> patriarch = sheet.createDrawingPatriarch(); // 昔は一度しか実行できなかったようです。
880 // final Drawing patriarch = sheet.createDrawingPatriarch(); // 昔は一度しか実行できなかったようです。
882 // final ClientAnchor anchor = patriarch.createAnchor( dx1,dy1,dx2,dy2,col1,row1,col2,row2 );
883 final int px = Units.EMU_PER_PIXEL; // 7.2.9.0 (2020/10/12)
884 final ClientAnchor anchor = patriarch.createAnchor( px*dx1,px*dy1,px*dx2,px*dy2,col1,row1,col2,row2 );
886 // ClientAnchor anchor = createHelper.createClientAnchor(); でも作成可能。
888 // MOVE_AND_RESIZE, MOVE_DONT_RESIZE, DONT_MOVE_AND_RESIZE から、決め打ち。
889 // anchor.setAnchorType( ClientAnchor.MOVE_DONT_RESIZE ); // 6.4.6.0 (2016/05/27) poi-3.12
890 anchor.setAnchorType( ClientAnchor.AnchorType.MOVE_DONT_RESIZE ); // 6.4.6.0 (2016/05/27) poi-3.15
892 final Picture pic = patriarch.createPicture( anchor, pictureIdx );
893 // セルの範囲指定がゼロの場合、画像サイズもゼロになる為、リサイズしておく。
894 if( row1 == row2 || col1 == col2 ) { pic.resize(); } // resize すると、anchor のマージンが無視されるようです。
898 * 内部 Workbook オブジェクトをファイルに書き出します。
900 * Excelの形式は、ここで指定する出力ファイルの拡張子ではなく、コンストラクタで
901 * 指定したファイルの拡張子で決まります。
902 * 異なる形式の拡張子を持つファイルを指定した場合、強制的に、オープンした
903 * Workbook の形式の拡張子を追加します。
905 * 拡張子は、Excel 2007以降の形式(.xlsx)か、Excel 2003以前の形式(.xls) が指定できます。
906 * 拡張子が未設定の場合は、オープンした Workbook の形式に合わせた拡張子を付与します。
908 * isAutoCellSize=true の場合は、ここで全Sheetに対してCell幅の自動調整が行われます。
910 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
911 * @og.rev 6.1.0.0 (2014/12/26) 入力ファイルの拡張子判定の対応
912 * @og.rev 6.2.0.0 (2015/02/27) ファイル引数を、String → File に変更
913 * @og.rev 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。
915 * @param file セーブするファイル
917 public void saveFile( final File file ) {
918 final File saveFile ;
919 String fname = file.getName();
920 if( fname.toLowerCase(Locale.JAPAN).endsWith( sufix ) ) {
924 final int idx = fname.lastIndexOf( '.' );
925 if( idx >= 0 ) { fname = fname.substring( 0,idx ); }
926 saveFile = new File( file.getParent() , fname + sufix );
929 if( isAutoCellSize ) { POIUtil.autoCellSize( wkbook, maxColCount, dataStartRow ); }
931 // 6.5.0.0 (2016/09/30) セルの計算式の再計算をさせる recalcSheetNames 属性の追加。
932 if( recalcSheetNames != null && recalcSheetNames.length > 0 ) {
933 for( final String shtName : recalcSheetNames ) {
934 final Sheet sht = wkbook.getSheet( shtName ); // シート名がマッチしなければ、null
935 if( sht != null ) { sht.setForceFormulaRecalculation(true); }
939 // こちらの都合で、TitleSheet は、autoCellSize ではなく、Sheet#autoSizeColumn(int) を使用して、自動計算させる。
940 if( addTitleSheet != null ) { makeAddTitleSheet(); }
942 OutputStream fileOut = null ;
944 fileOut = new BufferedOutputStream( new FileOutputStream( saveFile ) ); // 6.1.0.0 (2014/12/26)
945 wkbook.write( fileOut );
948 catch( final IOException ex ) {
949 final String errMsg = "ファイルへ書込み中にエラーが発生しました。" + CR
950 + " File=" + saveFile + CR
952 throw new OgRuntimeException( errMsg,ex );
955 Closer.ioClose( fileOut );
960 * 内部 Workbook オブジェクトのSheet一覧のSheetを、先頭に追加します。
962 * これは、Workbook に含まれる Sheet 一覧を作成する場合に、利用可能です。
964 * この処理は、内部のWorkbook、Sheetオブジェクトに依存して実行されます。
965 * また、単独ではなく、#saveFile( File ) 実行時に、addTitleSheet が
966 * 設定されている場合のみ、実行されます。
968 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
970 * @see #saveFile( File )
971 * @see #setAddTitleSheet( String )
973 private void makeAddTitleSheet() {
974 sheet = wkbook.createSheet();
975 final String shtNm = sheet.getSheetName(); // Sheet名の取得
976 wkbook.setSheetOrder( shtNm,0 ); // そのSheetを先頭に移動
977 setSheetName( 0,addTitleSheet ); // そのSheet名を変更 → これが、TitleSheet
980 createRow( rowNo++ ); // 先頭行(インスタンス共通のRowオブジェクト)作成
981 setCellValue( "No" , 0 );
982 setCellValue( "Sheet", 1 );
984 final int shCnt = wkbook.getNumberOfSheets();
985 for( int shtNo=1; shtNo<shCnt; shtNo++,rowNo++ ) {
986 final String nm = wkbook.getSheetName( shtNo );
988 createRow( rowNo ); // 行の追加作成
989 setCellValue( String.valueOf( rowNo ),0,true ); // 行番号として、数字型で登録
990 setCellValue( nm , 1 ); // シートの値を書き込む
991 setCellLink( nm , 1 ); // シートへのリンクを作成する。
994 sheet.autoSizeColumn( 0 );
995 sheet.autoSizeColumn( 1 );
999 // * 指定の Workbook の全Sheetを対象に、実際の有効行と有効カラムを取得します。
1001 // * ※ 現在、唯一LibreOfficeでのみ、xslx 変換できますが、有効行とカラムが
1002 // * シュリンクされず、無駄な行とカラムが存在します。
1003 // * これは、xsl で出力されたファイルから有効な値を取得して、xslxに適用させるための
1004 // * 機能で、本来きちんとした有効範囲の xslx が生成されれば、不要な処理です。
1006 // * 配列は、[0]=行の最大値(Sheet#getLastRowNum())と、[1]は有効行の中の列の
1007 // * 最大値(Row#getLastCellNum())を、シートごとにListに追加していきます。
1009 // * @og.rev 8.0.1.0 (2021/10/29) 全Sheetを対象に、実際の有効行と有効カラムを取得
1010 // * @og.rev 8.0.3.0 (2021/12/17) 処理が中途半端だったので、廃止します。
1012 // * @return シートごとの有効行の配列リスト
1013 // * @see #activeWorkbook( List )
1015 // public List<int[]> getLastRowCellNum() {
1016 // return POIUtil.getLastRowCellNum( wkbook );
1020 * Workbook の全Sheetを対象に、空行を取り除き、全体をシュリンクします。
1022 * この処理は、#saveFile( File ) の直前に行うのがよいでしょう。
1024 * ここでは、Row を逆順にスキャンし、Cellが 存在しない間は、行を削除します。
1025 * 途中の空行の削除ではなく、最終行からの連続した空行の削除です。
1027 * isCellDel=true を指定すると、Cellの末尾削除を行います。
1028 * 有効行の最後のCellから空セルを削除していきます。
1029 * 表形式などの場合は、Cellのあるなしで、レイアウトが崩れる場合がありますので
1030 * 処理が不要な場合は、isCellDel=false を指定してください。
1032 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
1034 * @param isCellDel Cellの末尾削除を行うかどうか(true:行う/false:行わない)
1036 public void activeWorkbook( final boolean isCellDel ) {
1037 POIUtil.activeWorkbook( wkbook, isCellDel );
1041 * 指定の Workbook の全Sheetを対象に、実際の有効行と有効カラムを元に全体をシュリンクします。
1043 * ※ 現在、唯一LibreOfficeでのみ、xslx 変換できますが、有効行とカラムが
1044 * シュリンクされず、無駄な行とカラムが存在します。
1045 * これは、xsl で出力されたファイルから有効な値を取得して、xslxに適用させるための
1046 * 機能で、本来きちんとした有効範囲の xslx が生成されれば、不要な処理です。
1048 * 引数のListオブジェクトに従って、無条件に処理を行います。
1050 * @og.rev 8.0.1.0 (2021/10/29) 全Sheetを対象に、実際の有効行と有効カラムを取得
1051 * @og.rev 8.0.3.0 (2021/12/17) シート毎の行数Listに変更。
1053 // * @param rcList シートごとの有効行の配列リスト
1054 * @param rowCntList シートごとの有効行の配列リスト
1055 // * @see #getLastRowCellNum()
1056 * @see #activeWorkbook( boolean )
1058 // public void activeWorkbook( final List<int[]> rcList ) {
1059 public void activeWorkbook( final List<Integer> rowCntList ) {
1060 POIUtil.activeWorkbook( wkbook, rowCntList );
1064 * Workbook の全Sheetを対象に、テキスト変換処理を行います(XSLX限定)。
1066 * この処理は、#saveFile( File ) の直前に行うのがよいでしょう。
1067 * #activeWorkbook( boolean ) との順番は構いません。
1069 * ・シート名の一覧をピックアップします。
1070 * ・セル値を、セル単位にピックアップします。
1071 * ・オブジェクト文字列を、改行単位にピックアップし、結果を合成します。
1073 * ここでは、内部的に、TextConverterインターフェースを作成して処理します。
1075 * @og.rev 6.2.4.2 (2015/05/29) テキスト変換処理
1076 * @og.rev 6.3.1.0 (2015/06/28) TextConverterに、引数(cmnt)を追加
1077 * @og.rev 6.3.9.0 (2015/11/06) Java 8 ラムダ式に変更
1079 * @param convMap 変換対象を管理するMapオブジェクト
1080 * @see #textConverter( TextConverter )
1082 public void textConverter( final Map<String,String> convMap ) {
1084 ( val,cmnt ) -> convMap.get( val )
1088 // new TextConverter<String,String>() {
1092 // * @param val 入力文字列
1093 // * @param cmnt コメント
1094 // * @return 変換文字列(変換されない場合は、null)
1097 // public String change( final String val , final String cmnt ) {
1098 // return convMap.get( val );
1105 * Workbook の全Sheetを対象に、テキスト変換処理を行います(XSLX限定)。
1107 * この処理は、#saveFile( File ) の直前に行うのがよいでしょう。
1108 * #activeWorkbook( boolean ) との順番は構いません。
1110 * ・シート名の一覧をピックアップします。
1111 * ・セル値を、セル単位内の改行単位にピックアップし、結果を合成ます。
1112 * ・オブジェクト文字列を、改行単位にピックアップし、結果を合成します。
1114 * ここでは、シート名、セルテキスト、SimpleShapeオブジェクトのテキストを
1115 * input に、TextConverterインターフェース の change メソッドを呼び出します。
1116 * 戻り値が、null でないなら、元のデータと置き換えます。
1117 * 戻り値が、null の場合は、そのまま読み飛ばします。(なにもしません)
1118 * EXCELへの書き戻しが発生しますので、万一、ファイル破損で、開けなくなる場合を
1119 * 想定して、バックアップファイルは、各自で準備してください。
1121 * @og.rev 6.2.4.2 (2015/05/29) テキスト変換処理
1122 * @og.rev 6.2.5.0 (2015/06/05) xsl形式のオブジェクト取得…はできなかった。
1123 * @og.rev 6.3.1.0 (2015/06/28) TextConverterに、引数(cmnt)を追加
1124 * @og.rev 6.3.9.0 (2015/11/06) セルに値をセットするときに、セルタイプを考慮する。
1125 * @og.rev 8.0.3.1 (2021/12/28) テキスト取得処理にgetShapeTextを使用する。
1126 * @og.rev 8.1.2.3 (2022/05/20) オブジェクト文字列の変換で、drawing の null 対応
1127 * @og.rev 8.4.0.0 (2023/01/30) オブジェクト文字列の変換ミス対応とメソッド化
1129 * @param conv TextConverterインターフェース
1130 * @see #textConverter( Map )
1132 // @SuppressWarnings(value={"deprecation"}) // poi-3.15
1133 public void textConverter( final TextConverter<String,String> conv ) {
1134 // if( ".xlsx".equals( sufix ) || ".xlsm".equals( sufix ) ) {
1135 final int shCnt = wkbook.getNumberOfSheets();
1136 for( int shtNo=0; shtNo<shCnt; shtNo++ ) {
1137 final Sheet sht = wkbook.getSheetAt( shtNo );
1139 // final String shtNm = conv.change( sht.getSheetName() , "Sheet" + shtNo + ":" );
1140 final String shtNm = conv.change( sht.getSheetName() , "Sheet" + shtNo + ":Name" ); // 8.5.0.0 (2023/04/21)
1141 if( shtNm != null ) {
1142 setSheetName( shtNo,shtNm ); // 同一シート対策済みのメソッドを呼び出す。
1146 final int stR = Math.max( sht.getFirstRowNum(),0 ); // stR が、マイナスのケースがある。
1147 final int edR = sht.getLastRowNum();
1149 for( int rowNo=stR; rowNo<=edR; rowNo++ ) {
1150 final Row rowObj = sht.getRow( rowNo );
1151 if( rowObj != null ) {
1152 final int stC = Math.max( rowObj.getFirstCellNum(),0 ); // stC が、マイナスのケースがある。
1153 final int edC = rowObj.getLastCellNum();
1154 for( int colNo=stC; colNo<=edC; colNo++ ) {
1155 final Cell colObj = rowObj.getCell( colNo );
1156 // if( colObj != null && colObj.getCellType() != Cell.CELL_TYPE_BLANK ) { // 6.5.0.0 (2016/09/30) poi-3.12
1157 // if( colObj != null && colObj.getCellTypeEnum() != CellType.BLANK ) { // 6.5.0.0 (2016/09/30) poi-3.15
1158 if( colObj != null && colObj.getCellType() != CellType.BLANK ) { // 8.0.0.0 (2021/07/31) poi-4.1.2.jar → poi-5.0.0.jar
1159 final String cmnt= "Sheet" + shtNo + ":" + POIUtil.getCelKigo( rowNo,colNo );
1160 final String val = crConv( conv, POIUtil.getValue( colObj ),cmnt ); // 改行対応
1162 POIUtil.setValue( colObj,val ); // 6.3.9.0 (2015/11/06)
1163 // colObj.setCellValue( val );
1171 // 8.0.3.1 (2021/12/28) オブジェクト文字列の変換
1172 final Drawing<?> drawing = sht.getDrawingPatriarch();
1173 // 8.1.2.3 (2022/05/20) オブジェクト文字列の変換で、drawing の null 対応
1174 if( drawing instanceof XSSFDrawing ) {
1175 // if( drawing != null ) {
1176 for (final XSSFShape shape : ((XSSFDrawing)drawing).getShapes() ) {
1177 // 8.4.0.0 (2023/01/30) オブジェクト文字列の変換ミス対応とメソッド化
1178 shapeConvert( shtNo,shape,conv );
1180 // final String shpNm = shape.getShapeName();
1181 // final String cmnt = "Sheet" + shtNo + ":" + shpNm ;
1182 // conv.change( getShapeText( (XSSFShape)shape,null ),cmnt );
1185 // 8.1.2.3 (2022/05/20) オブジェクト文字列の変換で、drawing の null 対応
1187 // 8.1.2.3 (2022/05/20) オブジェクト文字列の変換 復活
1188 if( sht instanceof POIXMLDocumentPart ) {
1189 for( final POIXMLDocumentPart pxdp : ((POIXMLDocumentPart)sht).getRelations() ) {
1190 if( pxdp instanceof XSSFDrawing ) {
1191 for( final XSSFShape shape : ((XSSFDrawing)pxdp).getShapes() ) {
1192 // 8.4.0.0 (2023/01/30) オブジェクト文字列の変換ミス対応とメソッド化
1193 shapeConvert( shtNo,shape,conv );
1195 // // 8.0.3.1 (2021/12/28) テキスト取得処理にgetShapeTextを使用する。
1196 // final String shpNm = shape.getShapeName();
1197 // final String cmnt = "Sheet" + shtNo + ":" + shpNm ;
1198 // conv.change( getShapeText( shape ),cmnt );
1200 // 8.1.2.3 (2022/05/20) オブジェクト文字列の変換 復活
1201 // 8.4.0.0 (2023/01/30) shapeConvert のメソッド化
1202 // final XSSFAnchor anc = shape.getAnchor();
1203 // final String ancSt = "XY(" + anc.getDx1() + "-" + anc.getDy1() + ")" ;
1205 // if( shape instanceof XSSFSimpleShape ) {
1206 // for( final XSSFTextParagraph para : ((XSSFSimpleShape)shape).getTextParagraphs() ) {
1207 // for( final XSSFTextRun text : para.getTextRuns() ) {
1208 // final String cmnt= "Sheet" + shtNo + ":" + ancSt + ":(" + cnt++ + ")" ;
1209 // final String val = crConv( conv,text.getText() , cmnt );
1210 // if( val != null ) {
1211 // text.setText( val );
1222 // 6.2.5.0 (2015/06/05) xsl形式のオブジェクト取得…はできなかった。
1223 // else if( sht instanceof HSSFSheet ) {
1224 // HSSFPatriarch patri = ((HSSFSheet)sht).getDrawingPatriarch();
1225 // for( final HSSFShape shape : patri.getChildren() ) {
1226 // if( shape instanceof HSSFTextbox ) {
1227 // HSSFRichTextString rts = ((HSSFSimpleShape)shape).getString();
1228 // if( rts != null ) {
1229 // final String val = crConv( conv,rts.getString() );
1230 // if( val != null ) {
1231 // HSSFRichTextString rts2 = new HSSFRichTextString( val );
1232 // ((HSSFSimpleShape)shape).setString( rts2 );
1243 * XSSFShape を引数に、XSSFSimpleShape の場合に、変換処理を行います。
1245 * @og.rev 8.4.0.0 (2023/01/30) オブジェクト文字列の変換ミス対応とメソッド化
1246 * @og.rev 8.5.0.0 (2023/04/21) XSSFAnchor オブジェクトの NullPointerException 対策
1248 * @param shtNo シート番号
1249 * @param shape XSSFShapeインターフェース
1250 * @param conv TextConverterインターフェース
1251 * @see #textConverter( Map )
1253 private void shapeConvert( final int shtNo , final XSSFShape shape , final TextConverter<String,String> conv ) {
1254 final XSSFAnchor anc = shape.getAnchor();
1256 // 8.5.0.0 (2023/04/21) XSSFAnchor オブジェクトの NullPointerException 対策
1257 final String ancSt ;
1258 if( anc instanceof XSSFClientAnchor ) {
1259 final XSSFClientAnchor anc2 = (XSSFClientAnchor)anc;
1260 // if( ClientAnchor.AnchorType.DONT_MOVE_AND_RESIZE.equals(anc2.getAnchorType()) ) {
1261 // ancSt = "XY1(" + anc2.getPosition() + ")" ;
1263 final String kigo = POIUtil.getCelKigo( anc2.getRow1(),anc2.getCol1() )
1264 + "-" + POIUtil.getCelKigo( anc2.getRow2(),anc2.getCol2() ) ;
1265 ancSt = "(" + kigo + ")" ;
1268 // ancSt = "XY2(" + anc2.getDx1() + "-" + anc2.getDy1() + ")" ;
1272 ancSt = "(" + anc.getDx1() + "-" + anc.getDy1() + ")" ;
1275 // final String ancSt = "XY(" + anc.getDx1() + "-" + anc.getDy1() + ")" ;
1277 if( shape instanceof XSSFSimpleShape ) {
1278 for( final XSSFTextParagraph para : ((XSSFSimpleShape)shape).getTextParagraphs() ) {
1279 for( final XSSFTextRun text : para.getTextRuns() ) {
1280 // final String cmnt= "Sheet" + shtNo + ":" + ancSt + ":(" + cnt++ + ")" ;
1281 final String cmnt= "Sheet" + shtNo + ":Shape " + ancSt ;
1282 final String val = crConv( conv,text.getText() , cmnt );
1284 text.setText( val );
1292 * Workbook の全SheetのShapeを対象に、テキストをスキャンします(XSLX限定)。
1294 * 引数のBiConsumerは、ラムダ式として適用できます。
1295 * シート毎のShapeから、#getShapeText(XSSFShape,BiConsumer) を呼び出して、
1296 * テキストが存在した場合に、その時のXSSFSimpleShapeとテキストを引数のラムダ式に渡します。
1298 * @og.rev 8.1.0.1 (2022/01/07) テキストベースのリンク作成
1300 * @param bicon BiConsumer関数型インターフェース
1302 public void xssfShapeScan( final BiConsumer<XSSFSimpleShape,String> bicon ) {
1303 final int shCnt = wkbook.getNumberOfSheets();
1304 for( int shtNo=0; shtNo<shCnt; shtNo++ ) {
1305 final Sheet sht = wkbook.getSheetAt( shtNo );
1307 // 8.0.3.1 (2021/12/28) オブジェクト文字列の変換
1308 final Drawing<?> drawing = sht.getDrawingPatriarch();
1309 for (final Shape shape : drawing) {
1310 if( shape instanceof XSSFShape ) {
1311 getShapeText( (XSSFShape)shape, bicon );
1318 * 現在のシートを選択済み(true)か、非選択済み(false)に設定します。
1320 * 通常は、シートは、先頭シート以外は、非選択状態になっています。
1321 * シートを選択済みにすることで、印刷範囲を指定する事ができます。
1323 * @og.rev 6.3.9.0 (2015/11/06) 新規追加
1325 * @param isSelect true:シート選択/false:非選択
1327 public void sheetSelected( final boolean isSelect ) {
1328 sheet.setSelected( isSelect );
1332 * Workbook の雛形シートのTextConverter した、新しいSheetを作成します。
1335 * 1.雛形シートを、コピーして、新しいSheet(shtName)を、作成します。
1336 * 2.雛形シートが指定されていない場合は、一番最後のシートをコピーします。
1337 * 3.そのシートに対して、TextConverter を行い、文字列変換します。
1339 * @og.rev 6.3.9.0 (2015/11/06) 新規追加
1340 * @og.rev 6.5.0.0 (2016/09/30) poi-3.15 対応(Cell.CELL_TYPE_XXXX → CellType.XXXX)
1341 * @og.rev 8.0.3.1 (2021/12/28) テキスト取得処理にgetShapeTextを使用する。
1343 * @param conv TextConverterインターフェース
1344 * @param shtName シート名
1345 * @see #textConverter( Map )
1347 // @SuppressWarnings(value={"deprecation"}) // poi-3.15
1348 public void sheetCopy( final TextConverter<String,String> conv , final String shtName ) {
1349 int shtNo = wkbook.getNumberOfSheets() - 1;
1350 if( refSheetIdx >= 0 && refSheetIdx < shtNo ) { // 雛形シートをコピーする。
1351 sheet = wkbook.cloneSheet( refSheetIdx );
1354 sheet = wkbook.cloneSheet( shtNo ); // 最後のシートをコピーします。
1356 shtNo++ ; // シート番号を増やしておく。
1359 setSheetName( shtNo,shtName ); // 同一シート対策済みのメソッドを呼び出す。
1362 final int stR = Math.max( sheet.getFirstRowNum(),0 ); // stR が、マイナスのケースがある。
1363 final int edR = sheet.getLastRowNum();
1365 for( int rowNo=stR; rowNo<=edR; rowNo++ ) {
1366 final Row rowObj = sheet.getRow( rowNo );
1367 if( rowObj != null ) {
1368 final int stC = Math.max( rowObj.getFirstCellNum(),0 ); // stC が、マイナスのケースがある。
1369 final int edC = rowObj.getLastCellNum();
1370 for( int colNo=stC; colNo<=edC; colNo++ ) {
1371 final Cell colObj = rowObj.getCell( colNo );
1372 // if( colObj != null && colObj.getCellType() != Cell.CELL_TYPE_BLANK ) { // 6.5.0.0 (2016/09/30) poi-3.12
1373 // if( colObj != null && colObj.getCellTypeEnum() != CellType.BLANK ) { // 6.5.0.0 (2016/09/30) poi-3.15
1374 if( colObj != null && colObj.getCellType() != CellType.BLANK ) { // 8.0.0.0 (2021/07/31) poi-4.1.2.jar → poi-5.0.0.jar
1375 final String cmnt= "Sheet" + shtNo + ":" + POIUtil.getCelKigo( rowNo,colNo ); //
1376 // final String val = crConv( conv, POIUtil.getValue( colObj ),null ); // 改行対応
1377 final String val = crConv( conv, POIUtil.getValue( colObj ),cmnt ); // 8.5.0.0 (2023/04/21)
1379 POIUtil.setValue( colObj,val );
1380 // colObj.setCellValue( val );
1387 // 8.0.3.1 (2021/12/28) オブジェクト文字列の変換
1388 final Drawing<?> drawing = sheet.getDrawingPatriarch();
1389 for (final Shape shape : drawing) {
1390 if( shape instanceof XSSFShape ) {
1391 shapeConvert( shtNo,(XSSFShape)shape,conv ); // 8.5.0.0 (2023/04/21) shapeConvert のメソッド化
1393 // final String shpNm = shape.getShapeName();
1394 // final String cmnt = "Sheet" + shtNo + ":" + shpNm ;
1395 // conv.change( getShapeText( (XSSFShape)shape,null ),cmnt );
1399 // // オブジェクト文字列の変換
1400 // if( sheet instanceof POIXMLDocumentPart ) {
1401 // for( final POIXMLDocumentPart pxdp : ((POIXMLDocumentPart)sheet).getRelations() ) {
1402 // if( pxdp instanceof XSSFDrawing ) {
1403 // for( final XSSFShape shape : ((XSSFDrawing)pxdp).getShapes() ) {
1404 // // 8.0.3.1 (2021/12/28) テキスト取得処理にgetShapeTextを使用する。
1405 // conv.change( getShapeText( shape ),null );
1407 // final org.apache.poi.xssf.usermodel.XSSFAnchor anc = shape.getAnchor();
1408 // if( shape instanceof XSSFSimpleShape ) {
1409 // for( final XSSFTextParagraph para : ((XSSFSimpleShape)shape).getTextParagraphs() ) {
1410 // for( final XSSFTextRun text : para.getTextRuns() ) {
1411 // final String val = crConv( conv,text.getText() , null );
1412 // if( val != null ) {
1413 // text.setText( val );
1425 * XSSFShapeから、テキスト文字列を取得します(XSLX限定)。
1427 * XSSFSimpleShapeの場合は、そのまま#getText()を実行します。
1428 * XSSFShapeGroupの場合は、XSSFSimpleShapeに順次分解して文字列を連結していきます。
1429 * 途中に存在する改行コードは削除しておきます。
1431 * @og.rev 8.0.3.1 (2021/12/28) テキスト取得処理にgetShapeTextを使用する。
1432 * @og.rev 8.1.0.1 (2022/01/07) BiConsumerの引数付きメソッドに修正
1434 * @param shape XSSFShapeオブジェクト
1435 * @param bicon BiConsumer関数オブジェクト
1436 * @return シェープから取得した文字列
1438 // private String getShapeText( final XSSFShape shape ) {
1439 private String getShapeText( final XSSFShape shape, final BiConsumer<XSSFSimpleShape,String> bicon ) {
1440 if( shape instanceof XSSFSimpleShape ) {
1441 final String txt = ((XSSFSimpleShape)shape).getText().replace("\n","");
1442 if( bicon != null && !txt.isEmpty() ) {
1443 bicon.accept( (XSSFSimpleShape)shape,txt );
1447 else if( shape instanceof XSSFShapeGroup ) {
1448 // final StringBuilder buf = new StringBuilder();
1449 for( final XSSFShape shape2 : (XSSFShapeGroup)shape ) {
1450 final String txt = getShapeText( shape2,bicon );
1451 if( !txt.isEmpty() ) { // 見つかった時点で終了
1454 // buf.append( getShapeText( shape2 ) );
1456 // return buf.toString();
1462 * Workbook の全Sheetを対象に、テキスト変換処理を行います(XSLX限定)。
1464 * この処理は、#saveFile( File ) の直前に行うのがよいでしょう。
1465 * #activeWorkbook( boolean ) との順番は構いません。
1467 * ・シート名の一覧をピックアップします。
1468 * ・セル値を、セル単位内の改行単位にピックアップし、結果を合成ます。
1469 * ・オブジェクト文字列を、改行単位にピックアップし、結果を合成します。
1471 * ここでは、シート名、セルテキスト、SimpleShapeオブジェクトのテキストを
1472 * input に、TextConverterインターフェース の change メソッドを呼び出します。
1473 * 戻り値が、null でないなら、元のデータと置き換えます。
1474 * 戻り値が、null の場合は、そのまま読み飛ばします。(なにもしません)
1475 * EXCELへの書き戻しが発生しますので、万一、ファイル破損で、開けなくなる場合を
1476 * 想定して、バックアップファイルは、各自で準備してください。
1478 * @og.rev 6.2.4.2 (2015/05/29) テキスト変換処理
1479 * @og.rev 6.3.1.0 (2015/06/28) TextConverterに、引数(cmnt)を追加
1481 * @param conv TextConverterインターフェース
1482 * @param val 改行処理を行う元の値
1484 * @return 改行処理の結果の値(対象が無ければ、null)
1485 * @see #textConverter( Map )
1487 private String crConv( final TextConverter<String,String> conv , final String val , final String cmnt ) {
1490 if( val.contains( "\n" ) ) { // 改行がある場合(EXCEL のセル内改行コードは、LF(0A)=\n のみ。
1491 final String[] val2 = val.split( "\\n" ); // 改行で分割する。
1492 boolean flag = false;
1493 for( int i=0; i<val2.length; i++ ) {
1494 final String val3 = conv.change( val2[i],cmnt ); // 6.3.1.0 (2015/06/28)
1495 if( val3 != null ) { val2[i] = val3; flag = true; }
1498 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
1499 buf.append( val2[0] );
1500 for( int i=1; i<val2.length; i++ ) {
1501 buf.append( '\n' ).append( val2[i] ); // LF(\n)で、セパレートしているので、LF のみ追加する。
1503 rtn = buf.toString();
1507 rtn = conv.change( val,cmnt ); // 6.3.1.0 (2015/06/28)
1514 * シート一覧を、内部の Workbook から取得します。
1516 * 取得元が、Workbook なので、xls , xlsx どちらの形式でも取り出せます。
1518 * EXCEL上のシート名を、配列で返します。
1520 * @og.rev 6.2.6.0 (2015/06/19) 新規作成
1523 * @see POIUtil#getSheetNames( Workbook )
1525 public String[] getSheetNames() {
1526 return POIUtil.getSheetNames( wkbook );
1530 * 名前定義一覧を内部の Workbook から取得します。
1532 * EXCEL上に定義された名前を、配列で返します。
1533 * ここでは、名前とFormulaをタブで連結した文字列を配列で返します。
1534 * Name オブジェクトを削除すると、EXCELが開かなくなったりするので、
1535 * 取りあえず一覧を作成して、手動で削除してください。
1536 * なお、名前定義には、非表示というのがありますので、ご注意ください。
1538 * @og.rev 6.2.6.0 (2015/06/19) 新規作成
1540 * @return 名前定義(名前+TAB+Formula)の配列
1541 * @see POIUtil#getNames( Workbook )
1544 public String[] getNames() {
1545 return POIUtil.getNames( wkbook );
1549 * 書式のスタイル一覧を内部の Workbook から取得します。
1551 * EXCEL上に定義された書式のスタイルを、配列で返します。
1552 * 書式のスタイルの名称は、CellStyle にメソッドが定義されていません。
1553 * 実クラスである HSSFCellStyle にキャストして使用する
1554 * 必要があります。(XSSFCellStyle にも名称を取得するメソッドがありません。)
1556 * ※ EXCEL2010 ホームタブ→セルのスタイル は、一つづつしか削除できません。
1557 * マクロは、開発タブ→Visual Basic で、挿入→標準モジュール を開き
1559 * 実行は、開発タブ→マクロ で、マクロ名を選択して、実行します。
1562 * @og.rev 6.2.6.0 (2015/06/19) 新規作成
1565 * @see POIUtil#getStyleNames( Workbook )
1568 public String[] getStyleNames() {
1569 return POIUtil.getStyleNames( wkbook );
1573 * 文字列を Double オブジェクトに変換します。
1575 * これは、引数の カンマ(,) を削除した文字列から、Double オブジェクトを生成します。
1576 * 処理中に、文字列が解析可能な double を含まない場合(NumberFormatException)
1577 * また、引数が、null,ゼロ文字列,'_', エラー の時には、null を返します。
1579 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
1580 * @og.rev 6.3.9.0 (2015/11/06) もう少し判りやすくする。(処理速度は落ちてます。)
1582 * @param value Doubleに変換する元の文字列
1584 * @return 変換後のDoubleオブジェクト(エラー発生時や変換不可の場合は、null)
1586 private Double parseDouble( final String value ) {
1590 if( value == null || value.isEmpty() || value.equals( "_" ) ) {
1593 else if( value.indexOf( ',' ) < 0 ) {
1594 rtn = Double.valueOf( value ); // 6.0.2.4 (2014/10/17) メソッドが非効率だった。
1597 // 6.3.9.0 (2015/11/06) もう少し判りやすくする。(処理速度は落ちてます。)
1598 rtn = Double.valueOf( value.replaceAll( ",","" ) );
1601 catch( final NumberFormatException ex ) { // 文字列が解析可能な数値を含まない場合
1602 final String errMsg = "Double変換できませんでした。" + CR
1603 + ex.getMessage() + CR
1604 + " value=" + value;
1605 System.err.println( errMsg );
1613 * アプリケーションのサンプルです。
1615 * Usage: java org.opengion.fukurou.model.ExcelModel 入力ファイル名 [出力ファイル名] ・・・
1616 * 通常は標準出力に行単位に、セルをタブ区切り出力します。
1617 * 出力ファイル名 を指定すると、EXCEL ファイルとしてセーブし直します。
1618 * その場合は、以下のパラメータも使用できます。
1619 * -CS CellStyleを 設定します。
1620 * -AS useAutoCellSizeを 設定します。
1621 * -FN=*** FontNameを 設定します。
1622 * -FP=** FontPointを 設定します。
1623 * -IMG 画像ファイルを挿入します。(-IMG 画像ファイル名 シート番号 行 列)をスペース区切りで続けます。
1625 * @og.rev 6.0.2.0 (2014/09/19) 新規作成
1627 * @param args コマンド引数配列
1629 public static void main( final String[] args ) {
1630 if( args.length == 0 ) {
1631 final String usage = "Usage: java org.opengion.fukurou.model.ExcelModel 入力ファイル名 [出力ファイル名] ・・・\n" +
1632 "\t-CS CellStyleを 設定します。 \n" +
1633 "\t-TC TextConverterを実行します。 \n" +
1634 "\t-AS useAutoCellSizeを 設定します。 \n" +
1635 "\t-FN=*** FontNameを 設定します。 \n" +
1636 "\t-FP=** FontPointを 設定します。 \n" +
1637 "\t-IMG 画像ファイルを挿入します。 \n" +
1638 "\t (-IMG ファイル名 シート番号 行 列) \n" ;
1639 System.err.println( usage );
1643 final ExcelModel excel = new ExcelModel( new File( args[0] ) , true );
1645 excel.activeWorkbook( true ); // 余計な行を削除します。
1647 if( args.length > 1 ) {
1648 final File outFile = new File( args[1] ); // 6.2.0.0 (2015/02/27)
1649 boolean isCS = false;
1650 boolean isAS = false;
1651 boolean isTC = false; // 6.2.4.2 (2015/05/29) テキスト変換処理
1655 for( int i=2; i<args.length; i++ ) {
1656 final String prm = args[i];
1658 if( "-CS".equalsIgnoreCase( prm ) ) { isCS = true; } // 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase.
1659 if( "-AS".equalsIgnoreCase( prm ) ) { isAS = true; } // 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase.
1660 if( "-TC".equalsIgnoreCase( prm ) ) { isTC = true; } // 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase.
1661 if( prm.startsWith( "-FN" ) ) { fn = prm.substring( 3 ); }
1662 if( prm.startsWith( "-FP" ) ) { fp = Short.parseShort( prm.substring( 3 ) ); }
1663 if( "-IMG".equalsIgnoreCase( prm ) ) { // 6.4.1.1 (2016/01/16) PMD refactoring. Position literals first in String comparisons for EqualsIgnoreCase.
1664 final String img = args[++i];
1665 final int shtNo = Integer.parseInt( args[++i] );
1666 final int rowNo = Integer.parseInt( args[++i] );
1667 final int colNo = Integer.parseInt( args[++i] );
1669 excel.addImageFile( img,shtNo,rowNo,colNo );
1673 if( isCS ) { excel.setCellStyle(); }
1674 excel.useAutoCellSize( isAS );
1675 excel.setFont( fn,fp );
1677 // 6.2.4.2 (2015/05/29) テキスト変換処理
1679 // 6.3.9.0 (2015/11/06) Java 8 ラムダ式に変更
1680 // 処理が複数行に別れるのは判りにくいので良くない。
1681 excel.textConverter(
1683 System.out.println( val ); // すべてのテキストを読み取る。
1684 return null; // 変換せず。
1689 excel.saveFile( outFile );
1692 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE );
1694 final int shLen = excel.getNumberOfSheets();
1695 for( int shtNo=0; shtNo<shLen; shtNo++ ) {
1696 final String shtName = excel.getSheetName( shtNo );
1698 final int stRow = excel.getFirstRowNum();
1699 final int edRow = excel.getLastRowNum();
1700 for( int rowNo=stRow; rowNo<=edRow; rowNo++ ) {
1701 buf.setLength(0); // Clearの事
1702 buf.append( shtName ).append( '\t' ).append( rowNo );
1703 final String[] vals = excel.getValues( rowNo );
1704 if( vals != null ) {
1705 for( int colNo=0; colNo<vals.length; colNo++ ) {
1706 final String val = vals[colNo] == null ? "" : vals[colNo];
1707 buf.append( '\t' ).append( val );
1710 System.out.println( buf );
1712 System.out.println();