web-dev-qa-db-ja.com

Excelスプレッドシートの最後の行を見つける

ApacheのPOI for Javaを使用して、Excelスプレッドシートの最後の行のインデックスを見つけようとしています。

これはgetLastRowNum()またはgetPhysicalNumberOfRows()で可能だと思いましたが、正しい結果が得られないようです。たとえば、1行のスプレッドシートがあり、これらの2つの関数は1140の値を返します。別の2行のスプレッドシートは1162の値を取得します。

もう1つの問題は、有効なデータの行の間に空の行がある可能性があるため、最初の空の行だけを検索できないことです。

それで、最後の行のインデックスを見つける方法はありますか?データ間に空の行がないことを要件にできると思いますが、もっと良い解決策を望んでいました。

編集:イテレータを使用した記録では役に立ちませんでした。 1140/1162の想定された行を繰り返しただけです。

13
FromCanada

Poi-3.6-20091214とtest.xls 2つの空の行の後に3つの占有行が続く:

InputStream myxls = new FileInputStream("test.xls");
Workbook book = new HSSFWorkbook(myxls);
Sheet sheet = book.getSheetAt(0);
System.out.println(sheet.getLastRowNum());

出力:4

14
trashgod

次のメソッドを使用して、元の行数を取得できます。

HSSFSheet worksheet = workbook.getSheet("Role_Mapping");
int rowsNum = worksheet.getPhysicalNumberOfRows();
6
user2318124

以前にも同じ問題がありました。編集されてからExcelで空にされたExcelセルが原因である可能性があります。タッチすると、使用済みセルとして表示されます。

私はこのトリックを使用して、これらのセルを(空ではなく)削除し、正しい戻り値の行を取得します。

  1. Excelファイルを開き、予期したシートに移動します。
  2. 最後の行+ 1を選択します。たとえば、データが12行ある場合、行13をクリックします。
  3. 行全体を選択[Shift]-[Space]
  4. シートの下部にあるすべての行を選択します[Ctrl]-[Shift]-[下矢印]
  5. 選択した行をすべて削除[Ctrl]-[マイナス]
  6. ブックを保存する
  7. コードを再実行し、戻り値を確認してください。

これはPOIライブラリの問題ではありません。

2
realheaven

確実に知る唯一の方法は、行をテストすることです。これは私が同じ問題に使用している解決策です:

int lastRowIndex = -1;
if( sheet.getPhysicalNumberOfRows() > 0 )
{
    // getLastRowNum() actually returns an index, not a row number
    lastRowIndex = sheet.getLastRowNum();

    // now, start at end of spreadsheet and work our way backwards until we find a row having data
    for( ; lastRowIndex >= 0; lastRowIndex-- ){
        Row row = sheet.getRow( lastRowIndex );
        if( row != null ){
            break;
        }
    }
}

注:これは、空の文字列が含まれているセルなど、空であるように見えても空ではない行をチェックしません。そのためには、次のようなより完全なソリューションが必要です。

private int determineRowCount()
{
    this.evaluator = workbook.getCreationHelper().createFormulaEvaluator();
    this.formatter = new DataFormatter( true );

    int lastRowIndex = -1;
    if( sheet.getPhysicalNumberOfRows() > 0 )
    {
        // getLastRowNum() actually returns an index, not a row number
        lastRowIndex = sheet.getLastRowNum();

        // now, start at end of spreadsheet and work our way backwards until we find a row having data
        for( ; lastRowIndex >= 0; lastRowIndex-- )
        {
            Row row = sheet.getRow( lastRowIndex );
            if( !isRowEmpty( row ) )
            {
                break;
            }
        }
    }
    return lastRowIndex;
}

/**
 * Determine whether a row is effectively completely empty - i.e. all cells either contain an empty string or nothing.
 */
private boolean isRowEmpty( Row row )
{
    if( row == null ){
        return true;
    }

    int cellCount = row.getLastCellNum() + 1;
    for( int i = 0; i < cellCount; i++ ){
        String cellValue = getCellValue( row, i );
        if( cellValue != null && cellValue.length() > 0 ){
            return false;
        }
    }
    return true;
}

/**
 * Get the effective value of a cell, formatted according to the formatting of the cell.
 * If the cell contains a formula, it is evaluated first, then the result is formatted.
 * 
 * @param row the row
 * @param columnIndex the cell's column index
 * @return the cell's value
 */
private String getCellValue( Row row, int columnIndex )
{
    String cellValue;
    Cell cell = row.getCell( columnIndex );
    if( cell == null ){
        // no data in this cell
        cellValue = null;
    }
    else{
        if( cell.getCellType() != Cell.CELL_TYPE_FORMULA ){
            // cell has a value, so format it into a string
            cellValue = this.formatter.formatCellValue( cell );
        }
        else {
            // cell has a formula, so evaluate it
            cellValue = this.formatter.formatCellValue( cell, this.evaluator );
        }
    }
    return cellValue;
}
1
GreenGiant

VBAを使用して問題を解決する方法は知っていますが、Apache POIインターフェースから同等の情報を取得する方法がわかりません。 VBAで、ワークシート「Sheet1」の使用済みセルの範囲を取得するには、次を使用します。

Worksheets("Sheet1").UsedRange

これは、詳細情報を提供するプロパティを持つRangeオブジェクトを返します。たとえば、このRangeの行数を取得するには、次を使用します。

Worksheets("Sheet1").UsedRange.Rows

繰り返しますが、これがPOI APIを介してアクセスできるかどうかはわかりませんが、そうでない場合は、おそらくVBAの任意のスニペットを実行する方法を提供しますか?

1
Dónal

これは、次のコードで実行できます。

SVTableModel model = new SVTableModel(sheet);
lastRowNum = model.getRowCount();

しかし、私はこれをApache POI 3.7で実行しようとしていますが、APIでSVTableModelを見つけることができませんでした。これは3.2から削除されたと思います。

0
ParagJ

HSSFWorkbookでは機能しますが、XSSFWorkbookでは機能しないため、私にとっては何も機能しませんでした。最後に回避策の助けを借りて、この問題を解決することができます。シートの最後で(コンテンツの終了後に)2つの列または行をマージします。次に、以下のコードを記述します。 sheet.getMergedRegion(0).getLastRow()ここで0は、私がマージした1つのケースにすぎませんが、セルまたは行を既にマージしている場合は、それに応じて値を増分します。これがお役に立てば幸いです。

0
Shiv Pratap