如何在 C# 中导入特定列和行的 excel 数据到没有 OLEDB 的 datagridview

How to import specific columns and rows of excel data to datagridview WITHOUT OLEDB in C#

我为自动映射网络驱动器的工作制作了一个简单的独立程序。该程序使用 DataGridView 列出所有驱动器号和路径,我编写的代码读取 DataGridView 中的条目并基于此映射驱动器 - 还从特定的驱动器号和路径excel sheet.

那个特定的 excel 文件使用 VB 代码跟踪用户计算机的某些信息。第三个作品sheet,名称为“Drives”,是网络驱动器所在的地方。盘符和路径在C和D列。除了名称“Network drives”外,没有headers在第 3 行开始之前的第 2 行。 不幸的是,在第 29 行之后,outlook pst 文件的条目开始。

由于我对 C# 的了解有限(我是 C# 的新手),我设法创建了这个:

public void FileSelect()
    {
        string filePath = string.Empty;
        string fileExt = string.Empty;
        OpenFileDialog file = new OpenFileDialog(); //open dialog to choose file
        file.Filter = "Discovery Excel|*.xlsm| CSV (Coming Soon)| *.csv";
        file.Title = "Please select a valid data file";

        if (file.ShowDialog() == System.Windows.Forms.DialogResult.OK) //if there is a file choosen by the user  
        {
            filePath = file.FileName; //get the path of the file  
            fileExt = Path.GetExtension(filePath); //get the file extension 
            if (fileExt.CompareTo(".xls") == 0 || fileExt.CompareTo(".xlsm") == 0)
            {
                try
                {

                    DataTable dtExcel = new DataTable();
                    dtExcel = ReadExcel(filePath, fileExt); //read file  
                    InfoTB.Visible = false;
                    dataGridView1.Visible = true;
                    FileSelectBT.Visible = false;
                    ManualBT.Visible = false;
                    RunBT.Visible = true;
                    ExitBT.Visible = true;
                    RunBT.Location = new System.Drawing.Point(109, 334);
                    ExitBT.Location = new System.Drawing.Point(190, 334);
                    dataGridView1.DataSource = dtExcel;
                    dataGridView1.AutoResizeColumns();
                    dataGridView1.Columns[0].HeaderText = "Drive Letter";
                    dataGridView1.Columns[1].HeaderText = "Drive Path";
                    for (int i = 1; i < dataGridView1.RowCount - 1; i++)
                    {
                        if (dataGridView1.Rows[i].Cells[0].Value.ToString() == "" || dataGridView1.Rows[i].Cells[1].Value.ToString() == "")
                        {
                            dataGridView1.Rows.RemoveAt(i);
                            i--;
                        }
                    }

                }
                catch (Exception ex)
                {
                    MessageBox.Show("Oops! Something went wrong! We'll make a log of that.\nDon't worry, we'll open the Excel File and switch to manuel mode for you!", "FAIL!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    ManualMode();
                    OpenExcel(filePath);
                    TextWriter txt = new StreamWriter(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "NDrive_Error_Log.txt"); //Saving the info from the results textbox to an actual text file
                    txt.Write(ex.ToString());
                    txt.Close();
                }
            }
            else
            {
                MessageBox.Show("Please choose .xlsm or .CSV file only.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Error); //custom messageBox to show error  
            }
        } 
    }


    public DataTable ReadExcel(string fileName, string fileExt)
    {
        string conn = string.Empty;
        DataTable dtexcel = new DataTable();
        conn = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source =" + fileName + ";Extended Properties=\"Excel 12.0 Xml;HDR=YES;IMEX=1\";"; //loading the Access engine to load/read the Excel file  
        using (OleDbConnection con = new OleDbConnection(conn))
        {
            try
            {
                OleDbDataAdapter oleAdpt = new OleDbDataAdapter("Select TOP 24 F3,F4 FROM [Drives$]", conn); //read data from sheet 3 which should be the drives 
                oleAdpt.Fill(1, 24, dtexcel); //fill excel data into dataTable  
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show("Oops! Something went wrong! We'll make a log of that.\nDon't worry, we'll open the Excel File and switch to manuel mode for you!", "FAIL!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                ManualMode();
                OpenExcel(fileName);
                TextWriter txt = new StreamWriter(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)+ "NDrive_Error_Log.txt"); //Saving the info from the results textbox to an actual text file
                txt.Write(ex.ToString());
                txt.Close();
            }
        }
        return dtexcel;
    }

并且此代码有效!

Here's photo of what the program looks like when it has some entries

不幸的是,Microsoft.ACE.OLEDB.12.0 在将程序从一台计算机移动到另一台计算机时并不可靠。我无法在工作的每台计算机上都安装 ACE,因此我必须找到另一种方法来专门读取 Excel 文件,而无需使用 OLEDB。

我确实四处寻找替代解决方案,但我发现的东西似乎专注于特定的起始行而不是结束行。

公平地说,我是 C# 的新手,所以我可能忽略了一些对我的程序有帮助的东西。

也就是说,对于这种情况,是否有替代 OLEDB 的方法?

正如 PaulF 的评论所述,Excel Interop 是一种可能的解决方案,无需使用任何外部库。

以下假设您的数据将始终在 C3:D29 中,并且还假设工作表中的数据有效:

public DataTable ReadExcel(string fileName)
{ 
    var excel = new Excel.Application();
    var wkb = excel.Workbooks.Open(fileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
                                Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);

    var sheet = wkb.Sheets["Drives"] as Excel.Worksheet;

    var range = sheet.Range[sheet.Cells[3, 3], sheet.Cells[29, 4]];
    var data = range.Value2;

    var dt = new DataTable();
    dt.Columns.Add("Drive");
    dt.Columns.Add("Path");

    for (int i = 1; i <= range.Rows.Count; i++)
    {
        dt.Rows.Add(data[i, 1], data[i, 2]);
    }

    return dt;
}