不论工作表名称如何,从工作表中进行选择的C#xls和xlsx查询

时间:2019-02-04 14:03:58

标签: c# excel winforms datatable openfiledialog

这是我的GetData方法:

    private DataTable GetData(string userFileName)
    {
        string dirName = Path.GetDirectoryName(userFileName);
        string fileName = Path.GetFileName(userFileName);
        string fileExtension = Path.GetExtension(userFileName);
        string connection = string.Empty;
        string query = string.Empty;

        switch (fileExtension)
        {
            case ".xls":
                connection = $@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={userFileName};" +
                               "Extended Properties=\"Excel 8.0; HDR=Yes; IMEX=1\"";
                query = "SELECT * FROM [Sheet1$]";
                break;

            case ".xlsx":
                connection = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={userFileName};" +
                               "Extended Properties=\"Excel 12.0; HDR=Yes; IMEX=1\"";
                query = "SELECT * FROM [Sheet1$]";
                break;

            case ".csv":
                connection = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dirName};" +
                               "Extended Properties=\"text; HDR=Yes; IMEX=1; FMT=Delimited\"";
                query = $"SELECT * FROM [{fileName}]";
                break;
        }

        return FillData(connection, query);
    }

它适用于.csv个文件,因为它使用文件名而不是工作表名。

它适用于具有工作表.xls的{​​{1}}和.xlsx文件。

当我尝试使用具有不同工作表名称的Sheet1文件时,出现以下错误:

  

System.Data.OleDb.OleDbException:“ Sheet1 $”不是有效名称。确保它不包含无效字符或标点符号,并且时间不要太长。'

另一个问题的答案:

.xls/.xlsx

没有帮助,因为我不知道代码应该放在哪里,答案中也没有任何指示。

我可以这样添加吗?

using (OleDbConnection conn = new OleDbConnection(connString))
{
    conn.Open();
    dtSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
    Sheet1= dtSchema.Rows[0].Field<string>("TABLE_NAME");
}

这给了我一个错误:

  

错误CS1929'DataGridViewRow'不包含'Field'的定义,最佳扩展方法重载'DataRowExtensions.Field(DataRow,string)'需要类型为'DataRow'的接收器

2 个答案:

答案 0 :(得分:3)

尝试在FillData方法的末尾调用此方法,而不是调用GetData方法,如您所见,不需要传递query,因为此方法从文档获取工作表名称自身模式。

    private DataTable GetDataFromFirstSheet(string connection)
    {
        using (OleDbConnection conn = new OleDbConnection(connection))
        {
            using (DataTable dtSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" }))
            {
                string firstSheet = dtSchema.Rows[0].Field<string>("TABLE_NAME");

                //try to remove $ from sheetname if it will be not working
                using (OleDbCommand cmd = new OleDbCommand($"SELECT * FROM [{firstSheet}$]", conn))
                {
                    using (OleDbDataAdapter adp = new OleDbDataAdapter(cmd))
                    {
                        conn.Open();

                        DataTable dt = new DataTable();
                        adp.Fill(dt);

                        return dt;
                    }                            
                }
            }
        }
    }

答案 1 :(得分:2)

我迅速为您的代码添加了一些修复程序,但是这种解决方案离完美无余。 您应该考虑@woldemar的解决方案,并进一步理解代码。一些出色的资源可以在这里找到:https://github.com/EbookFoundation/free-programming-books

返回您的代码。要找出第一张纸的名称,您必须首先打开与xlsx文件的连接。然后使用示例中的某些代码查询元数据:

using (OleDbConnection conn = new OleDbConnection(connString))
{
    conn.Open();
    dtSchema = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
    Sheet1= dtSchema.Rows[0].Field<string>("TABLE_NAME");
}

之后,您可以将接收到的工作表名称插入查询中。

快速又肮脏,您的代码应该看起来像这样才能使其与xlsx文件一起使用:

private static DataTable GetData(string userFileName)
    {
        string dirName = Path.GetDirectoryName(userFileName);
        string fileName = Path.GetFileName(userFileName);
        string fileExtension = Path.GetExtension(userFileName);
        string connection = string.Empty;
        string query = string.Empty;

        switch (fileExtension)
        {
            case ".xls":
                connection = $@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={userFileName};" +
                             "Extended Properties=\"Excel 8.0; HDR=Yes; IMEX=1\"";
                query = "SELECT * FROM [Sheet1$]";
                break;

            case ".xlsx":
                connection = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={userFileName};" +
                             "Extended Properties=\"Excel 12.0; HDR=Yes; IMEX=1\"";
                string sheetName;
                using (OleDbConnection con = new OleDbConnection(connection))
                {
                    con.Open();
                    var dtSchema = con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" });
                    sheetName = dtSchema.Rows[0].Field<string>("TABLE_NAME");
                }

                if (sheetName.Length <= 0) throw new InvalidDataException("No sheet found."); // abort if no sheet name was returned

                query = $"SELECT * FROM [{sheetName}]";
                break;

            case ".csv":
                connection = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dirName};" +
                             "Extended Properties=\"text; HDR=Yes; IMEX=1; FMT=Delimited\"";
                query = $"SELECT * FROM [{fileName}]";
                break;
        }

        return FillData(connection, query);
    }