C# xls 和 xlsx 查询从 sheet 中选择而不考虑 sheet 名称
C# xls & xlsx query selecting from a sheet regardless of sheet name
这是我的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
个文件,因为它使用文件名而不是 sheet 名称。
它适用于 .xls
和 .xlsx
文件,这些文件的作品sheet 名为 Sheet1
。
当我尝试使用具有不同 sheet 名称的 .xls/.xlsx
文件时,出现以下错误:
System.Data.OleDb.OleDbException: ''Sheet1$' is not a valid name. Make sure that it does not include invalid characters or punctuation and that it is not too long.'
另一个问题的答案:
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");
}
没有帮助,因为我不知道它应该放在我的代码中的什么位置,答案中也没有任何关于它应该放在什么位置的指示。
我这样加吗?
string Sheet1 = dataGridView1.Rows[0].Field<string>("TABLE_NAME");
这给了我一个错误:
Error CS1929 'DataGridViewRow' does not contain a definition for 'Field' and the best extension method overload 'DataRowExtensions.Field(DataRow, string)' requires a receiver of type 'DataRow'
尝试在 GetData
方法的末尾调用此方法而不是 FillData
方法,如您所见,不需要传递 query
,因为此方法获取 sheetname self来自文档架构。
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;
}
}
}
}
}
我很快为您的代码添加了一些修复程序,但这个解决方案远非干净。
您应该考虑@woldemar 的解决方案,并更深入地了解代码。一些优秀的资源可以在这里找到:https://github.com/EbookFoundation/free-programming-books
回到你的代码。要找出第一个 sheet 的名称,您必须首先打开到 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");
}
之后,您可以将收到的 sheet 名称插入到您的查询中。
快速而肮脏,你的代码应该看起来像这样才能让它与 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);
}
这是我的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
个文件,因为它使用文件名而不是 sheet 名称。
它适用于 .xls
和 .xlsx
文件,这些文件的作品sheet 名为 Sheet1
。
当我尝试使用具有不同 sheet 名称的 .xls/.xlsx
文件时,出现以下错误:
System.Data.OleDb.OleDbException: ''Sheet1$' is not a valid name. Make sure that it does not include invalid characters or punctuation and that it is not too long.'
另一个问题的答案:
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");
}
没有帮助,因为我不知道它应该放在我的代码中的什么位置,答案中也没有任何关于它应该放在什么位置的指示。
我这样加吗?
string Sheet1 = dataGridView1.Rows[0].Field<string>("TABLE_NAME");
这给了我一个错误:
Error CS1929 'DataGridViewRow' does not contain a definition for 'Field' and the best extension method overload 'DataRowExtensions.Field(DataRow, string)' requires a receiver of type 'DataRow'
尝试在 GetData
方法的末尾调用此方法而不是 FillData
方法,如您所见,不需要传递 query
,因为此方法获取 sheetname self来自文档架构。
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;
}
}
}
}
}
我很快为您的代码添加了一些修复程序,但这个解决方案远非干净。 您应该考虑@woldemar 的解决方案,并更深入地了解代码。一些优秀的资源可以在这里找到:https://github.com/EbookFoundation/free-programming-books
回到你的代码。要找出第一个 sheet 的名称,您必须首先打开到 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");
}
之后,您可以将收到的 sheet 名称插入到您的查询中。
快速而肮脏,你的代码应该看起来像这样才能让它与 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);
}