我有一个文本文件包含以下类似的行,例如500k行。
ADD GTRX:TRXID=0, TRXNAME="M_RAK_JeerExch_G_1879_18791_A-0", FREQ=81, TRXNO=0, CELLID=639, IDTYPE=BYID, ISMAINBCCH=YES, ISTMPTRX=NO, GTRXGROUPID=2556;
ADD GTRX:TRXID=1, TRXNAME="M_RAK_JeerExch_G_1879_18791_A-1", FREQ=24, TRXNO=1, CELLID=639, IDTYPE=BYID, ISMAINBCCH=NO, ISTMPTRX=NO, GTRXGROUPID=2556;
ADD GTRX:TRXID=5, TRXNAME="M_RAK_JeerExch_G_1879_18791_A-2", FREQ=28, TRXNO=2, CELLID=639, IDTYPE=BYID, ISMAINBCCH=NO, ISTMPTRX=NO, GTRXGROUPID=2556;
ADD GTRX:TRXID=6, TRXNAME="M_RAK_JeerExch_G_1879_18791_A-3", FREQ=67, TRXNO=3, CELLID=639, IDTYPE=BYID, ISMAINBCCH=NO, ISTMPTRX=NO, GTRXGROUPID=2556;
我的目的是首先获得FREQ
ISMAINBCCH=YES
的价值,其中ISMAINBCCH=NO
我很容易做到,但是如果FREQ
然后连接File.ReadLines
值,那么我使用{ {1}}但这需要很长时间。有没有更好的方法来做到这一点?如果我为ISMAINBCCH = YES取FREQ
值,则连接值ISMAINBCCH = NO在上下10行的范围内,但我不知道如何实现它。可能我应该获得ISMAINBCCH=YES
FREQ
的当前行。以下是我到目前为止所做的代码
using (StreamReader sr = File.OpenText(filename))
{
while ((s = sr.ReadLine()) != null)
{
if (s.Contains("ADD GTRX:"))
{
try
{
var gtrx = new Gtrx
{
CellId = int.Parse(PullValue(s, "CELLID")),
Freq = int.Parse(PullValue(s, "FREQ")),
//TrxNo = int.Parse(PullValue(s, "TRXNO")),
IsMainBcch = PullValue(s, "ISMAINBCCH").ToUpper() == "YES",
Commabcch = new List<string> { PullValue(s, "ISMAINBCCH") },
DEFINED_TCH_FRQ = null,
TrxName = PullValue(s, "TRXNAME"),
};
var result = String.Join(",",
from ss in File.ReadLines(filename)
where ss.Contains("ADD GTRX:")
where int.Parse(PullValue(ss, "CELLID")) == gtrx.CellId
where PullValue(ss, "ISMAINBCCH").ToUpper() != "YES"
select int.Parse(PullValue(ss, "FREQ")));
}
}
}
gtrx.DEFINED_TCH_FRQ = result;
}
答案 0 :(得分:1)
以下代码段可用于读取整个文本文件:
using System.IO;
/// Read Text Document specified by full path
private string ReadTextDocument(string TextFilePath)
{
string _text = String.Empty;
try
{
// open file if exists
if (File.Exists(TextFilePath))
{
using (StreamReader reader = new StreamReader(TextFilePath))
{
_text = reader.ReadToEnd();
reader.Close();
}
}
else
{
throw new FileNotFoundException();
}
return _text;
}
catch { throw; }
}
获取内存中的字符串,然后应用Split()
函数创建string[]
并以与原始文本文件中的行相同的方式处理数组元素。在处理非常大的文件的情况下,该方法提供了通过数据块读取它,处理它们然后在完成时处理的选项(re:https://msdn.microsoft.com/en-us/library/system.io.streamreader%28v=vs.110%29.aspx)。
正如@Michael Liu的评论中提到的,还有另一种使用File.ReadAllText()
的选项,它提供了更紧凑的解决方案,可以代替reader.ReadToEnd()
使用。 File
类的其他有用方法详见:https://msdn.microsoft.com/en-us/library/system.io.file%28v=vs.110%29.aspx
最后,FileStream
类可以用于具有不同粒度级别的文件读/写操作(re:https://msdn.microsoft.com/en-us/library/system.io.filestream%28v=vs.110%29.aspx)。
概要
在回应有趣的评论主题时,这里有一个简短的总结。
与PO问题中描述的过程相关的最大瓶颈是磁盘IO操作。以下是一些数字:优质HDD的平均寻道时间约为5毫秒加上实际读取时间(每行)。很可能整个内存文件数据处理所花费的时间少于单个HDD IO读取(有时显着;顺便说一下,SSD工作得更好但仍然不能与DDR3 RAM匹配)。现代PC的RAM内存大小相当大(通常4 ... 8 GB RAM足以处理大多数文本文件)。因此,我的解决方案的核心思想是最小化磁盘IO读取操作并在内存中执行整个文件数据处理。显然,实施可能会有所不同。
希望这可能会有所帮助。最好的问候,
答案 1 :(得分:1)
from ss in File.ReadLines(filename)
这将读取整个文件,生成一个数组,然后在循环中使用该数组(本身来自读取同一文件),以便抛弃该数组然后再次创建。如果在此期间没有更改,您将同时读取相同的文件number_of_lines + 1次。
因此,显而易见的提升只需调用File.ReadLines(filename)
一次,存储数组然后将该数组用于循环而不是while ((s = sr.ReadLine()) != null)
并在循环中而不是重复调用{{ 1}}。
但是,即使反复看ReadLines()
,你的逻辑也存在缺陷;您已经在浏览文件,因此无论如何您都会遇到与同一ReadLines()
相关的所有行:
CELLID
这样我们根本不需要在内存中保留多行文件,更不用说反复这样做了。运行后var gtrxDict = new Dictionary<int, Gtrx>();
using (StreamReader sr = File.OpenText(filename))
{
while ((s = sr.ReadLine()) != null)
{
if (s.Contains("ADD GTRX:"))
{
int cellID = int.Parse(PullValue(s, "CELLID"));
Gtrx gtrx;
if(gtrxDict.TryGetValue(cellID, out gtrx)) // Found previous one
gtrx.DEFINED_TCH_FRQ += "," + int.Parse(PullValue(ss, "FREQ"));
else // First one for this ID, so create a new object
gtrxDict[cellID] = new Gtrx
{
CellId = cellID,
Freq = int.Parse(PullValue(s, "FREQ")),
IsMainBcch = PullValue(s, "ISMAINBCCH").ToUpper() == "YES",
Commabcch = new List<string> { PullValue(s, "ISMAINBCCH") },
DEFINED_TCH_FRQ = int.Parse(PullValue(ss, "FREQ")).ToString(),
TrxName = PullValue(s, "TRXNAME"),
};
}
}
}
将包含文件中每个不同gtrxDict
的{{1}}对象,其中Gtrx
为每个匹配行的值的逗号分隔列表。
答案 2 :(得分:0)
我认为这或多或少会让你得到你想要的东西。
首先阅读所有数据:
var data =
(
from s in File.ReadLines(filename)
where s != null
where s.Contains("ADD GTRX:")
select new Gtrx
{
CellId = int.Parse(PullValue(s, "CELLID")),
Freq = int.Parse(PullValue(s, "FREQ")),
//TrxNo = int.Parse(PullValue(s, "TRXNO")),
IsMainBcch = PullValue(s, "ISMAINBCCH").ToUpper() == "YES",
Commabcch = new List<string> { PullValue(s, "ISMAINBCCH") },
DEFINED_TCH_FRQ = null,
TrxName = PullValue(s, "TRXNAME"),
}
).ToArray();
根据加载的数据创建查找以根据每个单元格ID返回频率:
var lookup =
data
.Where(d => !d.IsMainBcch)
.ToLookup(d => d.CellId, d => d.Freq);
现在根据查询更新DEFINED_TCH_FRQ
:
foreach (var d in data)
{
d.DEFINED_TCH_FRQ = String.Join(",", lookup[d.CellId]);
}