逐行读取文件的最快方法? [复制]
Posted
技术标签:
【中文标题】逐行读取文件的最快方法? [复制]【英文标题】:Fastest way to read a file line by line? [duplicate] 【发布时间】:2016-01-28 01:36:50 【问题描述】:我目前有一个 .TXT 文件,我正在尝试读取所有行,对它们进行排序,然后按顺序显示它们。
这就是我所拥有的
string inFile = "Z:/Daniel/Accounts.txt";
string outFile = "Z:/Daniel/SortedAccounts.txt";
var contents = File.ReadAllLines(inFile);
Array.Sort(contents);
File.WriteAllLines(outFile, contents);
int i = 0;
int lineCount = File.ReadLines("Z:/Daniel/SortedAccounts.txt").Count();
do
string accounts = File.ReadLines("Z:/Daniel/SortedAccounts.txt").Skip(i).Take(1).First();
//First Name
int pFrom1 = accounts.IndexOf("#1#") + "#1#".Length;
int pTo1 = accounts.LastIndexOf("#2#");
String accountFirstName = accounts.Substring(pFrom1, pTo1 - pFrom1);
//Last Name
int pFrom2 = accounts.IndexOf("#2#") + "#2#".Length;
int pTo2 = accounts.LastIndexOf("#3#");
String accountLastName = accounts.Substring(pFrom2, pTo2 - pFrom2);
//Email
int pFrom3 = accounts.IndexOf("#3#") + "#3#".Length;
int pTo3 = accounts.LastIndexOf("#4#");
String accountEmail = accounts.Substring(pFrom3, pTo3 - pFrom3);
//Phone Number
int pFrom4 = accounts.IndexOf("#4#") + "#4#".Length;
int pTo4 = accounts.LastIndexOf("#5#");
String accountNumber = accounts.Substring(pFrom4, pTo4 - pFrom4);
//Preferred Contact
int pFrom5 = accounts.IndexOf("#5#") + "#5#".Length;
int pTo5 = accounts.LastIndexOf("#6#");
String accountPreferredContact = accounts.Substring(pFrom5, pTo5 - pFrom5);
//Populate Combobox
accountComboBox.Items.Add(accountLastName + "," + accountFirstName);
i = i + 1;
while (i < lineCount);
Accounts.txt
内部的一个例子是
#1#Daniel#2#Mos#3#dasdnmasdda@gmail.com#4#31012304#5#EMAIL#6# #1#Daniael#2#Mosa#3#dddasdsa@gmail.com#4#310512304#5#EMAIL#6# #1#Dansdael#2#Mossdsa#3#dasdsdssa@gmail.com#4#31121234#5#TEXT#6# #1#Danasdl#2#Mosasaa#3#daasda@gmail.com#4#310123304#5#EMAIL#6# #1#Dandasel#2#Moasddand#3#daasdsda@gmail.com#4#3123551234#5#TEXT#6# #1#Danasdl#2#Mossdsadd#3#daasddsa@gmail.com#4#310213304#5#TEXT#6#
问题是,有时Accounts.txt
将有超过 10,000 行,然后程序需要一段时间才能加载。
我写的代码有更快的实现吗?
【问题讨论】:
一般来说,读取每一行并处理它可能比将整个文件读入内存中的一个巨大字符串然后解析它更快。不过,类似的问题还有很多。 嗨,你已经加载了 string[] 内容中的所有文本,为什么只使用它来循环它而不是从输出文件中再次读取? @JohnGardner ,在我看来,好像那个线程在说我正在做的已经是最快的方法。真可惜 而不是所有的 string.indexof/lastindexof,对于编译的正则表达式来说,这看起来是一个很好的候选者,它可以一次获得所有值。 除了你不只是“读取文件”。您正在:读取文件、对其进行排序、将其写回、再次读取、应用大量字符串操作,然后将项目添加到组合框。最后一步可能是所有这一切中最糟糕的部分,这取决于这是什么 ui 技术。 【参考方案1】:我的建议:
-
逐行读取文件,例如
file.readlines
,在进行过程中进行流式传输,而不是读取整个文件(尤其是不要以原来的方式读取文件两次!)
对于每一行,应用一个已编译的正则表达式,从该字符串中获取您需要的值
创建一个帐户类(或者我猜只是一个字符串值),根据需要保存 2 中的所有值。看起来您的循环只关心 2 个字符串(accountLastName
和 accountFirstName
)
将这些添加到不是组合框项目的列表中。
如果您需要对它们进行排序(尽可能少地和尽可能晚地排序),请使用 linq/sort 对它们进行排序,例如 items.OrderBy( x => x.LastName ).ThenBy( y => y.FirstName)
或其他任何东西
在最后将整个项目块添加到您的组合框中,而不是一次一个。理想情况下类似于combobox.Items.AddRange(items)
(许多组合框/等集合可能会在每次添加一个项目时触发一个集合更改事件,如果您要添加 1000 个项目,这可能会产生很多开销)
【讨论】:
其他一切对我来说都很有意义,但我已经被卡住了,哈哈。我不能让正则表达式工作? pastebin.com/HtY12yk5【参考方案2】:所有代码都应该按以下方式重构。您需要衡量这两种方法的性能。
const string inFile = "Z:/Daniel/Accounts.txt";
const string outFile = "Z:/Daniel/SortedAccounts.txt";
string[] contents = File.ReadAllLines(inFile);
Array.Sort(contents);
File.WriteAllLines(outFile, contents);
IEnumerable<string> lines = File.ReadLines("Z:/Daniel/SortedAccounts.txt");
foreach (string line in lines)
//First Name
string[] data = Regex.Split(line, "[#\\d#]");
string accountFirstName = data[0];
string accountLastName = data[1];
string accountEmail = data[2];
//Phone Number
string accountNumber = data[3];
//Preferred Contact
string accountPreferredContact = data[4];
//Populate Combobox
//accountComboBox.Items.Add(accountLastName + "," + accountFirstName);
编辑“使用 AddRange”
class Account
public string FirstName get; set;
public string LastName get; set;
public string Email get; set;
public string Number get; set;
public string PreferredContact get; set;
accountComboBox.Items.AddRange(
lines.Select(line => Regex.Split(line, "[#\\d#]")).Select(data => new Account
FirstName = data[0],
LastName = data[1],
Email = data[2],
Number = data[3],
PreferredContact = data[4]
).Select(item => string.Format("0,1", item.LastName, item.FirstName)).ToArray()
);
【讨论】:
如何将它添加到组合框? 同理,取消注释 John Gardner 说“在最后将整个项目块添加到您的组合框中,而不是一次一个。理想情况下,类似于 combobox.Items.AddRange(items)”。我怎么能这样做? 代码已修改,但需要衡量性能以上是关于逐行读取文件的最快方法? [复制]的主要内容,如果未能解决你的问题,请参考以下文章