【问题标题】:How to import all the Excel sheets to DataSet in C#如何在 C# 中将所有 Excel 工作表导入 DataSet
【发布时间】:2013-08-01 23:26:51
【问题描述】:

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

我以前没有用 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,以便查询知道在哪里查看要导入的内容。就我而言,我希望它遍历所有工作表,无论它们的名称如何,并将它们导入到 DataSet 的单个 DataTable 中。

所以本质上,最后的结果将是一个DataSet,其中每个DataTable 保存导入文件中每个工作表的行。

【问题讨论】:

  • 您确实想使用csv 文件而不是xls。你能把它保存为csv吗?

标签: c# .net excel


【解决方案1】:

这是我想出的代码,效果很好,但我看到其他人已经添加了答案:

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

【讨论】:

  • 我可以使用 sqlconnection 获得它吗?
【解决方案2】:

因为我很无聊:

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

【讨论】:

  • 对我真的很有帮助:)
【解决方案3】:

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;

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-08
        • 1970-01-01
        • 2014-12-02
        • 2019-11-02
        • 2012-12-25
        相关资源
        最近更新 更多