从Excel粘贴到C#应用程序,保持完整的精度
我有一个Excel电子表格中的数据,如下所示:
- 0.69491375
- 0.31220394
单元格格式为百分比,并设置为显示两位小数。 所以他们出现在Excel中:
- 69.49%
- 31.22%
我有一个C#程序从Clipboard
parsing这些数据。
var dataObj = Clipboard.GetDataObject(); var format = DataFormats.CommaSeparatedValue; if (dataObj != null && dataObj.GetDataPresent(format)) { var csvData = dataObj.GetData(format); // do something }
问题是, csvData
包含Excel的显示值,即“69.49%”和“ csvData
%”。 它不包含额外小数位的完整精度。
我曾尝试使用各种不同的DataFormats
值,但数据只包含来自Excel的显示值,例如:
-
DataFormats.Dif
-
DataFormats.Rtf
-
DataFormats.UnicodeText
- 等等
作为testing,我安装了LibreOffice Calc,并将Excel中的相同单元格复制/粘贴到Calc中。 Calc保留了原始数据的完整精度。
很显然,Excel将这些数据放在其他程序可以访问的地方。 我怎样才能从我的C#应用程序访问它?
编辑 – 下一步。
我已经下载了LibreOffice Calc源代码,并且会有一个捅过头来看看我是否可以find他们如何从Excel复制数据的完整上下文。
我还对从剪贴板返回的数据对象进行了一次GetFormats()
调用,并获得了24种不同数据格式的列表,其中一些不在DataFormats
枚举中。 这些格式包括Biff12
, Biff8
, Biff5
, Format129
等其他格式,我不熟悉,所以我会调查这些,并作出回应,如果我做任何发现…
也不是一个完整的答案,但对问题的一些进一步的见解:
当您复制单个Excel单元格时,最终剪贴板中将包含一个完整的Excel工作簿,其中包含一个电子表格,该电子表格又包含一个单元格:
var dataObject = Clipboard.GetDataObject(); var mstream = (MemoryStream)dataObject.GetData("XML Spreadsheet"); // Note: For some reason we need to ignore the last byte otherwise // an exception will occur... mstream.SetLength(mstream.Length - 1); var xml = XElement.Load(mstream);
现在,当您将XElement的内容转储到控制台时,您可以看到您确实获得了完整的Excel工作簿。 此外,“XML电子表格”格式包含存储在单元格中的数字的内部表示。 所以我想你可以使用Linq-To-Xml或类似的方式来获取你需要的数据:
XNamespace ssNs = "urn:schemas-microsoft-com:office:spreadsheet"; var numbers = xml.Descendants(ssNs + "Data"). Where(e => (string)e.Attribute(ssNs + "Type") == "Number"). Select(e => (double)e);
我也尝试使用Excel数据读取器读取Biff格式,但所得到的DataSets总是空着…
BIFF格式是微软公开的规范。 (注意,我说规格不标准)。 阅读这个来了解正在发生的事情。
那么你看到的那些BIFF对应于一些Excel格式。 BIFF5是Excel 5.0和95中的XLS,BIFF8是Excel 97到2003中的XLS,BIFF12是Excel 2003中的XLSB,注意Excel 2007也可以生成它们(我猜也是Excel 2010)。 这里有一些文档,也可以在这里 (来自OpenOffice),可以帮助你理解那里的二进制文件…
无论如何,过去已经做了一些工作来parsingC ++,Java,VB中的这些文档,并在C#中使用它。 比如这个BIFF12 Reader , NExcel项目, ExcelLibrary等等。
特别是NExcel会让你传递一个可以从剪贴板数据创build的数据stream,然后查询NExcel获取数据。 如果你打算采用源代码,那么我认为ExcelLibrary更具可读性。
你可以得到像这样的stream:
var dataobject = System.Windows.Forms.Clipboard.GetDataObject(); var stream = (System.IO.Stream)dataobject.GetData(format);
和NExcel一起阅读stream将是这样的:
var wb = getWorkbook(stream); var sheet = wb.Sheets[0]; var somedata = sheet.getCell(0, 0).Contents;
我想从微软的实际Office库也可以工作。
我知道这不是全部的故事,请分享它是如何发展的。 如果我有机会会尝试。