11

我已经在互联网上搜索过这个问题,但真的找不到这样的问题。每个人都在寻找一种在 excel 文件中导入单个工作表的方法,但我想要的是在不知道工作表名称的情况下将文件中的所有工作表导入到DataTable's 中。DataSet

我以前没有用 Excel 做过很多事情。这是我在互联网上找到的示例和部分工作代码,它只解析给定的工作表名称:

public static DataSet Parse(string fileName, string workSheetName)
{
    string connectionString = string.Format("provider=Microsoft.Jet.OLEDB.4.0; data source={0};Extended Properties=Excel 8.0;", fileName);
    string query = string.Format("SELECT * FROM [{0}$]", workSheetName);

    DataSet data = new DataSet();
    using (OleDbConnection con = new OleDbConnection(connectionString))
    {
        con.Open();
        OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
        adapter.Fill(data);
    }

    return data;
}

如您所见,在上面的代码中,应该传入 workSheetName,这样查询就可以知道在哪里查看要导入的内容。就我而言,我希望它遍历所有工作表,无论它们的名称如何,并将它们导入到个人DataTable的 aDataSet中。

所以本质上,最后的事情将是DataSet每个DataTable都为导入文件中的每个工作表保存行。

4

5 回答 5

19

这是我想出的代码,它运行良好,但我看到其他人已经添加了答案:

static DataSet Parse(string fileName)
{
    string connectionString = string.Format("provider=Microsoft.Jet.OLEDB.4.0; data source={0};Extended Properties=Excel 8.0;", fileName);


    DataSet data = new DataSet();

    foreach(var sheetName in GetExcelSheetNames(connectionString))
    {
        using (OleDbConnection con = new OleDbConnection(connectionString))
        {    
            var dataTable = new DataTable();
            string query = string.Format("SELECT * FROM [{0}]", sheetName);
            con.Open();
            OleDbDataAdapter adapter = new OleDbDataAdapter(query, con);
            adapter.Fill(dataTable);
            data.Tables.Add(dataTable);
        }
    }

    return data;
}

static string[] GetExcelSheetNames(string connectionString)
{
        OleDbConnection con = null;
        DataTable dt = null;
        con= new OleDbConnection(connectionString);
        con.Open();
        dt = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);

        if (dt == null)
        {
            return null;
        }

        String[] excelSheetNames = new String[dt.Rows.Count];
        int i = 0;

        foreach (DataRow row in dt.Rows)
        {
            excelSheetNames[i] = row["TABLE_NAME"].ToString();
            i++;
        }

        return excelSheetNames;
}
于 2013-08-01T23:56:07.977 回答
17

因为我很无聊:

 static void Main(string[] args)
 {
            string filename = @"c:\temp\myfile.xlsx";    
            System.Data.OleDb.OleDbConnection myConnection = new System.Data.OleDb.OleDbConnection( 
                        "Provider=Microsoft.ACE.OLEDB.12.0; " +
                         "data source='" + filename + "';" +
                            "Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1\" ");
            myConnection.Open();
            DataTable mySheets = myConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });                
            DataSet ds = new DataSet();
            DataTable dt;

            for (int i = 0; i <= mySheets.Rows.Count; i++)
            {
                   dt =   makeDataTableFromSheetName(filename, mySheets.Rows[i]["TABLE_NAME"].ToString());
                   ds.Tables.Add(dt);
            }
 }

private static DataTable makeDataTableFromSheetName(string filename, string sheetName)
{      
    System.Data.OleDb.OleDbConnection myConnection = new System.Data.OleDb.OleDbConnection(
    "Provider=Microsoft.ACE.OLEDB.12.0; " +
    "data source='" + filename + "';" +
    "Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1\" ");

    DataTable dtImport = new DataTable();
    System.Data.OleDb.OleDbDataAdapter myImportCommand = new System.Data.OleDb.OleDbDataAdapter("select * from [" + sheetName + "$]", myConnection);
    myImportCommand.Fill(dtImport);
    return dtImport;
}
于 2013-08-01T23:47:51.140 回答
4

Avitus 建议的功能是正确的,但它有逻辑错误,您必须重写:

DataTable dtImport = new DataTable();
using ( System.Data.OleDb.OleDbConnection myConnection = new System.Data.OleDb.OleDbConnection(
            "Provider=Microsoft.ACE.OLEDB.12.0; " +
             "data source='" + filename + "';" +
                "Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1\" ")){


using ( System.Data.OleDb.OleDbDataAdapter myImportCommand = new System.Data.OleDb.OleDbDataAdapter("select * from [" + sheetName + "$]", myConnection))
myImportCommand.Fill(dtImport);
} return dtImport;

这是正确的,否则您必须手动处理连接和数据适配器。

于 2014-02-20T16:16:03.797 回答
0

这可能不是最好和最快的,但它是另一种方式(编辑-添加消除空白单元格):

    public static DataSet ReadWorkbook(string excelFileName, bool useFirstRowAsColumnName = false)
    {
        var excel = new Microsoft.Office.Interop.Excel.Application();
        var workBook = excel.Workbooks.Open(excelFileName, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);//MLHIDE
        try
        {
            System.Data.DataSet ds = new DataSet(excelFileName);
            foreach (var sheet0 in workBook.Worksheets)
            {
                var sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheet0;
                try
                {
                    var dt = readSheet(sheet, useFirstRowAsColumnName);
                    if (dt != null)
                        ds.Tables.Add(dt);
                }
                finally
                {
                    releaseObject(sheet);
                }
            }
            return ds;
        }
        finally
        {
            workBook.Close(true, null, null);
            excel.Quit();

            releaseObject(workBook);
            releaseObject(excel);
        }
    }

    /// <summary>
    /// Returns null for empty sheets or if sheet is not found.
    /// </summary>
    public static DataTable ReadSheet(string excelFileName, string sheetName, bool useFirstRowAsColumnName = false)
    {
        var excel = new Microsoft.Office.Interop.Excel.Application();
        var workBook = excel.Workbooks.Open(excelFileName, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);//MLHIDE
        try
        {
            foreach (var sheet0 in workBook.Worksheets)
            {
                var sheet = (Microsoft.Office.Interop.Excel.Worksheet)sheet0;
                try
                {
                    if (sheet.Name.Equals_Wildcard(sheetName))
                    {
                        var dt = readSheet(sheet, useFirstRowAsColumnName);
                        if (dt != null)
                            return dt;
                    }
                }
                finally
                {
                    releaseObject(sheet);
                }
            }
            return null;
        }
        finally
        {
            workBook.Close(true, null, null);
            excel.Quit();

            releaseObject(workBook);
            releaseObject(excel);
        }
    }

    /// <summary>
    /// Returns null for empty sheets
    /// </summary>
private static DataTable readSheet(Microsoft.Office.Interop.Excel.Worksheet sheet, bool useFirstRowAsColumnName = false)
        {
            using (Dece.Common.BeginChangeCurrentCultureBlock_EN_us())
            {
                var range = sheet.UsedRange;
                try
                {
                    object[,] values = (object[,])range.Value2;
                    int rowCount = values.GetLength(0);
                    int colCount = values.GetLength(1);
                    int rowCount0 = rowCount;
                    int colCount0 = colCount;
                    #region find row-col count
                    {
                        bool ok = false;
                        for (int row = rowCount; row > 0; row--)
                            if (!ok)
                                for (int col = colCount; col > 0; col--)
                                {
                                    var val = values[row, col];
                                    if ((val != null) && (!System.Convert.ToString(val).IsNullOrEmpty()))
                                    {
                                        rowCount = row;
                                        ok = true;
                                        break;
                                    }
                                }
                            else
                                break;
                    }
                    {
                        bool ok = false;
                        for (int col = colCount; col > 0; col--)
                            if (!ok)
                                for (int row = rowCount; row > 0; row--)
                                {
                                    var val = values[row, col];
                                    if ((val != null) && (!System.Convert.ToString(val).IsNullOrEmpty()))
                                    {
                                        colCount = col;
                                        ok = true;
                                        break;
                                    }
                                }
                            else
                                break;
                    }
                    #endregion
                    if ((rowCount > 0) && (colCount > 0))
                    {  
                        var dt = new DataTable(sheet.Name);
                        dt.BeginLoadData();
                        try
                        {
                            for (int col = 1; col <= colCount; col++)
                                dt.Columns.Add_RenameIfRequired(useFirstRowAsColumnName ? values[1, col].ToString_NullProof() : col.ToString());
                            var arr = new object[colCount];
                            for (int row = useFirstRowAsColumnName ? 1 : 0; row < rowCount; row++)
                            {
                                for (int col = 1; col <= colCount; col++)
                                    arr[col - 1] = values[row + 1, col];
                                dt.Rows.Add(arr);
                            }
                        }
                        finally
                        {
                            dt.EndLoadData();
                        }
                        return dt;                        
                    }
                    else
                        return null;
                }
                finally
                {
                    releaseObject(range);
                }
            }
        }

    private static void releaseObject(object obj)
    {
        try
        {
            System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
            obj = null;
        }
        catch (Exception ex)
        {
            obj = null;
            throw new Exception("Unable to release the Object " + ex.ToString(), ex);//MLHIDE
        }
        finally
        {
            GC.Collect();
        }
    }
于 2016-10-01T11:15:17.290 回答
0

C#

一个整洁的最小版本,它提供了一个数据集,其中包含根据工作表命名的表(没有尾随的美元):

    private static OleDbConnection GetConnection(string filename, bool openIt)
    {
        // if your data has no header row, change HDR=NO
        var c = new OleDbConnection($"Provider=Microsoft.ACE.OLEDB.12.0;Data Source='{filename}';Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1\" ");
        if (openIt)
            c.Open();
        return c;
    }

    private static DataSet GetExcelFileAsDataSet(OleDbConnection conn)
    {
        var sheets = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new[] { default, default, default, "TABLE" });
        var ds = new DataSet();
        foreach (DataRow r in sheets.Rows)
            ds.Tables.Add(GetExcelSheetAsDataTable(conn, r["TABLE_NAME"].ToString()));
        return ds;
    }

    private static DataTable GetExcelSheetAsDataTable(OleDbConnection conn, string sheetName)
    {
        using (var da = new OleDbDataAdapter($"select * from [{sheetName}]", conn))
        {
            var dt = new DataTable() { TableName = sheetName.TrimEnd('$') };
            da.Fill(dt);
            return dt;
        }
    }

像这样使用它:

DataSet ds;

using(c = GetConnection(@"C:\path\to\your\xl.xlsx", true)
    ds = GetExcelFileAsDataSet(c);

或者,如果您只想要一张桌子,并且您知道您想要的所有确切工作表名称(请记住,它们最后有一美元):

DataTable dt;

using(c = GetConnection(@"C:\path\to\your\xl.xlsx", true)
    dt = GetExcelSheetAsDataTable(c, "Sheet1$");

VB.NET

奖金!注意:需要一个现代版本的 VB,它可以理解字符串插值、With 等内容

        Private Shared Function GetConnection(filename As String, openIt As Boolean) As OleDbConnection
        'if your data has no header row, change HDR=NO
        Dim c = New OleDbConnection($"Provider=Microsoft.ACE.OLEDB.12.0;Data Source='{filename}';Extended Properties=""Excel 12.0;HDR=YES;IMEX=1"" ")
        If openIt Then c.Open()

        Return c
    End Function

    Private Shared Function GetExcelFileAsDataSet(conn As OleDbConnection) As DataSet

        Dim sheets = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, {Nothing, Nothing, Nothing, "TABLE"})
        Dim ds = New DataSet()

        For Each r As DataRow In sheets.Rows
            ds.Tables.Add(GetExcelSheetAsDataTable(conn, r("TABLE_NAME").ToString()))
        Next

        Return ds

    End Function

    Private Shared Function GetExcelSheetAsDataTable(conn As OleDbConnection, sheetName As String) As DataTable
        Using da = New OleDbDataAdapter($"select * from [{sheetName}]", conn)
            Dim dt = New DataTable() With {.TableName = sheetName.TrimEnd("$"c)}
            da.Fill(dt)
            Return dt
        End Using
    End Function

像这样使用它:

    Dim ds As DataSet

    Using c = GetConnection("C:\path\to\your\xl.xlsx", True)
        ds = GetExcelFileAsDataSet(c)
    End Using 'closes connection

或者对于您知道其名称的单个工作表(记住工作表名称以美元结尾):

    Dim dt As DataTable

    Using c = GetConnection("C:\path\to\your\xl.xlsx", True)
        dt = GetExcelSheetAsDataTable(c, "Sheet1$")
    End Using 'closes connection
于 2020-09-26T08:16:46.453 回答