如何在没有“内存不足”异常的情况下将大型DataGridView导出到Excel?
我的问题是,我需要从MySQL数据库填充的DataGridView中将90.000+行/143列导出到Excel。无论我做什么,我总是在45k-60k行之后出现“System.Out.Of.Memory”异常,具体取决于解决方案。我知道可能会有像“为什么你需要这么多行”这样的问题,我会回答“不幸的是,这是需要的。”我已经搜索了关于我的问题的论坛,但没有找到任何有效的解决方案。我尝试将StreamWriter转换为CSV,使用下面的解决方案将数据分块处理,也使用多个Excel或CSV文件,但没有任何帮助。每次在执行期间,当我尝试使用较少的行数时,RAM的使用量都在增长,并且在成功导出后不会释放。我不知道成功执行后RAM何时释放,是否释放 测试机器有8 GB的RAM,并且使用Windows 10。不幸的是,我无法使用MySQL服务器的资源处理那里的Excel导出,然后输出文件与用户共享,所以我需要使用客户端机器 下面是我最新的不工作解决方案,其中数据从DGV中读取,并分块写入Excel。改变块的大小并不能减少内存消耗,如果我把它缩小到500到2000,唯一的效果就是导出速度变慢了如何在没有“内存不足”异常的情况下将大型DataGridView导出到Excel?,excel,vb.net,winforms,Excel,Vb.net,Winforms,我的问题是,我需要从MySQL数据库填充的DataGridView中将90.000+行/143列导出到Excel。无论我做什么,我总是在45k-60k行之后出现“System.Out.Of.Memory”异常,具体取决于解决方案。我知道可能会有像“为什么你需要这么多行”这样的问题,我会回答“不幸的是,这是需要的。”我已经搜索了关于我的问题的论坛,但没有找到任何有效的解决方案。我尝试将StreamWriter转换为CSV,使用下面的解决方案将数据分块处理,也使用多个Excel或CSV文件,但没有任
Imports Excel = Microsoft.Office.Interop.Excel
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If DataGridView1.Rows.Count > 0 Then
Dim filename As String = ""
Dim SV As SaveFileDialog = New SaveFileDialog()
SV.FileName = "Worst_cells"
SV.Filter = "xlsx files (*.xlsx)|*.xlsx|All files (*.*)|*.*"
SV.FilterIndex = 1
SV.RestoreDirectory = True
Dim result As DialogResult = SV.ShowDialog()
If result = DialogResult.OK Then
filename = SV.FileName
Dim XCELAPP As Microsoft.Office.Interop.Excel.Application = Nothing
Dim XWORKBOOK As Microsoft.Office.Interop.Excel.Workbook = Nothing
Dim XSHEET As Microsoft.Office.Interop.Excel.Worksheet = Nothing
Dim misValue As Object = System.Reflection.Missing.Value
XCELAPP = New Excel.Application()
XWORKBOOK = XCELAPP.Workbooks.Add(misValue)
XCELAPP.DisplayAlerts = False
XCELAPP.Visible = False
XSHEET = XWORKBOOK.ActiveSheet
XSHEET.Range("B1").ColumnWidth = 11
For Each column As DataGridViewColumn In DataGridView1.Columns
XSHEET.Cells(1, column.Index + 1) = column.HeaderText
Next
Dim rowCnt As Integer = DataGridView1.Rows.Count
Dim colCnt As Integer = DataGridView1.Columns.Count
Dim batchSize As Integer = 10000
Dim currentRow As Integer = 0
Dim valueObjArray As Object(,) = New Object(batchSize - 1, colCnt - 1) {}
While currentRow < rowCnt
Dim rowIndex As Integer = 0
While rowIndex < batchSize AndAlso currentRow + rowIndex < rowCnt
For colIndex As Integer = 0 To colCnt - 1
valueObjArray(rowIndex, colIndex) = DataGridView1(colIndex, currentRow + rowIndex).Value
Next
rowIndex += 1
End While
Dim colName As String = ColumnLetter(colCnt)
If (currentRow + batchSize + 1) < rowCnt Then
XSHEET.Range("A" + (currentRow + 2).ToString(), colName + (currentRow + batchSize + 1).ToString()).Value2 = valueObjArray
Else
XSHEET.Range("A" + (currentRow + 2).ToString(), colName + (rowCnt + 1).ToString()).Value2 = valueObjArray
End If
XWORKBOOK.SaveAs(filename)
currentRow += batchSize
End While
XCELAPP.DisplayAlerts = True
XWORKBOOK.Close(False)
XCELAPP.Quit()
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(XSHEET)
System.Runtime.InteropServices.Marshal.ReleaseComObject(XWORKBOOK)
System.Runtime.InteropServices.Marshal.ReleaseComObject(XCELAPP)
Catch
End Try
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End If
End If
End Sub
确认使用Marshal.ReleaseComObject。。。;在范围对象上修复OutOfMemory异常。下面是用于测试的代码。您必须用自己的代码替换几行代码。代码的第一部分是生成大量随机数据。第二部分以块的形式写出DataTable行。通过设置xls.Visible=true;您可以看到Excel使用Excel窗口底部的进度条处理每个块
public static void TestExcel(String filename, int maxRows) {
int numCols = 100;
Type[] availTypes = new Type[] { typeof(bool), typeof(int), typeof(double), typeof(String), typeof(DateTime) };
Type[] types = new Type[numCols];
Random r = new Random();
DataTable table = new DataTable();
for (int i = 0; i < numCols; i++) {
Type ty = availTypes[r.Next(availTypes.Length)];
types[i] = ty;
table.Columns.Add("Col" + i, ty);
}
DateTime minDate = new DateTime(1901,01,01);
for (int i = 0; i < maxRows; i++) {
Object[] arr2 = new Object[numCols];
for (int j = 0; j < numCols; j++) {
Object o = null;
Type ty = types[j];
if (ty == typeof(bool))
o = (r.Next(2) == 0 ? false : true);
else if (ty == typeof(int))
o = r.Next(int.MinValue, int.MaxValue);
else if (ty == typeof(double))
o = r.NextDouble();
else if (ty == typeof(String)) {
int len = r.Next(0, 256);
char c = ExcelUtils.ToLetters(r.Next(26))[0];
o = new String(c, len);
}
else if (ty == typeof(DateTime))
o = minDate.AddSeconds(r.Next(int.MaxValue));
arr2[j] = o;
}
table.Rows.Add(arr2);
}
XlFileFormat format = XlFileFormat.xlWorkbookDefault;
if (File.Exists(filename))
File.Delete(filename);
DateTime utcNow = DateTime.UtcNow;
Workbook wb = null;
Worksheet ws = null;
Excel xls = new Excel(); // replace with Application.Excel
xls.Visible = true;
xls.DisplayAlerts = false;
if (xls.Workbooks.Count == 0)
wb = xls.Workbooks.Add();
else
wb = xls.Workbooks[1];
if (wb.Worksheets.Count == 0)
ws = wb.Worksheets.Add();
else
ws = wb.Worksheets[1];
int maxCellsPerInsert = 1000000; // inserting too much data at once results in an out of memory exception
int batchSize = maxCellsPerInsert / table.Columns.Count;
int fromIndex = 0;
int n = table.Rows.Count;
while (fromIndex < n) {
int toIndex = Math.Min(fromIndex + batchSize, n);
Range r0 = ws.get_Range("A" + (fromIndex + 1));
Object[,] arr = DataTableUtils.ToObjectArray(table, false, true, null, fromIndex, toIndex); // replace with your own arr[,] code
Range r00 = r0.Resize(arr.GetLength(0), arr.GetLength(1));
r00.Value = arr;
r00.Dispose(); // replace with Marshal.Release
r0.Dispose(); // replace with Marshal.Release
fromIndex = toIndex;
}
wb.SaveAs(filename, format, AccessMode: XlSaveAsAccessMode.xlNoChange);
wb.Close(false, filename, null);
xls.Quit(false, false);
long length = FileEx.GetFileLengthFast(filename);
double totalSeconds = (DateTime.UtcNow - utcNow).TotalSeconds;
String message = "NumRows: " + maxRows + " duration: " + Math.Round(totalSeconds, 1) + " seconds. File length: " + length + " rows/sec: " + Math.Round(1.0* maxRows / totalSeconds);
}
确认使用Marshal.ReleaseComObject。。。;在范围对象上修复OutOfMemory异常。下面是用于测试的代码。您必须用自己的代码替换几行代码。代码的第一部分是生成大量随机数据。第二部分以块的形式写出DataTable行。通过设置xls.Visible=true;您可以看到Excel使用Excel窗口底部的进度条处理每个块
public static void TestExcel(String filename, int maxRows) {
int numCols = 100;
Type[] availTypes = new Type[] { typeof(bool), typeof(int), typeof(double), typeof(String), typeof(DateTime) };
Type[] types = new Type[numCols];
Random r = new Random();
DataTable table = new DataTable();
for (int i = 0; i < numCols; i++) {
Type ty = availTypes[r.Next(availTypes.Length)];
types[i] = ty;
table.Columns.Add("Col" + i, ty);
}
DateTime minDate = new DateTime(1901,01,01);
for (int i = 0; i < maxRows; i++) {
Object[] arr2 = new Object[numCols];
for (int j = 0; j < numCols; j++) {
Object o = null;
Type ty = types[j];
if (ty == typeof(bool))
o = (r.Next(2) == 0 ? false : true);
else if (ty == typeof(int))
o = r.Next(int.MinValue, int.MaxValue);
else if (ty == typeof(double))
o = r.NextDouble();
else if (ty == typeof(String)) {
int len = r.Next(0, 256);
char c = ExcelUtils.ToLetters(r.Next(26))[0];
o = new String(c, len);
}
else if (ty == typeof(DateTime))
o = minDate.AddSeconds(r.Next(int.MaxValue));
arr2[j] = o;
}
table.Rows.Add(arr2);
}
XlFileFormat format = XlFileFormat.xlWorkbookDefault;
if (File.Exists(filename))
File.Delete(filename);
DateTime utcNow = DateTime.UtcNow;
Workbook wb = null;
Worksheet ws = null;
Excel xls = new Excel(); // replace with Application.Excel
xls.Visible = true;
xls.DisplayAlerts = false;
if (xls.Workbooks.Count == 0)
wb = xls.Workbooks.Add();
else
wb = xls.Workbooks[1];
if (wb.Worksheets.Count == 0)
ws = wb.Worksheets.Add();
else
ws = wb.Worksheets[1];
int maxCellsPerInsert = 1000000; // inserting too much data at once results in an out of memory exception
int batchSize = maxCellsPerInsert / table.Columns.Count;
int fromIndex = 0;
int n = table.Rows.Count;
while (fromIndex < n) {
int toIndex = Math.Min(fromIndex + batchSize, n);
Range r0 = ws.get_Range("A" + (fromIndex + 1));
Object[,] arr = DataTableUtils.ToObjectArray(table, false, true, null, fromIndex, toIndex); // replace with your own arr[,] code
Range r00 = r0.Resize(arr.GetLength(0), arr.GetLength(1));
r00.Value = arr;
r00.Dispose(); // replace with Marshal.Release
r0.Dispose(); // replace with Marshal.Release
fromIndex = toIndex;
}
wb.SaveAs(filename, format, AccessMode: XlSaveAsAccessMode.xlNoChange);
wb.Close(false, filename, null);
xls.Quit(false, false);
long length = FileEx.GetFileLengthFast(filename);
double totalSeconds = (DateTime.UtcNow - utcNow).TotalSeconds;
String message = "NumRows: " + maxRows + " duration: " + Math.Round(totalSeconds, 1) + " seconds. File length: " + length + " rows/sec: " + Math.Round(1.0* maxRows / totalSeconds);
}
经过其他用户的大量测试和帮助,尤其是厌恶,我发现用标准方法无法将大型DataGridView导出到Excel而不将异常抛出内存,我还没有测试Oledb或Xml。对我来说,一个可行的解决方案是导出数据表,这是DGV的数据源。请注意,这种解决方案适用于在DGV填充数据之后在同一过程中进行导出。否则,如果要在以后导出数据,例如在单击按钮之后,则需要将datatable声明为Public,我不会这样做。似乎直接从DGV导出时发生的内存中断是,在从DGV读取数据块并将其复制到Excel range后,这些数据块仍保留在内存中,我不知道这是为什么。此解决方案中的一个关键问题是,从datatable读取数据,然后批量写入Excel。我的情况是,我需要将90.000多行导出到Excel。对于90.000行,我使用了25.000行的批处理大小,这对于90k单元格来说效果很好。但对于我测试的270k或360k等较大的行数,我使用了较小的批处理值10.000行。这是因为我的WinForm已经因为显示一个大DGV而加重了内存方面的负担。所以,如果在DGV中有270k行,那么以25000行为一批进行导出会出现异常。但有了10.000,这还可以,尽管出口时间更长。关于导出时间:90k行,批次为25k,在我的环境中1分钟05秒;270k行10k批次耗时9分钟,360k行10k批次耗时15分钟
Dim filename As String = ""
Dim SV As SaveFileDialog = New SaveFileDialog()
SV.FileName = "Excel export"
SV.Filter = "xlsx files (*.xlsx)|*.xlsx|All files (*.*)|*.*"
SV.FilterIndex = 1
SV.RestoreDirectory = True
Dim result As DialogResult = SV.ShowDialog()
If result = DialogResult.OK Then
filename = SV.FileName
Dim xcelApp As Microsoft.Office.Interop.Excel.Application = Nothing
Dim xWorkbook As Microsoft.Office.Interop.Excel.Workbook = Nothing
Dim xSheet As Microsoft.Office.Interop.Excel.Worksheet = Nothing
Dim misValue As Object = System.Reflection.Missing.Value
xcelApp = New Excel.Application()
xWorkbook = xcelApp.Workbooks.Add(misValue)
xcelApp.DisplayAlerts = False
xcelApp.Visible = False
xSheet = xWorkbook.ActiveSheet
xSheet.Range("B1").ColumnWidth = 11
'export column headers to Excel is shown below
Dim i As Integer = 1
For Each column As DataColumn In dataTab.Columns
xSheet.Cells(1, i) = column.ColumnName
i = i + 1
Next
Dim rowCnt As Integer = dataTab.Rows.Count
Dim colCnt As Integer = dataTab.Columns.Count
Dim batchSize As Integer = 10000 'export will de done in batches
Dim startRow As Integer = 0 'starting row for each batch
Dim valueObjArray As Object(,) = New Object(batchSize - 1, colCnt - 1) {}
'object array with a size of the batch x number of columns
While startRow < rowCnt 'iterate until max row number is exceeded
Dim rowIndex As Integer = 0
'iterate each until row index reaches batch size
While rowIndex < batchSize AndAlso startRow + rowIndex < rowCnt
'iterate each cell in the row until last column is reached
'and assign the value of the cell in datatable to the object array
For colIndex As Integer = 0 To colCnt - 1
valueObjArray(rowIndex, colIndex) =
dataTab.Rows(startRow + rowIndex).Item(colIndex)
Next
rowIndex += 1 'go to new row
End While
Dim colName As String = ColumnLetter(colCnt) 'transform column index to Excel column name
'("if" below) assign object array to Excel range if batch range + starting row is less than total rows
If (startRow + batchSize + 1) < rowCnt Then
Dim r As Excel.Range = xSheet.Range("A" + (startRow + 2).ToString(),
colName + (startRow + batchSize + 1).ToString())
r.Value2 = valueObjArray
System.Runtime.InteropServices.Marshal.ReleaseComObject(r) 'this might be not needed
Else 'if batch range + starting row is more than total rows assign to Excel range only the remaining rows
Dim r As Excel.Range = xSheet.Range("A" + (startRow + 2).ToString(),
colName + (rowCnt + 1).ToString())
r.Value2 = valueObjArray
System.Runtime.InteropServices.Marshal.ReleaseComObject(r) 'this might be not needed
End If
xWorkbook.SaveAs(filename)
startRow += batchSize
End While
xcelApp.DisplayAlerts = True
xWorkbook.Close(False)
xcelApp.Quit()
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(xSheet)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xWorkbook)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xcelApp)
Catch
End Try
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End If
经过其他用户的大量测试和帮助,尤其是厌恶,我发现用标准方法无法将大型DataGridView导出到Excel而不将异常抛出内存,我还没有测试Oledb或Xml。对我来说,一个可行的解决方案是导出数据表,这是DGV的数据源。请注意,这种解决方案适用于在DGV填充数据之后在同一过程中进行导出。否则,如果要在以后导出数据,例如在单击按钮之后,则需要将datatable声明为Public,我不会这样做。似乎直接从DGV导出时发生的内存中断是,在从DGV读取数据块并将其复制到Excel range后,这些数据块仍保留在内存中,我不知道这是为什么。此解决方案中的一个关键问题是,从datatable读取数据,然后批量写入Excel。我的情况是,我需要将90.000多行导出到Excel。对于90000行,我使用了25000行的批量大小,这很有效 对90k细胞来说很好。但对于我测试的270k或360k等较大的行数,我使用了较小的批处理值10.000行。这是因为我的WinForm已经因为显示一个大DGV而加重了内存方面的负担。所以,如果在DGV中有270k行,那么以25000行为一批进行导出会出现异常。但有了10.000,这还可以,尽管出口时间更长。关于导出时间:90k行,批次为25k,在我的环境中1分钟05秒;270k行10k批次耗时9分钟,360k行10k批次耗时15分钟
Dim filename As String = ""
Dim SV As SaveFileDialog = New SaveFileDialog()
SV.FileName = "Excel export"
SV.Filter = "xlsx files (*.xlsx)|*.xlsx|All files (*.*)|*.*"
SV.FilterIndex = 1
SV.RestoreDirectory = True
Dim result As DialogResult = SV.ShowDialog()
If result = DialogResult.OK Then
filename = SV.FileName
Dim xcelApp As Microsoft.Office.Interop.Excel.Application = Nothing
Dim xWorkbook As Microsoft.Office.Interop.Excel.Workbook = Nothing
Dim xSheet As Microsoft.Office.Interop.Excel.Worksheet = Nothing
Dim misValue As Object = System.Reflection.Missing.Value
xcelApp = New Excel.Application()
xWorkbook = xcelApp.Workbooks.Add(misValue)
xcelApp.DisplayAlerts = False
xcelApp.Visible = False
xSheet = xWorkbook.ActiveSheet
xSheet.Range("B1").ColumnWidth = 11
'export column headers to Excel is shown below
Dim i As Integer = 1
For Each column As DataColumn In dataTab.Columns
xSheet.Cells(1, i) = column.ColumnName
i = i + 1
Next
Dim rowCnt As Integer = dataTab.Rows.Count
Dim colCnt As Integer = dataTab.Columns.Count
Dim batchSize As Integer = 10000 'export will de done in batches
Dim startRow As Integer = 0 'starting row for each batch
Dim valueObjArray As Object(,) = New Object(batchSize - 1, colCnt - 1) {}
'object array with a size of the batch x number of columns
While startRow < rowCnt 'iterate until max row number is exceeded
Dim rowIndex As Integer = 0
'iterate each until row index reaches batch size
While rowIndex < batchSize AndAlso startRow + rowIndex < rowCnt
'iterate each cell in the row until last column is reached
'and assign the value of the cell in datatable to the object array
For colIndex As Integer = 0 To colCnt - 1
valueObjArray(rowIndex, colIndex) =
dataTab.Rows(startRow + rowIndex).Item(colIndex)
Next
rowIndex += 1 'go to new row
End While
Dim colName As String = ColumnLetter(colCnt) 'transform column index to Excel column name
'("if" below) assign object array to Excel range if batch range + starting row is less than total rows
If (startRow + batchSize + 1) < rowCnt Then
Dim r As Excel.Range = xSheet.Range("A" + (startRow + 2).ToString(),
colName + (startRow + batchSize + 1).ToString())
r.Value2 = valueObjArray
System.Runtime.InteropServices.Marshal.ReleaseComObject(r) 'this might be not needed
Else 'if batch range + starting row is more than total rows assign to Excel range only the remaining rows
Dim r As Excel.Range = xSheet.Range("A" + (startRow + 2).ToString(),
colName + (rowCnt + 1).ToString())
r.Value2 = valueObjArray
System.Runtime.InteropServices.Marshal.ReleaseComObject(r) 'this might be not needed
End If
xWorkbook.SaveAs(filename)
startRow += batchSize
End While
xcelApp.DisplayAlerts = True
xWorkbook.Close(False)
xcelApp.Quit()
Try
System.Runtime.InteropServices.Marshal.ReleaseComObject(xSheet)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xWorkbook)
System.Runtime.InteropServices.Marshal.ReleaseComObject(xcelApp)
Catch
End Try
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End If
您是否尝试过用于Excel的Oledb提供程序?一个网格中可能需要90000行。用户无法查看90000行。我没有检查Oledb。你认为值得检查一下吗?关于你的问题,一个人怎么可能需要90k行:假设你有一个拥有90k+电池的移动网络,而网络中存在一个主要问题,有成千上万的客户投诉。在这种情况下,工程师需要能够识别顶级单元格贡献者,还需要能够对单元格列表进行后期处理,以便找到交通量变化、KPI降级等。不确定这是否会产生影响,但您不会释放任何范围对象。通常情况下,它类似于范围r=。。。;r、 值2=。。。;Marshal.ReleaseComObject;应该避免代码中的双点。DGV是否绑定到数据表?如果是这样,考虑从DATAROW.ITEMLAMP中取值,而不是通过DGV Cyto.Valk来避免复制数据。对于额外信息的请求,您不会作出响应。你还在寻求解决这个问题的办法吗?我怀疑问题是由于迭代DGV行,从而导致它们变得不共享,并消耗大量内存。可以通过在rows集合上运行empty For Each循环来验证这一点。您是否尝试过用于Excel的Oledb提供程序?一个网格中可能需要90000行。用户无法查看90000行。我没有检查Oledb。你认为值得检查一下吗?关于你的问题,一个人怎么可能需要90k行:假设你有一个拥有90k+电池的移动网络,而网络中存在一个主要问题,有成千上万的客户投诉。在这种情况下,工程师需要能够识别顶级单元格贡献者,还需要能够对单元格列表进行后期处理,以便找到交通量变化、KPI降级等。不确定这是否会产生影响,但您不会释放任何范围对象。通常情况下,它类似于范围r=。。。;r、 值2=。。。;Marshal.ReleaseComObject;应该避免代码中的双点。DGV是否绑定到数据表?如果是这样,考虑从DATAROW.ITEMLAMP中取值,而不是通过DGV Cyto.Valk来避免复制数据。对于额外信息的请求,您不会作出响应。你还在寻求解决这个问题的办法吗?我怀疑问题是由于迭代DGV行,从而导致它们变得不共享,并消耗大量内存。这可以通过在rows集合上运行一个empty For Each循环来验证。我昨天尝试了您在我的原始帖子中关于释放Range对象的建议,见下文。不幸的是,这并没有改变内存消耗,并以抛出异常再次结束。我会根据我的需要修改你的新代码。谢谢你!我更改的代码,没有帮助行之间用;:尺寸r为Excel.Range=XSHEET.RangeA+currentRow+2.ToString,colName+currentRow+batchSize+1.ToString;r、 Value2=valueObjArray;System.Runtime.InteropServices.Marshal。ReleaseComObjectr@Ivaylo编辑您的原始问题,并放置整个更新的代码。您的原始代码在每个块之后调用SaveAs,这是不需要的。此外,基于100万个单元格/143列,最大行批处理大小应为6993。如果您的测试仍然使用10000,那么这就可以解释异常情况。代码中还有其他地方没有释放对象,例如:XSHEET.RangeB1.ColumnWidth=11和XSHEET.Cells1,column.Index+1I会将更新后的代码作为附加答案发布。问题似乎出在DGV本身,尤其是读取它的值,这些值显然保留在内存中。导出DGV后面的数据表解决了这个问题。我还没有测试过just Save和avoiding SaveAs。在处理Excel range时,我的测试没有显示任何更改,但我将它们保存在代码中以防万一。我昨天尝试了您在我的原始帖子中关于发布range对象的建议,请参见下文。不幸的是,这并没有改变内存消耗,并以抛出异常再次结束。我会根据我的需要修改你的新代码。谢谢你!我更改的代码,没有帮助行之间用;:尺寸r为Excel.Range=XSHEET.RangeA+currentRow+2.ToString,colName+currentRow+batchSize+1.ToString;r、 Value2=valueObjArray;System.Runtime.InteropServices.Marshal。ReleaseComObjectr@Ivaylo编辑你的
原始问题,并把整个更新的代码。您的原始代码在每个块之后调用SaveAs,这是不需要的。此外,基于100万个单元格/143列,最大行批处理大小应为6993。如果您的测试仍然使用10000,那么这就可以解释异常情况。代码中还有其他地方没有释放对象,例如:XSHEET.RangeB1.ColumnWidth=11和XSHEET.Cells1,column.Index+1I会将更新后的代码作为附加答案发布。问题似乎出在DGV本身,尤其是读取它的值,这些值显然保留在内存中。导出DGV后面的数据表解决了这个问题。我还没有测试过just Save和avoiding SaveAs。在处理Excel范围时,我的测试没有显示任何更改,但我将它们保存在代码中以防万一。