14

PDF に変換する必要があるユーザー提供の Excel ファイルがあります。Excel 相互運用機能を使用して、これをうまく行うことができます.ExportAsFixedFormat()。ワークブックに何百万行もあると、私の問題が発生します。これは、50,000 ページ以上のファイルになります。ワークブックのすべての行にコンテンツが含まれていれば問題ありません。ただし、これらのファイルの 1 つが表示されるたびに、おそらく 50 行にコンテンツがあり、残りは空白です。適切なサイズの PDF にエクスポートできるように、空の行を削除するにはどうすればよいですか?

  1. 最後の行から始めて、行にコンテンツがあるかどうかを1つずつCountA確認し、ある場合は削除してみました。これには永遠に時間がかかるだけでなく、約 100k 行の後に次のエラーで失敗するようです。

    コードが最適化されているか、ネイティブ フレームがコール スタックの一番上にあるため、式を評価できません。

  2. 使用してみましSpecialCells(XlCellType.xlCellTypeLastCell, XlSpecialCellsValue.xlTextValues)たが、セルに書式設定 (背景色など) がある場合は行が含まれます。

  3. Worksheet.UsedRangeその後、すべてを使用してから削除しようとしましたUsedRangeが、ポイント2と同じ問題があります。


これは私が試したコードです:

for (int i = 0; i < worksheets.Count; i++)
{
    sheet = worksheets[i + 1];
    rows = sheet.Rows;
    currentRowIndex = rows.Count;
    bool contentFound = false;

    while (!contentFound && currentRowIndex > 0)
    {
        currentRow = rows[currentRowIndex];

        if (Application.WorksheetFunction.CountA(currentRow) == 0)
        {
            currentRow.Delete();
        }
        else
        {
            contentFound = true;
        }

        Marshal.FinalReleaseComObject(currentRow);
        currentRowIndex--;
    }

    Marshal.FinalReleaseComObject(rows);
    Marshal.FinalReleaseComObject(sheet);
}

for (int i = 0; i < worksheets.Count; i++)
{
    sheet = worksheets[i + 1];
    rows = sheet.Rows;

    lastCell = rows.SpecialCells(XlCellType.xlCellTypeLastCell, XlSpecialCellsValue.xlTextValues);
    int startRow = lastCell.Row;

    Range range = sheet.get_Range(lastCell.get_Address(RowAbsolute: startRow));
    range.Delete();

    Marshal.FinalReleaseComObject(range);
    Marshal.FinalReleaseComObject(lastCell);
    Marshal.FinalReleaseComObject(rows);
    Marshal.FinalReleaseComObject(sheet);
}

コードに問題がありますか?これは相互運用の問題ですか?それとも、Excel でできることの制限にすぎないのでしょうか? 私が試みていることを行うためのより良い方法はありますか?

4

8 に答える 8

0

Sheet1.Range("A1").CurrentRegion.ExportAsFixedFormat()Sheet1が有効なシート名であり、「A1」がエクスポートする範囲内にあることを確認するためにテストできるセルである場合を試しましたか?

問題は残っています、なぜExcelはそれらの「空の」セルにデータがあると考えるのですか?フォーマットしますか?クリアする必要がある既存の印刷領域?私は以前にそのような状況に遭遇したことを知っています、それらは現時点で頭に浮かぶ唯一の可能性です。

于 2011-03-21T22:02:50.377 に答える
0

次の手順を試してください -

  1. Worksheet.UsedRange別のシート (sheet2) にコピーします。
  2. フォーマットが保持されるように特殊貼り付けを使用する
  3. 未使用の行について sheet2 を解析してみてください

これで問題が解決しない場合は、フォーマット情報をクリアしてからシート 2 を解析して手順 2 を繰り返してみてください。後でフォーマット情報をいつでもコピーできます(十分に単純な場合)

于 2011-03-22T18:46:37.430 に答える
0

最初に OleDBAdapter を介して Excel ファイルを DataSet に読み込むことができれば、インポート時に空白行を削除するのは比較的簡単です...スタック オーバーフロー経由で投稿したこのOleDBAdapter Excel QAをお試しください。

次に、DataSet を新しい Excel ファイルにエクスポートし、そのファイルを PDF に変換します。もちろん、Excelのレイアウト(またはレイアウトの欠如)によっては、それは大きな「IF」になる可能性があります。

于 2011-05-05T16:19:18.303 に答える
0

今日、あなたの考えられるケースのサブセットである可能性があるこの問題を解決しなければなりませんでした。

スプレッドシートが次の条件を満たしている場合:

  1. データを含むすべての列には、1 行目にヘッダー テキストがあります。
  2. データを含むすべての行は、最初の BLANK 行まで順番に並んでいます。

次に、次のコードが役立つ場合があります。

    private static string[,] LoadCellData(Excel.Application excel, dynamic sheet)
    {
        int countCols = CountColsToFirstBlank(excel, sheet);
        int countRows = CountRowsToFirstBlank(excel, sheet);
        cellData = new string[countCols, countRows];
        string datum;

        for (int i = 0; i < countCols; i++)
        {
            for (int j = 0; j < countRows; j++)
            {
                try
                {
                    if (null != sheet.Cells[i + 1, j + 1].Value)
                    {
                        datum = excel.Cells[i + 1, j + 1].Value.ToString();
                        cellData[i, j] = datum;
                    }
                }
                catch (Exception ex)
                {
                    lastException = ex;
                    //Console.WriteLine(String.Format("LoadCellData [{1}, {2}] reported an error: [{0}]", ex.Message, i, j));
                }
            }
        }

        return cellData;
    }

    private static int CountRowsToFirstBlank(Excel.Application excel, dynamic sheet)
    {
        int count = 0;

        for (int j = 0; j < sheet.UsedRange.Rows.Count; j++)
        {
            if (IsBlankRow(excel, sheet, j + 1))
                break;

            count++;
        }
        return count;
    }
    private static int CountColsToFirstBlank(Excel.Application excel, dynamic sheet)
    {
        int count = 0;

        for (int i = 0; i < sheet.UsedRange.Columns.Count; i++)
        {
            if (IsBlankCol(excel, sheet, i + 1))
                break;

            count++;
        }
        return count;
    }

    private static bool IsBlankCol(Excel.Application excel, dynamic sheet, int col)
    {
        for (int i = 0; i < sheet.UsedRange.Rows.Count; i++)
        {
            if (null != sheet.Cells[i + 1, col].Value)
            {
                return false;
            }
        }

        return true;
    }
    private static bool IsBlankRow(Excel.Application excel, dynamic sheet, int row)
    {
        for (int i = 0; i < sheet.UsedRange.Columns.Count; i++)
        {
            if (null != sheet.Cells[i + 1, row].Value)
            {
                return false;
            }
        }

        return true;
    }
于 2012-05-21T18:27:21.087 に答える