在 C# 中快速获取 Excel 范围作为文本数组或单元格格式的方法?
Fast way to get Excel range as array of texts or cell formats in C#?
数组操作比 VSTO 中的范围操作快得多,所以目前我正在使用
object[,] RangeValues = wsh.get_Range("A1:" + lastCell.Address).Value2;
效果不错。可悲的是,我有一些不一致的数据。有时是0.45
,有时是0.45%
,当然后来我在代码中看到的是0.0045
。遗憾的是,从 "business" 的角度来看,这两个值都意味着 0.45
。我不能强制一致性,文件来自各种我没有任何权限的来源。这是我需要处理的事情。
办法当然是看格式,或者看显示文字,里面有没有%
标志。如果有,我只需要将值乘以 100。遗憾的是,如果我尝试:
object[,] RangeValues = wsh.get_Range("A1:" + lastCell.Address).Text;
我收到无法将 DBNull
转换为 object[,]
的消息。那么有什么方法可以让我一次加载所有文本或格式,而无需在 mu 循环的每一步都进行彻底的代码 <-> 工作表边框?
这可能是一种糟糕的方法,但请考虑将您的 excel 文件重写为新的 excel 文件,并在此过程中转换为文本格式。我建议这样做只是因为根据您对问题的评论,您可能在原始文件中没有写权限。请在此处查看如何转换整个文件 [不包括新文件创建] 的示例:
或者,MSDN 在这里讨论了一种使用 Spire 将整个文件导出为文本文件的方法[披露 - 我自己没有使用过]:https://code.msdn.microsoft.com/windowsdesktop/Export-Excel-Data-to-Text-015bc013
我认为从 excel 读取大量非协调数据的最简单方法如下
在 C# 中将 excel 文件保存在 XML 电子表格 2003(*xml) 中。这将生成包含所有数据和样式的 xml 文件。 C# 保存方法 - Workbook.SaveAs with FileFormat value = XlFileFormat.xlXMLSpreadsheet
解析 xml 文件并提取格式为
的数据
- 删除临时文件
例子:
Excel
XML
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11"
ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="s62">
<NumberFormat ss:Format="0%"/>
</Style>
</Styles>
<Worksheet ss:Name="Sheet1">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="5" x:FullColumns="1"
x:FullRows="1" ss:DefaultRowHeight="15">
<Row ss:AutoFitHeight="0">
<Cell>
<Data ss:Type="String">Data</Data>
</Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell>
<Data ss:Type="Number">45</Data>
</Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell ss:StyleID="s62">
<Data ss:Type="Number">0.45</Data>
</Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell>
<Data ss:Type="String">String</Data>
</Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell>
<Data ss:Type="Number">45.5</Data>
</Cell>
</Row>
</Table>
</Worksheet>
为简单起见,我删除了一些节点。需要分析以下元素才能正确提取数据
- Workbook\Worksheet\Table\Row\Cell\Data - 包含格式化为固定区域性的数据
- Workbook\Worksheet\Table\Row\Cell\Data,属性 ss:Type - 包含数据元素内容的数据类型
- Workbook\Worksheet\Table\Row\Cell,属性 ss:StyleID - 对样式的引用,对于您的情况,只需要正确识别数字格式为百分比的单元格(需要乘以 100)
- Workbook\Styles\Style,属性 ss:ID - 用于引用单元格样式的样式 ID
- Workbook\Styles\Style\NumberFormat,属性 ss:Format - 如果以 % 结尾且数据类型为 Number -> 它是百分比
解析器逻辑:
- 单元格中的字符串类型 -> 按原样转换
- 在单元格中输入数字。如果格式以 '%' 结尾 -> 乘以 100,否则按原样使用。
如果数据量不是很大(小于 200-300),可以从 C# 中逐个单元格地进行分析,而无需以 xml 格式保存文件。
正在检测 Excel 单元格格式
要查找单元格的格式,请使用 Excel 的 Cell("format",A1)
函数,而不是查询数据类型,这会更慢、更难并且容易出现问题,例如:0.45 % != 45%。
private void button1_Click(object sender, EventArgs e)
{
// evaluate the Format of Cells A1 thru to A7
using (var rnEvaluate = xlApp.Range["C1:C1"].WithComCleanup())
{
for (int i = 1; i < 8; i++)
{
rnEvaluate.Resource.Value2 = "=CELL(\"format\",A" + i.ToString() + ")";
string cellFormat = GetExcelCellFormat(rnEvaluate.Resource.Value2);
System.Diagnostics.Debug.Write(cellFormat);
}
}
}
private string GetExcelCellFormat(string cellFormat = "G")
{
switch (cellFormat.Substring(0, 1))
{
case "F" :
return "Number";
break;
case "P" :
return "Percentage";
break;
case "C":
return "Currency";
break;
case "D":
return "Date";
break;
default :
return "General";
break;
}
}
.WithComCleanup()
是因为我用的是VSTO Contrib.
一次检测所有 Excel 单元格格式
Is there any way that would allow me to load texts or formats all at once?
只需使用上述方法检测所有单元格格式(使用自动填充)并将它们添加到一个objectArray。举例来说,我想知道 A 列和 B 列的单元格格式:
使用此 VBA 代码我可以获得所有单元格格式(一次无需遍历单元格):
Range("C1").Select
ActiveCell.Value2 = "=CELL(""format"",A1)"
'Fill Down
Range("C1").Select
Selection.AutoFill Destination:=Range("C1:C6"), Type:=xlFillDefault
'Fill Across
Range("C1:C6").Select
Selection.AutoFill Destination:=Range("C1:D6"), Type:=xlFillDefault
上面的 VBA 代码转换为 C# 并将格式存储在对象数组中:
var filepath = @"C:\temp\test\book2.xlsx";
var xlApp = new Microsoft.Office.Interop.Excel.Application();
//Optional but recommended if the user shouldn't see Excel.
xlApp.Visible = false;
xlApp.ScreenUpdating = false;
//AddToMru parameter is optional, but recommended in automation scenarios.
var workbook = xlApp.Workbooks.Open(filepath, AddToMru: false);
//This operation may take a little bit of time but no where near 15 minutes!!!
var cell = xlApp.Range["C1:C1"];
cell.Value2 = "=CELL(\"format\",A1)";
//Fill Down
cell.AutoFill(xlApp.Range["C1:C6"], Microsoft.Office.Interop.Excel.XlAutoFillType.xlFillDefault);
//Fill Across
cell = xlApp.Range["C1:C6"];
cell.AutoFill(xlApp.Range["C1:D6"], Microsoft.Office.Interop.Excel.XlAutoFillType.xlFillDefault);
//Get cell formats into object array
object[,] rangeFormats = xlApp.get_Range("C1:D6").Value2;
Excel 百分比转换技巧
I have some inconsistent data. Sometimes there is 0.45, and sometimes 0.45%
如果您遇到的唯一数据不一致是 % 值,那么这里有一个技巧。
大概百分比值将在一列中,要转换它们,请复制值列(在 A 列中):
确保您设置的列的值为 100(如 B 列所示)
右键单击 100's 列中的单元格并选择选择性粘贴:
选择值并相乘:
Excel 将它们转换为实数:
显然,您可以通过编程方式执行此操作。只需将操作记录为宏并将 VBA 转换为 C#。
and of course later i see it as 0.0045 in code.
注意:代码是对的,0.45%不是45%,0.45%不到半个百分点!如果某个特定客户向您发送文件,希望您打破数学定律并处理 0.45% = 45%,那么他们很有可能突然开始增加 100 倍或减少 100 倍。我会礼貌地指出他们需要改变它。不要尝试围绕这个进行编程。如果这就是您想要查看单元格格式的原因,那么您所做的只是对症状进行故障排除,而不是修复会加剧问题并隐藏更大问题的根本原因。礼貌地向您无法控制的来源 指出 可能存在 100 倍的大问题并坚持需要更正。否则我希望在 DailyWTF 中看到一个关于它的搞笑故事,其中包含以下代码:
var val = rangeValues[1,1].ToString();
var cellFormat = rangeFormat[1,1].ToString();
if (val.EndsWith("%") && val.Replace("%","") < 1 && cellFormat == "G") {
dailyWTFval = val.Replace("%","") * 100;
}
else
dailyWTFval = val;
}
数组操作比 VSTO 中的范围操作快得多,所以目前我正在使用
object[,] RangeValues = wsh.get_Range("A1:" + lastCell.Address).Value2;
效果不错。可悲的是,我有一些不一致的数据。有时是0.45
,有时是0.45%
,当然后来我在代码中看到的是0.0045
。遗憾的是,从 "business" 的角度来看,这两个值都意味着 0.45
。我不能强制一致性,文件来自各种我没有任何权限的来源。这是我需要处理的事情。
办法当然是看格式,或者看显示文字,里面有没有%
标志。如果有,我只需要将值乘以 100。遗憾的是,如果我尝试:
object[,] RangeValues = wsh.get_Range("A1:" + lastCell.Address).Text;
我收到无法将 DBNull
转换为 object[,]
的消息。那么有什么方法可以让我一次加载所有文本或格式,而无需在 mu 循环的每一步都进行彻底的代码 <-> 工作表边框?
这可能是一种糟糕的方法,但请考虑将您的 excel 文件重写为新的 excel 文件,并在此过程中转换为文本格式。我建议这样做只是因为根据您对问题的评论,您可能在原始文件中没有写权限。请在此处查看如何转换整个文件 [不包括新文件创建] 的示例:
或者,MSDN 在这里讨论了一种使用 Spire 将整个文件导出为文本文件的方法[披露 - 我自己没有使用过]:https://code.msdn.microsoft.com/windowsdesktop/Export-Excel-Data-to-Text-015bc013
我认为从 excel 读取大量非协调数据的最简单方法如下
在 C# 中将 excel 文件保存在 XML 电子表格 2003(*xml) 中。这将生成包含所有数据和样式的 xml 文件。 C# 保存方法 - Workbook.SaveAs with FileFormat value = XlFileFormat.xlXMLSpreadsheet
解析 xml 文件并提取格式为
的数据
- 删除临时文件
例子:
Excel
XML
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="Calibri" x:CharSet="204" x:Family="Swiss" ss:Size="11"
ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="s62">
<NumberFormat ss:Format="0%"/>
</Style>
</Styles>
<Worksheet ss:Name="Sheet1">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="5" x:FullColumns="1"
x:FullRows="1" ss:DefaultRowHeight="15">
<Row ss:AutoFitHeight="0">
<Cell>
<Data ss:Type="String">Data</Data>
</Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell>
<Data ss:Type="Number">45</Data>
</Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell ss:StyleID="s62">
<Data ss:Type="Number">0.45</Data>
</Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell>
<Data ss:Type="String">String</Data>
</Cell>
</Row>
<Row ss:AutoFitHeight="0">
<Cell>
<Data ss:Type="Number">45.5</Data>
</Cell>
</Row>
</Table>
</Worksheet>
为简单起见,我删除了一些节点。需要分析以下元素才能正确提取数据
- Workbook\Worksheet\Table\Row\Cell\Data - 包含格式化为固定区域性的数据
- Workbook\Worksheet\Table\Row\Cell\Data,属性 ss:Type - 包含数据元素内容的数据类型
- Workbook\Worksheet\Table\Row\Cell,属性 ss:StyleID - 对样式的引用,对于您的情况,只需要正确识别数字格式为百分比的单元格(需要乘以 100)
- Workbook\Styles\Style,属性 ss:ID - 用于引用单元格样式的样式 ID
- Workbook\Styles\Style\NumberFormat,属性 ss:Format - 如果以 % 结尾且数据类型为 Number -> 它是百分比
解析器逻辑:
- 单元格中的字符串类型 -> 按原样转换
- 在单元格中输入数字。如果格式以 '%' 结尾 -> 乘以 100,否则按原样使用。
如果数据量不是很大(小于 200-300),可以从 C# 中逐个单元格地进行分析,而无需以 xml 格式保存文件。
正在检测 Excel 单元格格式
要查找单元格的格式,请使用 Excel 的 Cell("format",A1)
函数,而不是查询数据类型,这会更慢、更难并且容易出现问题,例如:0.45 % != 45%。
private void button1_Click(object sender, EventArgs e)
{
// evaluate the Format of Cells A1 thru to A7
using (var rnEvaluate = xlApp.Range["C1:C1"].WithComCleanup())
{
for (int i = 1; i < 8; i++)
{
rnEvaluate.Resource.Value2 = "=CELL(\"format\",A" + i.ToString() + ")";
string cellFormat = GetExcelCellFormat(rnEvaluate.Resource.Value2);
System.Diagnostics.Debug.Write(cellFormat);
}
}
}
private string GetExcelCellFormat(string cellFormat = "G")
{
switch (cellFormat.Substring(0, 1))
{
case "F" :
return "Number";
break;
case "P" :
return "Percentage";
break;
case "C":
return "Currency";
break;
case "D":
return "Date";
break;
default :
return "General";
break;
}
}
.WithComCleanup()
是因为我用的是VSTO Contrib.
一次检测所有 Excel 单元格格式
Is there any way that would allow me to load texts or formats all at once?
只需使用上述方法检测所有单元格格式(使用自动填充)并将它们添加到一个objectArray。举例来说,我想知道 A 列和 B 列的单元格格式:
使用此 VBA 代码我可以获得所有单元格格式(一次无需遍历单元格):
Range("C1").Select
ActiveCell.Value2 = "=CELL(""format"",A1)"
'Fill Down
Range("C1").Select
Selection.AutoFill Destination:=Range("C1:C6"), Type:=xlFillDefault
'Fill Across
Range("C1:C6").Select
Selection.AutoFill Destination:=Range("C1:D6"), Type:=xlFillDefault
上面的 VBA 代码转换为 C# 并将格式存储在对象数组中:
var filepath = @"C:\temp\test\book2.xlsx";
var xlApp = new Microsoft.Office.Interop.Excel.Application();
//Optional but recommended if the user shouldn't see Excel.
xlApp.Visible = false;
xlApp.ScreenUpdating = false;
//AddToMru parameter is optional, but recommended in automation scenarios.
var workbook = xlApp.Workbooks.Open(filepath, AddToMru: false);
//This operation may take a little bit of time but no where near 15 minutes!!!
var cell = xlApp.Range["C1:C1"];
cell.Value2 = "=CELL(\"format\",A1)";
//Fill Down
cell.AutoFill(xlApp.Range["C1:C6"], Microsoft.Office.Interop.Excel.XlAutoFillType.xlFillDefault);
//Fill Across
cell = xlApp.Range["C1:C6"];
cell.AutoFill(xlApp.Range["C1:D6"], Microsoft.Office.Interop.Excel.XlAutoFillType.xlFillDefault);
//Get cell formats into object array
object[,] rangeFormats = xlApp.get_Range("C1:D6").Value2;
Excel 百分比转换技巧
I have some inconsistent data. Sometimes there is 0.45, and sometimes 0.45%
如果您遇到的唯一数据不一致是 % 值,那么这里有一个技巧。
大概百分比值将在一列中,要转换它们,请复制值列(在 A 列中):
确保您设置的列的值为 100(如 B 列所示)
右键单击 100's 列中的单元格并选择选择性粘贴:
选择值并相乘:
Excel 将它们转换为实数:
显然,您可以通过编程方式执行此操作。只需将操作记录为宏并将 VBA 转换为 C#。
and of course later i see it as 0.0045 in code.
注意:代码是对的,0.45%不是45%,0.45%不到半个百分点!如果某个特定客户向您发送文件,希望您打破数学定律并处理 0.45% = 45%,那么他们很有可能突然开始增加 100 倍或减少 100 倍。我会礼貌地指出他们需要改变它。不要尝试围绕这个进行编程。如果这就是您想要查看单元格格式的原因,那么您所做的只是对症状进行故障排除,而不是修复会加剧问题并隐藏更大问题的根本原因。礼貌地向您无法控制的来源 指出 可能存在 100 倍的大问题并坚持需要更正。否则我希望在 DailyWTF 中看到一个关于它的搞笑故事,其中包含以下代码:
var val = rangeValues[1,1].ToString();
var cellFormat = rangeFormat[1,1].ToString();
if (val.EndsWith("%") && val.Replace("%","") < 1 && cellFormat == "G") {
dailyWTFval = val.Replace("%","") * 100;
}
else
dailyWTFval = val;
}