遍历 DataTable 非常慢
Iterating through DataTable very slow
我对 webforms / windowsforms 的经验很少。去年,我作为一名开发人员开始了第一份工作,从事 MVC 网络开发,这就是我从那以后所做的一切。
我父亲最近让我创建一个简单的应用程序,为此我决定尝试 Windows 表单。该应用程序所做的是使用 OLEDB 将 excel sheet 文件读入 DataTable
并将其显示在 DataGridView
:
上
完成后,每一列都与一组预定义的标签匹配,然后按以下格式写入 txt 文件:
@tag (column value)
我作为示例使用的 excel 文件有大约 18k 行。使用 OLEDB 读取文件并将其绑定到 DataGridView
几乎是即时的(1/2 到 2 秒)。但是,当我将列与适当的标签匹配并生成所需的输出时,它会花费很长时间(5 分钟)。考虑到 DataTable
在这个阶段在内存中,这感觉是错误的。我不确定我是否会以极其低效的方式遍历 DataTable
。
下面是遍历 DataTable
以创建输出的代码:
private void GenerateOutputButton_Click(object sender, EventArgs e)
{
OutputDisplayRichText.Clear();
output = string.Empty;
string selectedT = TComboBox.SelectedItem.ToString(),
selectCDocdate = CDocdateComboBox.SelectedItem.ToString(),
selectedCSubject = CSubjectCombobox.SelectedItem.ToString(),
selectedTiff = TiffComboBox.SelectedItem.ToString();
foreach (DataRow row in excelSheet.Rows)
{
if (TToken.Checked)
{
/*..removed code..*/
output += "@T\t\t" + tempOutput + Environment.NewLine;
}
if (CDocdateToken.Checked)
{
string rowValue = row[selectCDocdate].ToString();
string tempOutput = "@C Docdate\t\t" + rowValue + Environment.NewLine;
output += tempOutput;
}
if (CSubjectToken.Checked)
{
string rowValue = row[selectedCSubject].ToString();
string tempOutput = "@C Subject\t\t" + rowValue + Environment.NewLine;
output += tempOutput;
}
if (DToken.Checked)
{
string rowValue = DTextBox.Text;
string tempOutput = "@D \t\t" + rowValue + Environment.NewLine;
output += tempOutput;
}
if (TiffFiles.Checked)
{
/*..removed code..*/
output = TTextBox.Text + "{" + pageFromStr2 + "-" + pageToStr2 + "}.tif";
}
output += Environment.NewLine;
}
OutputDisplayTextBox.Text = output;
}
.net 中的 string
是不可变的,因此,每次使用 +
运算符连接两个 strings/values 时,都会创建一个新字符串并保留其他的 .net 将其从中删除记忆。为避免此问题,您可以使用 StringBuilder
实例,例如:
StringBuilder b = new StringBuilder();
foreach (DataRow row in excelSheet.Rows)
{
if (TToken.Checked)
b.AppendLine(string.Format("@T\t\t{0}", tempOutput));
if (CDocdateToken.Checked)
b.AppendLine(string.Format("@C Docdate\t\t{0}", row[selectCDocdate].ToString()));
if (CSubjectToken.Checked)
b.AppendLine(string.Format("@C Subject\t\t{0}", row[selectedCSubject].ToString()));
if (DToken.Checked)
b.AppendLine(string.Format("@D \t\t{0}", DTextBox.Text));
if (TiffFiles.Checked)
b.Append(TTextBox.Text + "{" + pageFromStr2 + "-" + pageToStr2 + "}.tif");
b.AppendLine();
}
// generate everything in a single string.
output = b.ToString();
根据您的代码进行调整,因为我们没有它的详细信息。
字符串是不可变的,这意味着它们在内存中无法更改。您将看似大量的信息附加到字符串变量中 - 这会在内存中创建许多重复的字符串,占用越来越多的内存并降低应用程序的速度。
改用 StringBuilder
class - 这是可变的。示例:
Stringbuilder builder = new StringBuilder();
builder.AppendLine("text"); // adds a new line to the StringBuilder
当需要输出文本时,在StringBuilder实例上调用.ToString()
。
我对 webforms / windowsforms 的经验很少。去年,我作为一名开发人员开始了第一份工作,从事 MVC 网络开发,这就是我从那以后所做的一切。
我父亲最近让我创建一个简单的应用程序,为此我决定尝试 Windows 表单。该应用程序所做的是使用 OLEDB 将 excel sheet 文件读入 DataTable
并将其显示在 DataGridView
:
完成后,每一列都与一组预定义的标签匹配,然后按以下格式写入 txt 文件:
@tag (column value)
我作为示例使用的 excel 文件有大约 18k 行。使用 OLEDB 读取文件并将其绑定到 DataGridView
几乎是即时的(1/2 到 2 秒)。但是,当我将列与适当的标签匹配并生成所需的输出时,它会花费很长时间(5 分钟)。考虑到 DataTable
在这个阶段在内存中,这感觉是错误的。我不确定我是否会以极其低效的方式遍历 DataTable
。
下面是遍历 DataTable
以创建输出的代码:
private void GenerateOutputButton_Click(object sender, EventArgs e)
{
OutputDisplayRichText.Clear();
output = string.Empty;
string selectedT = TComboBox.SelectedItem.ToString(),
selectCDocdate = CDocdateComboBox.SelectedItem.ToString(),
selectedCSubject = CSubjectCombobox.SelectedItem.ToString(),
selectedTiff = TiffComboBox.SelectedItem.ToString();
foreach (DataRow row in excelSheet.Rows)
{
if (TToken.Checked)
{
/*..removed code..*/
output += "@T\t\t" + tempOutput + Environment.NewLine;
}
if (CDocdateToken.Checked)
{
string rowValue = row[selectCDocdate].ToString();
string tempOutput = "@C Docdate\t\t" + rowValue + Environment.NewLine;
output += tempOutput;
}
if (CSubjectToken.Checked)
{
string rowValue = row[selectedCSubject].ToString();
string tempOutput = "@C Subject\t\t" + rowValue + Environment.NewLine;
output += tempOutput;
}
if (DToken.Checked)
{
string rowValue = DTextBox.Text;
string tempOutput = "@D \t\t" + rowValue + Environment.NewLine;
output += tempOutput;
}
if (TiffFiles.Checked)
{
/*..removed code..*/
output = TTextBox.Text + "{" + pageFromStr2 + "-" + pageToStr2 + "}.tif";
}
output += Environment.NewLine;
}
OutputDisplayTextBox.Text = output;
}
string
是不可变的,因此,每次使用 +
运算符连接两个 strings/values 时,都会创建一个新字符串并保留其他的 .net 将其从中删除记忆。为避免此问题,您可以使用 StringBuilder
实例,例如:
StringBuilder b = new StringBuilder();
foreach (DataRow row in excelSheet.Rows)
{
if (TToken.Checked)
b.AppendLine(string.Format("@T\t\t{0}", tempOutput));
if (CDocdateToken.Checked)
b.AppendLine(string.Format("@C Docdate\t\t{0}", row[selectCDocdate].ToString()));
if (CSubjectToken.Checked)
b.AppendLine(string.Format("@C Subject\t\t{0}", row[selectedCSubject].ToString()));
if (DToken.Checked)
b.AppendLine(string.Format("@D \t\t{0}", DTextBox.Text));
if (TiffFiles.Checked)
b.Append(TTextBox.Text + "{" + pageFromStr2 + "-" + pageToStr2 + "}.tif");
b.AppendLine();
}
// generate everything in a single string.
output = b.ToString();
根据您的代码进行调整,因为我们没有它的详细信息。
字符串是不可变的,这意味着它们在内存中无法更改。您将看似大量的信息附加到字符串变量中 - 这会在内存中创建许多重复的字符串,占用越来越多的内存并降低应用程序的速度。
改用 StringBuilder
class - 这是可变的。示例:
Stringbuilder builder = new StringBuilder();
builder.AppendLine("text"); // adds a new line to the StringBuilder
当需要输出文本时,在StringBuilder实例上调用.ToString()
。