如何使用剪贴板将数据从Excel Sheet复制到DataTable?

MiB*_*Bol 6 c# datatable excel clipboard xmldocument

我有一个在 Microsoft Framework 3.5 上创建的 Winform 项目。用户可能安装了Windows 7或Windows XP以及Office 2007或更高版本。

我正在研究一个获取剪贴板数据并将其放入 C# 数据表的过程。我已经创建了一个方法来从剪贴板获取原始数据并将其上传到数据表中。

但在某些情况下,Excel 数据显示一个值,但内部有另一个值:

在此输入图像描述

我正在研究一种从 Excel 获取原始数据的方法:

string XmlFmt = "XML Spreadsheet";
var clipboard = Clipboard.GetDataObject();

if (clipboard.GetDataPresent(XmlFmt))
{
    var clipData = clipboard.GetData(XmlFmt);
    StreamReader streamReader = new StreamReader((MemoryStream)clipData);
    streamReader.BaseStream.SetLength(streamReader.BaseStream.Length - 1);

    string xmlText = streamReader.ReadToEnd();
    var stream = new StringReader(xmlText);

    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.LoadXml(xmlText);

    DataSet dsExcelData = new DataSet();
    dsExcelData.ReadXml(new XmlNodeReader(xmlDocument));
}
Run Code Online (Sandbox Code Playgroud)

但是,此方法会检索一个包含多个表的数据集,其中包含 Excel 数据每个部分的配置: 在此输入图像描述 在此输入图像描述

基本上,我想将这些结构转换为仅包含原始数据的简单数据表。有人可以帮助我提示如何实现这一目标?...我不想在此实现中使用第三方库。

MiB*_*Bol 7

我找到了一个干净且防弹的解决方案。这里是代码:

首先,将 XmlDocument 转换为 XElement 的扩展:

/// <summary> Convert XML Document to XDocument </summary>
/// <param name="xmlDocument">Attached XML Document</param>
public static XDocument fwToXDocument(this XmlDocument xmlDocument)
{
    using (XmlNodeReader xmlNodeReader = new XmlNodeReader(xmlDocument))
    {
        xmlNodeReader.MoveToContent();
        return XDocument.Load(xmlNodeReader);
    }
}
Run Code Online (Sandbox Code Playgroud)

完整功能:

private DataTable clipboardExcelToDataTable(bool blnFirstRowHasHeader = false)
{
    string strTime = "S " + DateTime.Now.ToString("mm:ss:fff");
    var clipboard = Clipboard.GetDataObject();
    if (!clipboard.GetDataPresent("XML Spreadsheet")) return null;

    strTime += "\r\nRead " + DateTime.Now.ToString("mm:ss:fff");
    StreamReader streamReader = new StreamReader((MemoryStream)clipboard.GetData("XML Spreadsheet"));
    strTime += "\r\nFinish read " + DateTime.Now.ToString("mm:ss:fff");
    streamReader.BaseStream.SetLength(streamReader.BaseStream.Length - 1);

    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.LoadXml(streamReader.ReadToEnd());
    strTime += "\r\nRead XML Document " + DateTime.Now.ToString("mm:ss:fff");

    XNamespace ssNs = "urn:schemas-microsoft-com:office:spreadsheet";
    DataTable dtData = new DataTable();

    var linqRows = xmlDocument.fwToXDocument().Descendants(ssNs + "Row").ToList<XElement>();

    for (int x = 0; x < linqRows.Max(a => a.Descendants(ssNs + "Cell").Count()); x++)
        dtData.Columns.Add("Column " + (x + 1).ToString());

    int intCol = 0;

    DataRow drCurrent;

    linqRows.ForEach(rowElement =>
        {
            intCol = 0;
            drCurrent = dtData.Rows.Add();
            rowElement.Descendants(ssNs + "Cell")
                .ToList<XElement>()
                .ForEach(cell => drCurrent[intCol++] = cell.Value);
        });

    if (blnFirstRowHasHeader)
    {
        int x = 0;
        foreach (DataColumn dcCurrent in dtData.Columns)
            dcCurrent.ColumnName = dtData.Rows[0][x++].ToString();

        dtData.Rows.RemoveAt(0);
    }

    strTime += "\r\nF " + DateTime.Now.ToString("mm:ss:fff");

    return dtData;
}
Run Code Online (Sandbox Code Playgroud)

该过程大约需要 15 秒才能读取大约 25,000 行。

适用于任何类型的数据。基本上,该方法创建一个与 Excel 工作表结构相同的网格。行或列的合并将填满第一个单元格。默认情况下,所有列都是字符串数据类型。


小智 5

如果它们是平面数据,你可以这样做。

private class Field
{
        public string Valor { get; set; }
}

private class Row
{
        public List<Field> Fields { get; set; }

        public Row(string value)
        {
            Fields = new List<Field>();
            var fieldsString = value.Split(new char[] {'\t'});
            foreach (string f in fieldsString)
            {
                Fields.Add(new Field {Valor = f});
            }
    }
}

public Parse()
{
    var data = Clipboard.GetDataObject();
    var datos = (string)data.GetData(DataFormats.Text);
    var stringRows = datos.Split(new Char[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries);
    var table = new List<Row>(stringRows.Length) ;
    foreach (string stringRow in stringRows)
    {
        table.Add( new Row(stringRow) );
    }
}
Run Code Online (Sandbox Code Playgroud)