【问题标题】:OpenFileDialog can't load CSV files but can load xls/xlsx Excel files [duplicate]OpenFileDialog 无法加载 CSV 文件,但可以加载 xls/xlsx Excel 文件 [重复]
【发布时间】:2019-06-18 08:38:43
【问题描述】:

在我的 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'";
    }

还是同样的错误。

【问题讨论】:

  • 在您的点击处理程序中,您在两个位置设置sConnectionString,一个是您的分割片段是“xls”,另一个是“xlsx”。你不要设置它,否则。但是在您的 FillData 方法中,您检查它的长度(它会触发 NRE)。考虑使用System.IO.Path 类中的方法而不是string.Split 来挑选路径
  • 你安装了微软office吗? ACE 驱动程序附带办公室。如果您没有 Office,则必须从 msdn 安装 ACE。我从来没有成功安装过 ACE,但其他人声称它可以工作。
  • 我有点惊讶“xlsx”的工作原理。你的 if/then/else 逻辑搞砸了。进行“xlsx”检查的唯一方法是 Arr.Length 是否 else if 应该抛出。你有没有用调试器一步步完成这个?
  • @Jimi 我会用 csv 做什么?我已经尝试过 ACE 和 JET 提供程序
  • @jdweng 是的,我已经安装了。

标签: c# excel winforms csv openfiledialog


【解决方案1】:

关于报错

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

产生异常是因为Connection字符串声明为:

public string sConnectionString;

由于它从未被初始化,因为连接字符串的初始化仅对某些文件类型执行,而不是对包含在OpenFileDialog.Filter 中的所有文件类型执行。当代码测试字符串的长度时,字符串仍然是null。这可以避免设置一个初始值:

public string sConnectionString = string.Empty;

关于使用OleDbConnection 操作.CSV 文件所需的连接字符串

  • 所有 OleDb 提供者都会:
    • Microsoft.Jet.OLEDB.4.0
    • Microsoft.ACE.OLEDB.12.0
    • Microsoft.ACE.OLEDB.16.0
  • 如果某些旧格式(旧的 Access .mdb 文件)需要 Microsoft.Jet.OLEDB.4.0,则应用程序必须编译为 32 位,因此请安装其他提供程序的相应 32 位版本:

Microsoft Database Engine 2010 Redistributable
Microsoft Database Engine 2016 Redistributable

要读取 CSV 文件,连接字符串 - 对于所有提供者 - 组成如下:

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

地点:

  • {Provider} => OleDb 提供者之一。他们中的任何一个都可以。

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

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

  • IMEX=1 => 导入/导出模式设置为 1(导出模式 = 0;导入模式 = 1,链接模式 = 2),以忽略数值并仅使用字符串。这里实际上并不相关。最好保留它,作为一般帮助(以防文件中没有 Header 和 HDR=Yes)。

  • FMT=Delimited => 文件格式:分隔。标题/字段由分隔符分隔。识别的分隔符是逗号 (,)。此设置可能与系统相关(第 3 部分应用程序可能出于自身原因修改了注册表)。要指定不同于默认的分隔符(CSV 中的C 表示逗号),Catalog 文件夹中必须有一个 Schema.ini 文件,该文件为特定文件:

      [MyFile.csv]
      Format=Delimited(;)
    
  • 由于 Data Source 是目录名(将其视为数据库),因此要在查询中指定要打开的文件的文件名:

      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\";";

请参阅The Connection Strings Reference 网站了解其他可用的连接字符串格式。

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

private void Browse_Click(object sender, EventArgs e)
{
    string userFileName = string.Empty;
    using (var ofd = new OpenFileDialog()) {
        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;
    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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-20
    • 2014-11-15
    • 2020-01-24
    • 2016-04-14
    相关资源
    最近更新 更多