OpenFileDialog can't load CSV files but can load xls/xlsx Excel files
About the reported error:
System.NullReferenceException: Object reference not set to an
instance of an object.sConnectionString
was null.
The exception is generated because the Connection string is declared as:
public string sConnectionString;
Since it's never initialized, because the initialization of the Connection string is performed only for some file types but not all those included in the OpenFileDialog.Filter
. When the code tests the length of the string, the string is still null
. This can be avoided setting an initial value:
public string sConnectionString = string.Empty;
About the Connection string required to oped a .CSV
file with an OleDbConnection
:
- All OleDb providers will do:
Microsoft.Jet.OLEDB.4.0
Microsoft.ACE.OLEDB.12.0
Microsoft.ACE.OLEDB.16.0
- if
Microsoft.Jet.OLEDB.4.0
is required for some legacy formats (old Access.mdb
files), the application must be compiled as 32Bit, so install the corresponding 32Bit version of the other providers:
Microsoft Database Engine 2010 Redistributable
Microsoft Database Engine 2016 Redistributable
To read a CSV file, the connection string - for all providers - is composed as:
{Provider};Data Source={Catalog}; Extended Properties="text; HDR=Yes; IMEX=1; FMT=Delimited;
Where:
{Provider} =>
One of the OleDb providers. Any of them will do.{Catalog} =>
The Directory that contains the file to open.HDR=Yes/No =>
TheCSV
file contains a Header: ifYes
, the Header is the first line of the fileIMEX=1 =>
Import/Export Mode set to 1 (Export Mode = 0; Import Mode = 1, Linked Mode = 2), to ignore numeric values and use strings only. Not actually relevant here. Better keep it, as a general aid (in case there's no Header in the file andHDR=Yes
).FMT=Delimited =>
File format: Delimited. The Header/Fields are separated by a delimiter. The recognized delimiter is a Comma (,
). This setting may be System-dependant (a 3rd part app may have modified the Registry for it's own sake). To specify a delimiter different from the default (theC
inCSV
means comma), there must be a Schema.ini file in theCatalog
folder that defines a specific delimiter for a specific file:[MyFile.csv]
Format=Delimited(;)Since the
Data Source
is a directory name (consider it the Database), the file name of the file to open is specified in the query:SELECT * FROM MyFile.csv
Sample Connection string using Microsoft.ACE.OLEDB.12.0
as provider:
string connectionString = $@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={dirName};" +
"Extended Properties=\"text; HDR=Yes; IMEX=1; FMT=Delimited\";";
See The Connection Strings Reference web site for other available Connection string formats.
Sample code to test the results (using Microsoft.Jet.OLEDB.4.0
in this case):
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;
}
Open File Dialog, One Filter for Multiple Excel Extensions?
Use a semicolon
OpenFileDialog of = new OpenFileDialog();
of.Filter = "Excel Files|*.xls;*.xlsx;*.xlsm";
Import Data from a xls file to datagridview?
You have to work with office interop libaries.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/interop/how-to-access-office-onterop-objects
Why can't I load an Excel file automatically?
All of your code seems to be running in the constructor for the form. The form fields have not been created yet.
Move your code into the form_load
event and your code will work better.
Explanation: You will often get strange behavior with this programming approach. The threading model for winforms is hard to explain sometimes. Which is why it may work with your "manual" approach because of the delays, which allow the background thread to catch-up.
Loading CSV file in C# Winform get's older version
i Found the issue, it was different then i thought.
Seeing older versions of the file were also in the folder i didn't notice that it wasn't taking an older version of itself but it was simply merging all CSV files in to the output.
I searched for this instead and found the following post:
c# reading csv file gives not a valid path
i added an if clause to see if the file is a csv file and then use the following:
Because the difference between opening an Excel or a CSV file is is that the Excel file asked for path and file name while CSV only wants the path and later on a query to select the file...a bit odd but ok.
MyCommand = new OleDbDataAdapter("SELECT * FROM [" + Path.GetFileName(openFileDialog1.FileName) + "]", MyConnection);
How can I add 2 cells in a CSV file in WPF?
There you go:
....
while ((line = file.ReadLine()) != null)
{
if (counter == 0)
{
line += ",column1,column2";
}
else
{
line += $",{value1},{value2}";
}
counter++;
}
...
Related Topics
Read Big Txt File, Out of Memory Exception
Process.Close() Is Not Terminating Created Process,C#
How to Create a File and Any Folders, If the Folders Don't Exist
Removing the Delay After Keydown Event
How to Define Properties in Partial Classes, Then Mark Them with Attributes in Another Partial Class
Conversion of a Decimal to Double Number in C# Results in a Difference
Difference Between Select and Convertall in C#
Read a Xml (From a String) and Get Some Fields - Problems Reading Xml
Button in a Column, Getting the Row from Which It Came on the Click Event Handler
Identifying Active Network Interface
What Is the Use of 'Default' Keyword in C#
Case-Insensitive Dictionary with String Key-Type in C#
Calculating Hmacsha256 Using C# to Match Payment Provider Example
Xaml Gridview Itemtemplate Not Binding to Control
Log4Net Logging of Two Different Levels to Two Different Appenders for the Same Logger
Proper Datagrid Search from Textbox in Wpf Using Mvvm
Getting Content/Message from Httpresponsemessage
What's the Best Way to Test SQL Server Connection Programmatically