使用ExcelDataReader从特定单元格开始读取Excel数据

时间:2014-12-24 09:21:35

标签: c# excel exceldatareader

我正在使用ExcelDataReader从C#中的Excel工作簿中读取数据 但我的Excel工作表的结构使得要读取的数据可以从任何特定单元格开始,而不一定是A1

任何人都可以使用ExcelDataReader建议如何实现这一目标吗?

8 个答案:

答案 0 :(得分:33)

如果您使用的是ExcelDataReader 3+,您会发现没有任何方法可以为您的读者对象设置AsDataSet(),您还需要为ExcelDataReader.DataSet安装另一个包,然后您就可以了使用AsDataSet()方法 此外,IsFirstRowAsColumnNames没有属性,您需要在ExcelDataSetConfiguration内设置。

示例:

using (var stream = File.Open(originalFileName, FileMode.Open, FileAccess.Read))
{
    IExcelDataReader reader;

    // Create Reader - old until 3.4+
    ////var file = new FileInfo(originalFileName);
    ////if (file.Extension.Equals(".xls"))
    ////    reader = ExcelDataReader.ExcelReaderFactory.CreateBinaryReader(stream);
    ////else if (file.Extension.Equals(".xlsx"))
    ////    reader = ExcelDataReader.ExcelReaderFactory.CreateOpenXmlReader(stream);
    ////else
    ////    throw new Exception("Invalid FileName");
    // Or in 3.4+ you can only call this:
    reader = ExcelDataReader.ExcelReaderFactory.CreateReader(stream)

    //// reader.IsFirstRowAsColumnNames
    var conf = new ExcelDataSetConfiguration
    {
        ConfigureDataTable = _ => new ExcelDataTableConfiguration
        {
            UseHeaderRow = true 
        }
    };

    var dataSet = reader.AsDataSet(conf);
    var dataTable = dataSet.Tables[0];

    //...
}

您可以找到单元格引用的行号和列号,如下所示:

var cellStr = "AB2"; // var cellStr = "A1";
var match = Regex.Match(cellStr, @"(?<col>[A-Z]+)(?<row>\d+)");
var colStr = match.Groups["col"].ToString();
var col = colStr.Select((t, i) => (colStr[i] - 64) * Math.Pow(26, colStr.Length - i - 1)).Sum();
var row = int.Parse(match.Groups["row"].ToString());

现在你可以使用一些循环从这个单元格读取数据:

for (var i = row; i < dataTable.Rows.Count; i++)
{
    for (var j = col; j < dataTable.Columns.Count; j++)
    {
        var data = dataTable.Rows[i][j];
    }
}

更新:

您可以使用此配置在读取时过滤Excel工作表的行和列:

var i = 0;
var conf = new ExcelDataSetConfiguration
{
    UseColumnDataType = true,
    ConfigureDataTable = _ => new ExcelDataTableConfiguration
    {
        FilterRow = rowReader => fromRow <= ++i - 1,
        FilterColumn = (rowReader, colIndex) => fromCol <= colIndex,
        UseHeaderRow = true
    }
};

答案 1 :(得分:16)

为了更清楚,我将从头开始。

我将依赖https://exceldatareader.codeplex.com/中的示例代码,但需要进行一些修改以避免不便。

以下代码检测文件格式,xls或xlsx。

FileStream stream = File.Open(filePath, FileMode.Open, FileAccess.Read);
IExcelDataReader excelReader;

//1. Reading Excel file
if (Path.GetExtension(filePath).ToUpper() == ".XLS")
{
    //1.1 Reading from a binary Excel file ('97-2003 format; *.xls)
    excelReader = ExcelReaderFactory.CreateBinaryReader(stream);
}
else
{
    //1.2 Reading from a OpenXml Excel file (2007 format; *.xlsx)
    excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
}

//2. DataSet - The result of each spreadsheet will be created in the result.Tables
DataSet result = excelReader.AsDataSet();

//3. DataSet - Create column names from first row
excelReader.IsFirstRowAsColumnNames = false;

现在我们可以更方便地访问文件内容。我使用DataTable。以下是访问特定单元格并在控制台中打印其值的示例:

DataTable dt = result.Tables[0];
Console.WriteLine(dt.Rows[rowPosition][columnPosition]);

如果您不想使用DataTable,可以执行以下操作:

Console.WriteLine(result.Tables[0].Rows[rowPosition][columnPosition]);

重要的是不要尝试超出表格的限制,为此您可以看到行数和列数,如下所示:

Console.WriteLine(result.Tables[0].Rows.Count);
Console.WriteLine(result.Tables[0].Columns.Count);

最后,当你完成后,你应该关闭阅读器并释放资源:

//5. Free resources (IExcelDataReader is IDisposable)
excelReader.Close();

我希望你觉得它很有用。

(我知道这个问题已经过时了,但我做了这个贡献来增强知识库,因为关于这个库的特定实现的材料很少。)

答案 2 :(得分:6)

对于ExcelDataReader v3.6.0及更高版本。 我为在Rows上进行迭代而苦苦挣扎。因此,上述代码还有更多内容。希望它对至少有帮助。

private void button1_Click(object sender, EventArgs e)
{

    using (SqlConnection connection = new SqlConnection(myConnection))
    {
        SqlCommand command = connection.CreateCommand();
        SqlTransaction transaction = connection.BeginTransaction("MyTransaction");

        command.Connection = connection;
        command.Transaction = transaction;
        try
        {
            command.CommandText = $"Insert into Elevi(Name,Age) values({textBox1.Text},{textBox2.Text})";
            command.ExecuteNonQuery();
            transaction.Commit();
        }
        catch(Exception a)
        {
            MessageBox.Show(a.Message);
        }
    }
}

答案 3 :(得分:3)

一种方法:

FileStream stream = File.Open(@"c:\working\test.xls", FileMode.Open, FileAccess.Read);

IExcelDataReader excelReader = ExcelReaderFactory.CreateBinaryReader(stream);

excelReader.IsFirstRowAsColumnNames = true;

DataSet result = excelReader.AsDataSet();

result.Tables包含工作表,result.tables[0].Rows包含单元格行。

答案 4 :(得分:3)

我发现这对于从特定列和行

中读取非常有用
user_capacity

答案 5 :(得分:0)

使用ExcelReaderFactory 3.1和更高版本非常容易:

using (var openFileDialog1 = new OpenFileDialog { Filter = "Excel Workbook|*.xls;*.xlsx;*.xlsm", ValidateNames = true })
{
    if (openFileDialog1.ShowDialog() == DialogResult.OK)
    {
        var fs = File.Open(openFileDialog1.FileName, FileMode.Open, FileAccess.Read);
        var reader = ExcelReaderFactory.CreateBinaryReader(fs);
        var dataSet = reader.AsDataSet(new ExcelDataSetConfiguration
        {
            ConfigureDataTable = _ => new ExcelDataTableConfiguration
            {
                UseHeaderRow = true // Use first row is ColumnName here :D
            }
        });
        if (dataSet.Tables.Count > 0)
        {
            var dtData = dataSet.Tables[0];
            // Do Something
        }
    }
}

答案 6 :(得分:0)

public static DataTable ConvertExcelToDataTable(string filePath, bool isXlsx = false)
{
    System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
    //open file and returns as Stream
        using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read))
        {
                using (var reader = ExcelReaderFactory.CreateReader(stream))
                {

                    var conf = new ExcelDataSetConfiguration
                    {
                        ConfigureDataTable = _ => new ExcelDataTableConfiguration
                        {
                            UseHeaderRow = true
                        }
                    };

                    var dataSet = reader.AsDataSet(conf);

                    // Now you can get data from each sheet by its index or its "name"
                    var dataTable = dataSet.Tables[0];

                    Console.WriteLine("Total no of rows  " + dataTable.Rows.Count);
                    Console.WriteLine("Total no of Columns  " + dataTable.Columns.Count);

                    return dataTable;

                }

        }
   
}

答案 7 :(得分:-3)

您可以使用.NET库执行相同的操作,我认为这更直接。

string ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0; data source={path of your excel file}; Extended Properties=Excel 12.0;";

        OleDbConnection objConn = null;
        System.Data.DataTable dt = null;
        //Create connection object by using the preceding connection string.
        objConn = new OleDbConnection(connString);
        objConn.Open();
        //Get the data table containg the schema guid.
        dt = objConn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
        string sql = string.Format("select * from [{0}$]", sheetName);
        var adapter = new System.Data.OleDb.OleDbDataAdapter(sql, ConnectionString);
        var ds = new System.Data.DataSet();
        string tableName = sheetName;
        adapter.Fill(ds, tableName);
        System.Data.DataTable data = ds.Tables[tableName];

在数据表中包含数据后,您可以像通常使用DataTable类一样访问它们。