質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.31%
ClosedXML

ClosedXMLは、Excel形式ファイル(.xlsx, .xlsm)の操作や読み書きのための.NETライブラリです。

VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

Visual Basic .NET

Microsoft Visual Basic .NET (VB.NET)とはオブジェクト志向のプログラム言語です。 Microsoft"s Visual Basic 6 のバージョンアップとしてみることができますが、Microsoft.NET Frameworktによって動かされています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

Q&A

1回答

220閲覧

vbのClosedXMLを使用して出力したエクセルがClosedXMLでは読めない

t20240712

総合スコア10

ClosedXML

ClosedXMLは、Excel形式ファイル(.xlsx, .xlsm)の操作や読み書きのための.NETライブラリです。

VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

Visual Basic .NET

Microsoft Visual Basic .NET (VB.NET)とはオブジェクト志向のプログラム言語です。 Microsoft"s Visual Basic 6 のバージョンアップとしてみることができますが、Microsoft.NET Frameworktによって動かされています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

0グッド

0クリップ

投稿2025/04/21 04:15

実現したいこと

別途説明するエクセルファイルをClosedXMLを使用して読み込めるようにしたい
エクセルがインストールされていない端末でもそれが可能な事

発生している問題・分からないこと

以下のスレッドの続きです。(見なくても、ここに必要要項は書きますが。)
https://teratail.com/questions/lmfwqvnb5lx442#reply-85ukqmng7vq6ft

ClosedXMLを使用してExcelファイルを読み込む時に、式が入ったセルでエラーになるので、上記のスレッドを立てました。
しかし、ClosedXMLやVBのソースではなく、Excelファイルが壊れていました。

なぜ、Excelファイルが壊れていると言えるのか
ClosedXMLからは読めないが、本物のエクセルでは読み込む事ができるので、本物のエクセルで再保存したところ正しく処理が行えた。

ClosedXMLの読込能力の低さを残念がる事もできますが、エクセルで再保存したものは正しく処理できたので、ファイル作成者が悪いという見方もできます。

そのファイル作成者は外ならぬClosedXMLライブラリでした。
ですので、今回は書き込み側中心の話になります。

エラーメッセージ

error

1型 'System.StackOverflowException' のハンドルされていない例外が mscorlib.dll で発生しました 2 3埋め込みドキュメント 'System.Globalization\CompareInfo.cs' を 'C:\Users\sys_developer\AppData\Local\Temp\.vsdbgsrc\82f5c4d99137273f37e4fbe578de1a03843e6011bebc9ed0966c7a983ed26386\CompareInfo.cs' に抽出しました 4プログラム '[18536] WindowsApp1.exe' はコード 4294967295 (0xffffffff) で終了しました。

該当のソースコード

Form1.vb

1Imports System.IO 2Imports System.Reflection 3Imports ClosedXML.Excel 4Imports DocumentFormat.OpenXml.Spreadsheet 5 6Public Class Form1 7 Const Temp1 As String = "d:\work\TEMP1.xlsx" 8 Const Temp2 As String = "d:\work\TEMP2.xlsx" 9 Dim DataTableDGView1 As New DataTable 10 Dim ExcelResourceName As String = "WindowsApp1.TEST1.xlsx" 11 12 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 13 TabControl1.Dock = DockStyle.Fill 14 DataGridView1.Dock = DockStyle.Fill 15 DataGridView2.Dock = DockStyle.Fill 16 Call DataTable1Set() 17 End Sub 18 19 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 20 Dim Eod As Integer 21 Using ResourceStream As Stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(Me.ExcelResourceName) 22 If ResourceStream Is Nothing Then 23 MessageBox.Show("リソースが見つかりませんでした。") 24 Exit Sub 25 End If 26 Using fileStream As FileStream = File.Create(Temp1) 27 ResourceStream.CopyTo(fileStream) 28 End Using 29 End Using 30 31 Using XLWorkbook1 = New XLWorkbook(Temp1) 32 Dim WorksheetX = XLWorkbook1.Worksheet(1) 33 Dim CntRow As Integer = 1 34 For Each DataRow1 As DataRow In Me.DataTableDGView1.Rows 35 CntRow += 1 36 Dim CntCol As Integer = 1 37 WorksheetX.Cell(CntRow, CntCol).Value = DataRow1("A-Item").ToString 38 WorksheetX.Cell(CntRow, CntCol + 1).Value = DataRow1("B-Key").ToString 39 WorksheetX.Cell(CntRow, CntCol + 2).Value = ExcelCellDate(DataRow1("C-Date").ToString) 40 For For1 As Integer = 1 To 28 41 WorksheetX.Cell(CntRow, CntCol + 2 + For1).Value = "Dummy" & For1.ToString(0) 42 Next 43 WorksheetX.Cell(CntRow, CntCol + 31).Value = DataRow1("AG-String").ToString 44 WorksheetX.Cell(CntRow, CntCol + 32).Value = ExcelCellDate(DataRow1("AH-Date").ToString) 45 WorksheetX.Cell(CntRow, CntCol + 33).Value = ExcelCellDate(DataRow1("AI-Date").ToString) 46 WorksheetX.Cell(CntRow, CntCol + 35).Value = ExcelCellDate(DataRow1("AK-Date").ToString) 47 WorksheetX.Cell(CntRow, CntCol + 36).Value = DataRow1("AL-String").ToString 48 WorksheetX.Cell(CntRow, CntCol + 37).Value = DataRow1("AM-String").ToString 49 WorksheetX.Cell(CntRow, CntCol + 38).Value = ExcelCellNumeric(DataRow1("AN-フラグ").ToString) 50 WorksheetX.Cell(CntRow, CntCol + 41).Value = ExcelCellNumeric(DataRow1("AQ-フラグ").ToString) 51 WorksheetX.Cell(CntRow, CntCol + 43).Value = ExcelCellNumeric(DataRow1("AS-フラグ").ToString) 52 WorksheetX.Cell(CntRow, CntCol + 44).Value = ExcelCellDate(DataRow1("AT-Date").ToString) 53 Next 54 Eod = CntRow 55 XLWorkbook1.Save() 56 End Using 57 58 Call ExcelRemoveRows(Temp1, Eod + 1, 1000) 59 Call ExcelSaveAs(Temp1, Temp2) 60 MsgBox("Excelファイルへの書き込みが正常に完了しました。") 61 End Sub 62 63 Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 64 Call Put_DataGrid(Temp1) 65 End Sub 66 67 Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click 68 Call Put_DataGrid(Temp2) 69 End Sub 70 71 Private Sub DataTable1Set() 72 Me.DataTableDGView1 = New DataTable() 73 With Me.DataTableDGView1.Columns 74 .Add("A-Item", GetType(String)) 75 .Add("B-Key", GetType(String)) 76 .Add("C-Date", GetType(String)) 77 .Add("AG-String", GetType(String)) 78 .Add("AH-Date", GetType(String)) 79 .Add("AI-Date", GetType(String)) 80 .Add("AK-Date", GetType(String)) 81 .Add("AL-String", GetType(String)) 82 .Add("AM-String", GetType(String)) 83 .Add("AN-フラグ", GetType(String)) 84 .Add("AQ-フラグ", GetType(String)) 85 .Add("AS-フラグ", GetType(String)) 86 .Add("AT-Date", GetType(String)) 87 End With 88 89 Dim Random1 As New Random() 90 For Count1 As Integer = 1 To 255 91 Dim RandomNumb As Integer = Random1.Next(0, 2) 92 Dim NewRow1 As DataRow = Me.DataTableDGView1.NewRow() 93 NewRow1("A-Item") = "あああ" 94 NewRow1("B-Key") = "KEY" & Count1.ToString("0000000000") 95 NewRow1("C-Date") = DateTime.Now.AddDays(Random1.Next(-50, 61)).ToString("yyyy/MM/dd") 96 NewRow1("AG-String") = If(RandomNumb = 0, String.Empty, "AG" & RandomNumb.ToString) 97 NewRow1("AH-Date") = DateTime.Now.AddDays(Random1.Next(-10, 10)).ToString("yyyy/MM/dd") 98 NewRow1("AI-Date") = DateTime.Now.AddDays(Random1.Next(-10, 10)).ToString("yyyy/MM/dd") 99 NewRow1("AK-Date") = DateTime.Now.AddDays(Random1.Next(-10, 10)).ToString("yyyy/MM/dd") 100 NewRow1("AL-String") = "AL" & (Random1.Next(-10, 10)).ToString 101 NewRow1("AM-String") = "AM" & (Random1.Next(-10, 10)).ToString 102 NewRow1("AN-フラグ") = Random1.Next(0, 2).ToString 103 NewRow1("AQ-フラグ") = Random1.Next(0, 2).ToString 104 NewRow1("AS-フラグ") = Random1.Next(0, 2).ToString 105 NewRow1("AT-Date") = DateTime.Now.AddDays(Random1.Next(-10, 10)).ToString("yyyy/MM/dd") 106 Me.DataTableDGView1.Rows.Add(NewRow1) 107 Next 108 DataGridView1.DataSource = Me.DataTableDGView1 109 End Sub 110 111 Private Function ExcelCellDate(inputDateTime As String) As String 112 Try 113 Return DateTime.Parse(inputDateTime).ToString("yyyy-MM-dd") 114 Catch ex As Exception 115 Debug.WriteLine($"エラー: {ex.Message}") 116 Return String.Empty 117 End Try 118 End Function 119 120 Private Function ExcelCellNumeric(numericValue As String) As Double 121 Try 122 If String.IsNullOrWhiteSpace(numericValue) Then Return 0.0 123 Dim result As Double 124 If Double.TryParse(numericValue, result) Then Return result 125 Debug.WriteLine($"数値変換失敗: 入力値 '{numericValue}' は数値ではありません。") 126 Return 0.0 127 Catch ex As Exception 128 Debug.WriteLine($"エラー発生: {ex.Message}") 129 Return 0.0 130 End Try 131 End Function 132 133 Private Sub ExcelRemoveRows(filePath As String, startRow As Integer, endRow As Integer) 134 Debug.WriteLine($"ファイルパス: {filePath}, 削除範囲: {startRow} から {endRow}") 135 Using XLWorkbook1 As New XLWorkbook(filePath) 136 Dim IXLWorksheet1 As IXLWorksheet = XLWorkbook1.Worksheet("Sheet1") 137 Dim delcnt = 0 138 For rowIndex As Integer = endRow To startRow Step -1 139 delcnt += 1 140 IXLWorksheet1.Row(rowIndex).Delete() 141 If delcnt >= 50 Then 142 XLWorkbook1.Save() 143 Application.DoEvents() 144 Debug.WriteLine($"50件削除") 145 delcnt = 0 146 End If 147 Next 148 XLWorkbook1.Save() 149 Debug.WriteLine($"削除完了") 150 End Using 151 End Sub 152 153 Private Sub ExcelSaveAs(filePath1 As String, filePath2 As String) 154 Using XLWorkbook1 As New XLWorkbook(filePath1) 155 XLWorkbook1.SaveAs(filePath2) 156 Debug.WriteLine($"保存しなおし完了") 157 End Using 158 End Sub 159 160 Private Sub Put_DataGrid(TempFile As String) 161 Dim DataTable1 = New DataTable 162 163 'Headerのセット 164 Using XLWorkbook1 As New XLWorkbook(TempFile) 165 Dim Worksheet1 = XLWorkbook1.Worksheet(1) 166 Dim lastColumn As Integer = Worksheet1.LastColumnUsed().ColumnNumber() 167 For col As Integer = 1 To lastColumn 168 Dim IXLCell1 As IXLCell = Worksheet1.Cell(1, col) 169 Dim headerValue As String = If(IXLCell1.IsEmpty(), String.Empty, IXLCell1.GetValue(Of String)()) 170 DataTable1.Columns.Add(headerValue) 171 Next 172 End Using 173 DataGridView2.DataSource = DataTable1 174 175 'Bodyのデータは割愛 176 MsgBox("Excelファイルへの読み込みが正常に完了しました。") 177 End Sub 178End Class

TEST1.xlsx

1ある程度負荷をかけないと落ちてくれないので、列はあまり減らしていない。 2任意の場所で作成し、直下にアドしてビルドアクションを埋め込みリソースに変更する。 3 4<ヘッダ> 5A-Item 6【式】="B-Key" & CHAR(10) & COUNTA(B2:B999) & "件" 7C-Date 8dummy1 9dummy2 10dummy3 11dummy4 12dummy5 13dummy6 14dummy7 15dummy8 16dummy9 17dummy10 18dummy11 19dummy12 20dummy13 21dummy14 22dummy15 23dummy16 24dummy17 25dummy18 26dummy19 27dummy20 28dummy21 29dummy22 30dummy23 31dummy24 32dummy25 33dummy26 34dummy27 35dummy28 36【式】="アラート3⇒" & CHAR(10) & COUNTIF(AF2:AF1000,"!") & "件" 37AG-String 38AH-Date 39AI-Date 40【式】="アラート1⇒" & CHAR(10) & COUNTIF(AJ2:AJ1000,"!") & "件" 41AK-Date 42AL-String 43AM-String 44AN-フラグ 45AO-式 46AP-式 47AQ-フラグ 48【式】="アラート2⇒" & CHAR(10) & COUNTIF(AR2:AR1000,"!") & "件" 49AS-フラグ 50AT-Date 51 52 53<ボディ> 54ボディに式があるのは下記の5項目、行2~1000まで埋まっているものとする。 55 56アラート3⇒ 57=IF(C2+30<TODAY(), IF(LEN(TRIM(AG2)) < 1, TRIM("!"), TRIM("")), TRIM("")) 58 59アラート1⇒ 60=IF(AK2+0<TODAY(), TRIM("!"), TRIM("")) 61 62AO-式 63=IF(TEXT(AS2, "0") <> TRIM("1"), IF(C2 + 7 * 2 < TODAY(), TRIM(1), TRIM(0)), TRIM(0)) 64 65AP-式 66=IF(TRIM(AT2) = TRIM(""), IF(TRIM(AH2) = TRIM(""), 1, IF(AH2 > TODAY(), 1, 0)), IF(AT2 - 7 * 2 >= TODAY(), 1, 0)) 67 68アラート2⇒ 69=IF((TRIM(AP2) & TRIM(AQ2)) = TRIM("11"), TRIM(""), IF(TRIM(AO2) = "1", TRIM("!"), TRIM(""))) 70

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

起動⇒ページ2にテストデータ
ボタン1⇒TEMP1、TEMP2が作成される
ボタン2⇒TEMP1から読み込めない
ボタン3⇒SaveAsで保存したTEMP2から読み込めない
その後
TEMP1を開きExcelで再保存するとボタン2でページ3にデータが読み込めるのを確認できる
TEMP2を開きExcelで再保存するとボタン2でページ3にデータが読み込めるのを確認できる

補足

■バージョン
vb 2022
.NET Framework 4.8
ClosedXML(0.104.2)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t20240712

2025/04/21 04:33 編集

Form1 以下を事前にForm1に配置 +-TabControl1  +-TabPage1  | +-Button1 Excel作成(TEMP1:Save|TEMP2:SaveAs)  | +-Button2 TEMP1から表示  | +-Button3 TEMP2から表示  +-TabPage2  | +-DataGridView1 入力データを視覚的に確認する  +-TabPage3   +-DataGridView2 Excelを読み込んだ内容を表示
KOZ6.0

2025/04/22 04:50 編集

ClosedXML が計算式のすべてを網羅しているわけではありません。 最終的には Excel で開いて確認なり印刷するわけなので、計算式が入ったセルの値を参照しなくて済む方法を考えたほうがいいと思いますよ。
KOZ6.0

2025/04/22 05:01

ReoGrid に読み込ませてみるのも一つの手かもしれません。 https://reogrid.net/jp/ MIT ライセンスで無償で使えます。(サポートは有料)
t20240712

2025/04/22 05:30

>最終的には Excel で開いて確認なり印刷するわけなので、計算式が入ったセルの値を参照しなくて済む方法を考えたほうがいいと思いますよ。 なるほど、ひな型なので、読んで別の場所に書くのが役割ですが、読むのはシート単位でやって、セル単位で読まないという形で逃げられなくもないです。
guest

回答1

0

こんにちは。

ちゃんと調べていませんが、
計算式セルに対して TRIM していることで即座に文字列への変換処理が走るため、そこで無限に評価が再帰して落ちていそうです。
ぶっちゃけ ClosedXML のバグな気がしますが、計算式セルの参照に対する TRIM をやめれば回避できるかもしれません。

diff

1- =IF((TRIM(AP2) & TRIM(AQ2)) = TRIM("11"), TRIM(""), IF(TRIM(AO2) = "1", TRIM("!"), TRIM("")) 2+ =IF(AP2 & TRIM(AQ2)) = TRIM("11"), TRIM(""), IF(AO2 = "1", TRIM("!"), TRIM(""))

ところで、トリム処理が不要な文字列リテラルに対する TRIM は全く無駄なので、意図的でないなら省略したほうが良いと思いました。

diff

1- =IF((TRIM(AP2) & TRIM(AQ2)) = TRIM("11"), TRIM(""), IF(TRIM(AO2) = "1", TRIM("!"), TRIM("")) 2+ =IF((AP2 & TRIM(AQ2)) = "11", "", IF(AO2 = "1", "!", ""))

投稿2025/04/21 08:56

編集2025/04/21 08:58
tamoto

総合スコア4288

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

t20240712

2025/04/22 00:33 編集

不要なTRIMが多いのは半分わざとです。 エクセルは生のままでは表に出せないので、簡略化したりエッセンス部分だけ出しています。 しかし、シンプルに削ると事象が起こらなくなるので、ダミーフィールを間に作ったり、ク ソみたいな式をあえて残しています。 ク ソみたいなエクセルのひな型が沢山あって、そこに元々手入力していたものをVBを使って放り込むといった事をしようとしています。 もちろん、エクセルの式が悪い場合はエクセル式を直しますが、エクセルで開いて編集したり、エクセルで再保存するといけるレベルの事はClosedXML側で回避したいです。 でないと、ここをTRIMを除いて通しても、他で同じようになることが目に見えてますので。 あるいは、「ClosedXML なんてものは、凝ったエクセルに対応できる代物ではない」という現実であれば、そう認識する必要があります。
tamoto

2025/04/22 02:26

TRIM 限定なのかは分かっていませんが、ClosedXML がそれらを扱う場合の考慮漏れと思われるので、単純に ClosedXML のバグです。 再現ファイルを添えて Issue を立ててバグ報告することをおすすめします。 開発が活発ならすぐ直ると思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.31%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問