提前一行读取文件

本文关键字:一行 读取 文件 | 更新日期: 2023-09-27 18:19:40

我有一个相当大的文件,大约80MB,我想把它分成块。我的管道分隔文件结构如下:

Name|ID|Phone|Address
Al|34|3453453234|123 Main
Bo|456|44545|123 Main
Al|34|455666|5th Ave
James|007|7021023456|Green Ave

但正如你所看到的,一个人的信息可能分散在文件中,所以首先用LINQ编写了一个文件分类器,按照ID对文件的行进行排序,所以我的文件现在看起来是这样的:

Name|ID|Phone|Address
James|007|7021023456|Green Ave
Al|34|3453453234|123 Main
Al|34|455666|5th Ave
Bo|456|44545|123 Main

我想说,好吧,让我们把它分成更小的文件,每个文件最多包含50个人。因此,我无法理解的关键也是最主要的一件事是,如何编写代码,使每个文件中最多包含50人,并确保每个人的记录都在同一个文件中?

提前一行读取文件

也许有一些更简单的东西,但这应该有效:

var dataLines = File.ReadLines(@"C:'Temp'SplitFileTest'BigFile.txt")
    .SkipWhile(l => String.IsNullOrWhiteSpace(l)).Skip(1); //skip header
var dataIdGroups = dataLines
    .Select(l => new { Line = l.Trim(), Fields = l.Trim().Split('|') })
    .Where(x => x.Fields.Length == 4)
    .Select(x => new
    {
        Name = x.Fields[0],
        ID = x.Fields[1],
        Phone = x.Fields[2],
        Address = x.Fields[3],
        Line = x.Line
    })
    .GroupBy(x => x.ID);
var allFileLines = new List<List<string>>();
foreach (var userGroup in dataIdGroups)
{
    if (userGroup.Count() > 50 || allFileLines.Count == 0 || allFileLines.Last().Count + userGroup.Count() > 50)
        allFileLines.Add(userGroup.Select(x => x.Line).ToList());
    else
        allFileLines.Last().AddRange(userGroup.Select(x => x.Line));
}

for(int i = 0; i < allFileLines.Count; i++)
    File.WriteAllLines(
        string.Format(@"C:'Temp'SplitFileTest'UserFile_{0}.txt", i + 1), 
        allFileLines[i]);

我用一些样本数据对它进行了测试,它从一个大文件中创建了4个文件,每个用户总是完全在一个文件中。只有当该文件包含的行数少于50行,并且下一个用户能够放入该文件时,它才是混合的。

也许是类似的东西

// Take 50 records
var first50 = source.Take(50).ToList();
// Add all records which have the same name as the last taken record
var additional = source.TakeWhile(p => p.Name == first50.Last().Name);

需要一些角落案例处理(空文件等),但这个想法应该可行。