【发布时间】:2020-07-10 00:19:48
【问题描述】:
我正在使用下面的代码来修剪我的 DataTable 中的所有单元格。
问题是,我是通过一个循环来完成的,并且根据我填充 DataTable 的内容,如果它有 1500 行和 20 列,那么循环需要非常非常长的时间。
DataColumn[] stringColumns = dtDataTable.Columns.Cast<DataColumn>().Where(c => c.DataType == typeof(string)).ToArray();
foreach (DataRow row in dtDataTable.Rows)
{
foreach (DataColumn col in stringColumns)
{
if (row[col] != DBNull.Value)
{
row.SetField<string>(col, row.Field<string>(col).Trim());
}
}
}
下面是我将 Excel 工作表导入 DataTable 的方式:
using (OpenFileDialog ofd = new OpenFileDialog() { Title = "Select File", Filter = "Excel WorkBook|*.xlsx|Excel WorkBook 97-2003|*.xls|All Files(*.*)|*.*", Multiselect = false, ValidateNames = true })
{
if (ofd.ShowDialog() == DialogResult.OK)
{
String PathName = ofd.FileName;
FileName = System.IO.Path.GetFileNameWithoutExtension(ofd.FileName);
strConn = string.Empty;
FileInfo file = new FileInfo(PathName);
if (!file.Exists) { throw new Exception("Error, file doesn't exists!"); }
string extension = file.Extension;
switch (extension)
{
case ".xls":
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + PathName + ";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1;'";
case ".xlsx":
strConn = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + PathName + ";Extended Properties='Excel 12.0;HDR=Yes;IMEX=1;'";
default:
strConn = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + PathName + ";Extended Properties='Excel 8.0;HDR=Yes;IMEX=1;'";
}
}
else
{
return;
}
}
using (OleDbConnection cnnxls = new OleDbConnection(strConn))
{
using (OleDbDataAdapter oda = new OleDbDataAdapter(string.Format("select * from [{0}$]", "Sheet1"), cnnxls))
{
oda.Fill(dtDataTableInitial);
}
}
//Clone dtDataTableInitial so that I can have the new DataTable in String Type
dtDataTable = dtDataImportInitial.Clone();
foreach (DataColumn col in dtDataTable.Columns)
{
col.DataType = typeof(string);
}
foreach (DataRow row in dtDataImportInitial.Rows)
{
dtDataTable.ImportRow(row);
}
有没有更有效的方法来实现这一点?
编辑: 根据 JQSOFT 的建议,我现在正在使用 OleDbDataReader,但仍在运行两个问题:
一个: SELECT RTRIM(LTRIM(*)) FROM [Sheet1$] 似乎不起作用。
我知道可以一一选择每一列,但是 excel 表中列的数量和标题是随机的,我不知道如何调整我的 SELECT 字符串来解决这个问题。
二:一列的行主要是数字,但有几行字母似乎省略了那些字母的行。例如:
Col1
1
2
3
4
5
6
一个
b
变成:
Col1
1
2
3
4
5
6
但是,我发现如果我手动进入 excel 表并将整个表格单元格格式转换为“文本”,这个问题就解决了。 但是,这样做会将 Excel 工作表中的任何日期转换为无法识别的数字字符串,因此我希望尽可能避免这样做。
例如:7/2/2020 如果转换为“文本”,则变为 44014。
这是我的新代码:
private void Something()
{
if (ofd.ShowDialog() == DialogResult.OK)
{
PathName = ofd.FileName;
FileName = System.IO.Path.GetFileNameWithoutExtension(ofd.FileName);
strConn = string.Empty;
FileInfo file = new FileInfo(PathName);
if (!file.Exists) { throw new Exception("Error, file doesn't exists!"); }
}
using (OleDbConnection cn = new OleDbConnection { ConnectionString = ConnectionString(PathName, "No") })
{
using (OleDbCommand cmd = new OleDbCommand { CommandText = query, Connection = cn })
{
cn.Open();
OleDbDataReader dr = cmd.ExecuteReader();
dtDataTable.Load(dr);
}
}
dataGridView1.DataSource = dtDataTable;
}
public string ConnectionString(string FileName, string Header)
{
OleDbConnectionStringBuilder Builder = new OleDbConnectionStringBuilder();
if (Path.GetExtension(FileName).ToUpper() == ".XLS")
{
Builder.Provider = "Microsoft.Jet.OLEDB.4.0";
Builder.Add("Extended Properties", string.Format("Excel 8.0;IMEX=1;HDR=Yes;", Header));
}
else
{
Builder.Provider = "Microsoft.ACE.OLEDB.12.0";
Builder.Add("Extended Properties", string.Format("Excel 12.0;IMEX=1;HDR=Yes;", Header));
}
Builder.DataSource = FileName;
return Builder.ConnectionString;
}
【问题讨论】:
-
你为什么要修剪它们
-
我会在 SQL 中实现修剪。基于集合的操作总是比循环快。您正在循环中进行循环,因此性能会随着行数/列数而几何下降。
-
@LegacyCode 好吧,我正在将一个 Excel 工作表导入我的应用程序,有时会有不应该存在的前导和尾随空格。
-
@JQSOFT 谢谢!我会读一读:)。非常感谢!
-
更新了原帖。