这个问题在这里已有答案:
我有一个100万行的文件。如果程序包含用户请求删除的单词之一,我的程序将逐行检查。如果该行包含该单词,则必须将其删除并添加到列表中。每次按下“开始”,程序都会冻结,并且列表框中不显示任何内容。但是,如果我添加像1k它将清理文件并在列表中显示新文件。处理这个问题的最佳方法是什么?
我的代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace BoringAssComboTool
{
public partial class Form2 : Form
{
List<String> list;
string myFile = null;
string[] line = null;
int linecount = 0;
public Form2()
{
InitializeComponent();
}
private void groupBox1_Enter(object sender, EventArgs e)
{
}
private void label1_Click(object sender, EventArgs e)
{
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
public void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.RestoreDirectory = true;
openFileDialog.Multiselect = false;
openFileDialog.Filter = "Combo List (*.txt)|*.txt";
openFileDialog.FilterIndex = 1;
if (openFileDialog.ShowDialog() == DialogResult.OK)
{
myFile = openFileDialog.FileName;
MessageBox.Show("You selected " + openFileDialog.FileName);
linecount = File.ReadAllLines(myFile).Length;
label3.Text = "Total loaded : " + linecount;
line = File.ReadAllLines(myFile);
//MessageBox.Show(line[0]);
//MessageBox.Show(line[4]);
list = File.ReadAllLines(myFile).ToList();
// StreamReader sr = new StreamReader(myFile);
}
}
private void button3_Click(object sender, EventArgs e)
{
int removedlines = 0;
string domainSplitted = textBox1.Text;
string[] splitDomain = domainSplitted.Split(',');
//MessageBox.Show(splitDomain[2]);
//MessageBox.Show(splitDomain[3]);
//MessageBox.Show(line[2]);
int sizeOfArray = splitDomain.Length;
// MessageBox.Show("Length is " + sizeOfArray);
for (int x = 0; x < sizeOfArray - 1; x++)
{
// for (int i = 0; i < linecount - 1; i++)
for ( int i = linecount - 1; i>=0; i--)
{
if (line[i].Contains(splitDomain[x]))
{
list.RemoveAt(i);
string[] lines = list.ToArray();
removedlines++;
label4.Text = "Total Removed = " + removedlines;
listBox1.DataSource = list;
// MessageBox.Show("there is a match on " + line[i]);
}
}
}
// listBox1.DataSource = list;
}
private void pictureBox3_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
}
private void pictureBox2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void label3_Click(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
// System.IO.File.WriteAllLines("Cleaned Combo File.txt", list);
SaveFileDialog save = new SaveFileDialog();
save.FileName = "Cleaned Combo File.txt";
save.Filter = "Text File | *.txt";
if (save.ShowDialog() == DialogResult.OK)
{
StreamWriter writer = new StreamWriter(save.OpenFile());
for (int i = 0; i < listBox1.Items.Count; i++)
{
writer.WriteLine(listBox1.Items[i].ToString());
}
writer.Dispose();
writer.Close();
MessageBox.Show("Saved succesfully");
}
}
// MessageBox.Show("==" + line[27]);
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_NCHITTEST)
m.Result = (IntPtr)(HT_CAPTION);
}
private const int WM_NCHITTEST = 0x84;
private const int HT_CLIENT = 0x1;
private const int HT_CAPTION = 0x2;
private void Form2_Load(object sender, EventArgs e)
{
}
}
}
你不应该把所有文本都读到内存中。而是将程序更改为逐行读取。然后,您可以将每个更新/固定行附加到临时文件中。处理完成后,如有必要,使用临时文件覆盖源文件。
以下是逐行读取文件的方法:
using (StreamReader sr = new StreamReader(path))
{
while (sr.Peek() >= 0)
{
Console.WriteLine(sr.ReadLine());
}
}
Here是StreamReader / StreamWriter类的文档。
除此之外,我建议你切换到async
API。 StreamReader也有一个ReadLineAsync
API,以满足这种需求。这将允许避免UI线程的长时间延迟。