【问题标题】:Trying to read an Excel file file stream in C#, I get numbers instead of text尝试在 C# 中读取 Excel 文件文件流,我得到数字而不是文本
【发布时间】:2015-06-12 18:45:36
【问题描述】:

我正在尝试使用 DocumentFormat.OpenXml 来读取上传的 Excel 文件。当我得到文件(HttpPosteFileWrapper)时,我只是试图读取单元格并将它们写入文本字符串。 (以后我会做更多,但我现在只是想习惯 OpenXml。)

我在 Excel 中的数据如下所示:

字段 1 - 字段 2 - 电话 - 城市
IT 部门 - Emp - 7175551234 - Springfield
HR - Emp - 7175556543 - W Springfield

代码如下所示:

var doc = SpreadsheetDocument.Open(file.InputStream, false);
WorkbookPart workbookPart = doc.WorkbookPart;
WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
SheetData thisSheet = worksheetPart.Worksheet.Elements<SheetData>().First();
System.Text.StringBuilder text = new System.Text.StringBuilder();
foreach (Row r in thisSheet.Elements<Row>())
{
    foreach (Cell c in r.Elements<Cell>())
    {
        text.Append(c.CellValue.Text + ",");
    }
    text.AppendLine();
}

它创建的字符串如下所示:

49,51,50,0,1,2,3,4,5,6,7,8,9,10,11,12,13,16,14,15,17,18,19,20 ,21,22,40,41,42,43,44,45,54,\r\n
52,24,23,25,26,27,7306,33,28,29,30,31,17033,32,34,7175555555,7175551234,7175554321,7175550000,35,36,37,36526,40179,38, 39,30,31,17033,32,55,\r\n
53,46,47,48,555,\r\n

数字值似乎通过了。是因为我使用了错误的流类型吗?

编辑:我已经更新了我的代码,现在看起来像这样,但它仍然不能正常工作。我似乎无法看到文本数据。

public ActionResult ProfileImport(IEnumerable<HttpPostedFileBase> files)
{
    // Build file list
    int i = 1;
    foreach (var file in files)
    {
        if (file.ContentLength > 0)
        {

var doc = SpreadsheetDocument.Open(file.InputStream, false);
WorkbookPart workbookPart = doc.WorkbookPart;
WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
SheetData thisSheet = worksheetPart.Worksheet.Elements<SheetData>().First();
System.Text.StringBuilder text = new System.Text.StringBuilder();
foreach (Row r in thisSheet.Elements<Row>())
{
    foreach (Cell c in r.Elements<Cell>())
    {
        string value = c.InnerText;
        if (c.DataType != null && c.DataType.Value == CellValues.SharedString) // Check DataType exists
        {
            var stringTable = workbookPart.GetPartsOfType<SharedStringTablePart>()
                .FirstOrDefault(); // Get Table parts from workbookPart
            if (stringTable != null)
                value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
            text.Append(value + ",");
        }
        else
            text.Append(value + ",");
     }
     text.AppendLine();
 }
 var outText = text.ToString();
}
}
}

文件第一行的实际数据:
AddressDescription, Address1, Address2, City, State, PostalCode, CountryCode, Email, CellPhone, HomePhone, WorkPhone, Fax, OrganizationName, Department, Position, StartDate, EndDate, OrganizationAddress1, OrganizationAddress2 OrganizationCity, OrganizationState, OrganizationPostalCode, OrganizationCountryCode, 关键字

该行的Row.InnerText:
“49515001234567891011121316141517181920212240414243444554”

Row.OuterXml:

"<x:row r=\"1\" spans=\"1:33\" s=\"3\" customFormat=\"1\" x14ac:dyDescent=\"0.25\" xmlns:x14ac=\"http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac\" xmlns:x=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">
    <x:c r=\"A1\" s=\"3\" t=\"s\"><x:v>49</x:v></x:c>
    <x:c r=\"B1\" s=\"3\" t=\"s\"><x:v>51</x:v></x:c>
    <x:c r=\"C1\" s=\"3\" t=\"s\"><x:v>50</x:v></x:c>
    <x:c r=\"D1\" s=\"3\" t=\"s\"><x:v>0</x:v></x:c>
    <x:c r=\"E1\" s=\"3\" t=\"s\"><x:v>1</x:v></x:c>
    <x:c r=\"F1\" s=\"3\" t=\"s\"><x:v>2</x:v></x:c>
    <x:c r=\"G1\" s=\"3\" t=\"s\"><x:v>3</x:v></x:c>
    <x:c r=\"H1\" s=\"3\" t=\"s\"><x:v>4</x:v></x:c>
    <x:c r=\"I1\" s=\"3\" t=\"s\"><x:v>5</x:v></x:c>
    <x:c r=\"J1\" s=\"3\" t=\"s\"><x:v>6</x:v></x:c>
    <x:c r=\"K1\" s=\"3\" t=\"s\"><x:v>7</x:v></x:c>
    <x:c r=\"L1\" s=\"3\" t=\"s\"><x:v>8</x:v></x:c>
    <x:c r=\"M1\" s=\"3\" t=\"s\"><x:v>9</x:v></x:c>
    <x:c r=\"N1\" s=\"3\" t=\"s\"><x:v>10</x:v></x:c>
    <x:c r=\"O1\" s=\"3\" t=\"s\"><x:v>11</x:v></x:c>
    <x:c r=\"P1\" s=\"4\" t=\"s\"><x:v>12</x:v></x:c>
    <x:c r=\"Q1\" s=\"4\" t=\"s\"><x:v>13</x:v></x:c>
    <x:c r=\"R1\" s=\"3\" t=\"s\"><x:v>16</x:v></x:c>
    <x:c r=\"S1\" s=\"3\" t=\"s\"><x:v>14</x:v></x:c>
    <x:c r=\"T1\" s=\"3\" t=\"s\"><x:v>15</x:v></x:c>
    <x:c r=\"U1\" s=\"3\" t=\"s\"><x:v>17</x:v></x:c>
    <x:c r=\"V1\" s=\"3\" t=\"s\"><x:v>18</x:v></x:c>
    <x:c r=\"W1\" s=\"3\" t=\"s\"><x:v>19</x:v></x:c>
    <x:c r=\"X1\" s=\"3\" t=\"s\"><x:v>20</x:v></x:c>
    <x:c r=\"Y1\" s=\"3\" t=\"s\"><x:v>21</x:v></x:c>
    <x:c r=\"Z1\" s=\"3\" t=\"s\"><x:v>22</x:v></x:c>
    <x:c r=\"AA1\" s=\"3\" t=\"s\"><x:v>40</x:v></x:c>
    <x:c r=\"AB1\" s=\"3\" t=\"s\"><x:v>41</x:v></x:c>
    <x:c r=\"AC1\" s=\"3\" t=\"s\"><x:v>42</x:v></x:c>
    <x:c r=\"AD1\" s=\"3\" t=\"s\"><x:v>43</x:v></x:c>
    <x:c r=\"AE1\" s=\"3\" t=\"s\"><x:v>44</x:v></x:c>
    <x:c r=\"AF1\" s=\"3\" t=\"s\"><x:v>45</x:v></x:c>
    <x:c r=\"AG1\" s=\"3\" t=\"s\"><x:v>54</x:v></x:c>
</x:row>"

【问题讨论】:

  • 我已经有一段时间没有在 .net 中使用电子表格了。我记得我经常使用 Range 对象。
  • 该文件是一个 xlsx 工作表文件。
  • 您能否确定无法获取字符串数据的单元格的DataType
  • c.DataType 是 's'。嗯?在 Excel 中,文件单元格都是“常规”。
  • 我现在可以得到文本了。它是一个 SharedString,但该示例将我指向错误的位置。我需要从 workbookPart 中获取 SharedStringTablePart,而不是从 worksheetPart 中获取。

标签: c# excel openxml memorystream


【解决方案1】:

看起来这些是共享字符串表中字符串的索引。在 Excel 文件格式中,字符串数据存储在共享字符串表中,然后在单元格级别进行引用。根据文档,如果数据类型是文本,CellValue 将返回指向StringTable 的索引。

https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.cellvalue%28v=office.14%29.aspx?f=255&MSPPError=-2147217396

不了解您的单元格中的数据类型(根据数据类型有不同的检索方法)。如果是我认为的那样,它将是 SharedString,您需要将其检索为 SharedStringTablePart,如此 MSDN 页面所示:

https://msdn.microsoft.com/en-us/library/hh298534%28v=office.14%29.aspx?f=255&MSPPError=-2147217396

您的代码将如下所示:

foreach (Cell c in r.Elements<Cell>())
{
    string value = c.InnerText;
    if (c.DataType.Value == CellValues.SharedString)
    {
        var stringTable = workbookPart.GetPartsOfType<SharedStringTablePart>()
            .FirstOrDefault();
        if (stringTable != null)
            value = stringTable.SharedStringTable.ElementAt(int.Parse(value)).InnerText;
        text.Append(value + ",");
    }
    else
        text.Append(value + ",");
    text.AppendLine();
}

【讨论】:

  • 感谢您提供代码示例。然而,虽然单元格确实说它们是 SharedString,但 stringTable 始终为“null”。另外,你所说的 theCell.InnerText 是指 c.InnerText;?
  • 是的,我做到了!我改编了一些我为测试共享字符串表假设而编写的代码。但是我只是复制了页面上的代码,让您有机会看到它。整个逻辑基于 MSDN 链接中的代码,这是一个自包含的类,用于从 Excel 单元格中获取值。如果您看一下该类,它可能会为您提取值。
  • 另外,InnerText 有时是正确的数据。如果数据的值是数字,例如电话号码,InnerText 会正确反映这一点。
  • 当然,检查SharedString 值类型是为了防止您在共享字符串表中搜索这些值。在这种情况下,它应该默认为 InnerText 值。
  • 你需要从workBookPart获取stringTable,而不是workSheetPart。然后就可以正常使用了,谢谢解答!
【解决方案2】:

我有同样的问题并找到了解决方案,你只需要添加这个方法,你会得到你需要的确切文本,而不是数字:

        private string ReadExcelCell(Cell cell, WorkbookPart workbookPart)
        {
            var cellValue = cell.CellValue;
            var text = (cellValue == null) ? cell.InnerText : cellValue.Text;
            if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString))
            {
                text = workbookPart.SharedStringTablePart.SharedStringTable
                    .Elements<SharedStringItem>().ElementAt(
                        Convert.ToInt32(cell.CellValue.Text)).InnerText;
            }
            return (text ?? string.Empty).Trim();
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多