C# OpenFileDialog无法加载CSV文件,但可以加载xls/xlsx Excel文件

C# OpenFileDialog无法加载CSV文件,但可以加载xls/xlsx Excel文件,c#,excel,winforms,csv,openfiledialog,C#,Excel,Winforms,Csv,Openfiledialog,在我的Windows窗体应用程序中加载Excel文件时,我可以很好地加载.xls和.xlsx格式,但当我选择.CSV时,会出现以下错误: System.NullReferenceException:“对象引用未设置为对象的实例。” sConnectionString为空 错误发生在以下行: if (sConnectionString.Length > 0) 从代码的完整部分: public string sConnectionString; public void FillData()

在我的Windows窗体应用程序中加载Excel文件时,我可以很好地加载.xls和.xlsx格式,但当我选择.CSV时,会出现以下错误:

System.NullReferenceException:“对象引用未设置为对象的实例。” sConnectionString为空

错误发生在以下行:

if (sConnectionString.Length > 0)
从代码的完整部分:

public string sConnectionString;
public void FillData()
{
    if (sConnectionString.Length > 0)
    {
        OleDbConnection cn = new OleDbConnection(sConnectionString);
        {
            cn.Open();
            DataTable dt = new DataTable();
            OleDbDataAdapter Adpt = new OleDbDataAdapter("select * from [sheet1$]", cn);
            Adpt.Fill(dt);
            dataGridView1.DataSource = dt;
        }
    }
}
在按钮代码之前:

private void Browse_Click(object sender, EventArgs e)
{
    OpenFileDialog op = new OpenFileDialog();
    op.InitialDirectory = @"C:\";
    op.Title = "Browse Excel Files";
    op.CheckFileExists = true;
    op.CheckPathExists = true;
    op.DefaultExt = "csv";
    op.Filter = "CSV Files (*.csv)|*.csv";
    op.FilterIndex = 2;
    op.RestoreDirectory = true;
    op.ReadOnlyChecked = true;
    op.ShowReadOnly = true;

    if (op.ShowDialog() == System.Windows.Forms.DialogResult.OK)
    {
        if (File.Exists(op.FileName))
        {
            string[] Arr = null;
            Arr = op.FileName.Split('.');
            if (Arr.Length > 0)
            {
                if (Arr[Arr.Length - 1] == "xls")
                    sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" +
                    op.FileName + ";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'";
            }
            else if (Arr[Arr.Length - 1] == "xlsx")
            {
                sConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + op.FileName + ";Extended Properties='Excel 12.0 Xml;HDR=YES';";
            }
        }
        FillData();
        fileTextBox.Text = op.FileName;
    }
}
编辑

增加:

else if (Arr[Arr.Length - 1] == "csv")
    {
    sConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + op.FileName + 
                        ";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'";
    }
仍然会收到相同的错误。

关于报告的错误:

System.NullReferenceException:对象引用未设置为 对象的实例。sConnectionString为空

由于连接字符串声明为:

public string sConnectionString;
因为它从未初始化,因为连接字符串的初始化只针对某些文件类型执行,而不是OpenFileDialog.Filter中包含的所有文件类型。当代码测试字符串的长度时,字符串仍然为null。可以避免设置初始值:

public string sConnectionString = string.Empty;
关于使用OLEDB连接操作.CSV文件所需的连接字符串:

所有OleDb提供商将执行以下操作: 微软.Jet.OLEDB.4.0 Microsoft.ACE.OLEDB.12.0 Microsoft.ACE.OLEDB.16.0 如果某些旧格式的旧Access.mdb文件需要Microsoft.Jet.OLEDB.4.0,则应用程序必须编译为32位,因此请安装其他提供程序的相应32位版本:

要读取CSV文件,连接字符串(适用于所有提供程序)的组成如下:

{Provider};Data Source={Catalog}; Extended Properties="text; HDR=Yes; IMEX=1; FMT=Delimited;
其中:

{Provider}=>OleDb提供程序之一。任何一个都可以

{Catalog}=>包含要打开的文件的目录

HDR=Yes/No=>CSV文件包含一个头:如果是,头是文件的第一行

IMEX=1=>导入/导出模式设置为1导出模式=0;导入模式=1,链接模式=2,忽略数值,仅使用字符串。实际上与此无关。最好保留它,作为一般的帮助,以防文件中没有头并且HDR=Yes

FMT=Delimited=>文件格式:Delimited。标题/字段由分隔符分隔。识别的分隔符是逗号,。此设置可能取决于系统。第三方应用程序可能出于自身原因修改了注册表。要指定不同于默认值的分隔符,CSV中的C表示逗号,目录文件夹中必须有一个文件为特定文件定义特定分隔符:

  [MyFile.csv]
  Format=Delimited(;)

由于数据源是一个目录名,将其视为数据库,要打开的文件的文件名在查询中指定:

  SELECT * FROM MyFile.csv
使用Microsoft.ACE.OLEDB.12.0作为提供程序的连接字符串示例:

string connectionString = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dirName};" +
                            "Extended Properties=\"text; HDR=Yes; IMEX=1; FMT=Delimited\";";
有关其他可用的连接字符串格式,请参见网站

在本例中,使用Microsoft.Jet.OLEDB.4.0测试结果的示例代码:


在click处理程序中,您在两个位置设置了sConnectionString,一个是分割片段为xls,另一个是xlsx。你不能把它设成别的。但是在FillData方法中,您检查其触发NRE的长度。考虑使用Stry.iO.PATH类中的方法,而不是String?S拆除法来选择安装微软Office的路径吗?王牌车手随办公室而来。如果您没有Office,则必须从msdn安装ACE。我从未成功安装过ACE,但其他人声称它能工作。我有点惊讶xlsx能工作。你的if/then/else逻辑混乱了。获取xlsx检查的唯一方法是,如果Arr.Length为@Jimi,csv将使用什么?我试过王牌和喷气式飞机providers@jdweng是的,我已经安装好了。
private void Browse_Click(object sender, EventArgs e)
{
    string userFileName = string.Empty;
    using (OpenFileDialog ofd = new OpenFileDialog())
    {
        ofd.RestoreDirectory = true;
        ofd.Filter = "CSV Files|*.csv|Excel '97-2003|*.xls|Excel 2007-2019|*.xlsx";
        if (ofd.ShowDialog(this) == DialogResult.OK)
            userFileName = ofd.FileName;
    }
    
    if (userFileName.Length == 0) return;
    this.dataGridView1.DataSource = GetData(userFileName);
}

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

    switch (fileExtension)
    {
        // Can also use Microsoft.ACE.OLEDB.12 or Microsoft.ACE.OLEDB.16
        case ".xls":
            conString = $@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={userFileName};" +
                           "Extended Properties=\"Excel 8.0; HDR=Yes; IMEX=1\"";
            query = "SELECT * FROM [Sheet1$]";
            break;
        // Can also use Microsoft.ACE.OLEDB.16
        case ".xlsx":
            conString = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={userFileName};" +
                           "Extended Properties=\"Excel 12.0; HDR=Yes; IMEX=1\"";
            query = "SELECT * FROM [Sheet1$]";
            break;
        // Can also use Microsoft.ACE.OLEDB.16
        case ".csv":
            conString = $@"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(conString, query);
}

private DataTable FillData(string conString, string query)
{
    var dt = new DataTable();
    using (var con = new OleDbConnection(conString)) { 
        con.Open();
        using (var cmd = new OleDbCommand(query, con))
        using (var reader = cmd.ExecuteReader()) {
            dt.Load(reader);
        };
    }
    return dt;
}