Как использовать буфер обмена для копирования данных из листа Excel в DataTable?

У меня есть проект Winform, созданный в Microsoft Framework 3.5. Возможно, пользователи установили Windows 7 или Windows XP, а также Office 2007 или выше.

Я работаю над процедурой, чтобы получить данные буфера обмена и вставить в C # DataTable. Я уже создал метод для получения необработанных данных из буфера обмена и загрузки его в DataTable.

Но в некоторых случаях данные 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)); } 

Но этот метод возвращает мне DataSet с краткими таблицами с конфигурацией каждой части данных Excel: введите описание изображения здесь введите описание изображения здесь

В принципе, я хочу преобразовать эти структуры в простой DataTable только с необработанными данными. Кто-то может помочь мне с намеком, как это достичь? … Я не хочу использовать стороннюю библиотеку в этой реализации.

    Если они плоские данные, вы можете сделать это так.

     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) ); } } 

    в некоторых случаях данные Excel показывают значение, но внутренне имеют другое.

    Использование метода XML является причиной этой внутренней структуры нескольких типов данных. Попробуйте этот метод вместо этого:

     private void PasteFromExcel() { DataTable tbl = new DataTable(); tbl.TableName = "ImportedTable"; List<string> data = new List<string>(ClipboardData.Split('\n')); bool firstRow = true; if (data.Count > 0 && string.IsNullOrWhiteSpace(data[data.Count - 1])) { data.RemoveAt(data.Count - 1); } foreach (string iterationRow in data) { string row = iterationRow; if (row.EndsWith("\r")) { row = row.Substring(0, row.Length - "\r".Length); } string[] rowData = row.Split(new char[] { '\r', '\x09' }); DataRow newRow = tbl.NewRow(); if (firstRow) { int colNumber = 0; foreach (string value in rowData) { if (string.IsNullOrWhiteSpace(value)) { tbl.Columns.Add(string.Format("[BLANK{0}]", colNumber)); } else if (!tbl.Columns.Contains(value)) { tbl.Columns.Add(value); } else { tbl.Columns.Add(string.Format("Column {0}", colNumber)); } colNumber++; } firstRow = false; } else { for (int i = 0; i < rowData.Length; i++) { if (i >= tbl.Columns.Count) break; newRow[i] = rowData[i]; } tbl.Rows.Add(newRow); } } DataGridView1.DataSource = tbl; } 

    Ссылка: http://www.seesharpdot.net/?p=221

    Редактировать:

    Я проделал некоторые тесты и даже используя формат буфера обмена XML Spreadsheet, данные могут храниться в экспоненциальной нотации:

    введите описание изображения здесь

    Вы можете обнаружить и преобразовать эти числа: проанализировать число из экспоненциальной нотации

    Я нашел чистое и пуленепробиваемое решение. Здесь код:

    Во-первых, расширение для преобразования 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); } } 

    Полная функция:

     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 {0}".fwFormat(x + 1)); 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; } 

    Процесс занимает ~ 15 секунд, чтобы прочитать ~ 25 000 строк.

    Отлично работает для любых данных. В принципе, метод создает сетку с той же структурой Excel WorkSheet. Слияние строк или столбцов заполняет первую ячейку. По умолчанию все столбцы будут содержать DataType.

    Давайте будем гением компьютера.