繁体   English   中英

从 C# 中的文本文件一次读取 10 行

[英]Read 10 lines at a time from text file in C#

我正在寻找一种解决方案,从文本文件中读取 10 行,然后再读取 10 行,直到文件末尾。 这是我开始的,当然它显示了前 10 行,但是我怎样才能在接下来的 10 行中重复这个过程等等,直到文件结束?

private void openFile_Click(object sender, EventArgs e)
{
    int counter = 0;
    string line;

    using (var file =
       new System.IO.StreamReader(@"C:\\Users\\LJ_TEX\\Desktop\\Book1.txt"))
    {
        while ((line = file.ReadLine()) != null)
        {
            counter++;
            if (counter <= 10)
            {
                tboxreadData.AppendText(line + '\r' + '\n');
            }
            if (counter == 10)
            {
                tboxreadData.AppendText("NEXT");
            }
        }
    }
}

编辑

所以我设法做了一点改变,点击按钮显示一行

 System.IO.StreamReader file = null;

 private void openFile_Click(object sender, EventArgs e)
    {
        string line;

        if (file == null)
            file = new System.IO.StreamReader(@"C:\\Users\\LJ_TEX\\Desktop\\Book1.txt");

        if (!file.EndOfStream)
        {
            line = file.ReadLine();
            tboxreadData.AppendText(line + '\r' + '\n');
        }
        else
        {
            tboxreadData.AppendText("End");
        }
       
    }

当然,它一次只显示一条线。 如果有人知道如何显示更多行(5 或 10 行),请随时分享。

谢谢,乔纳森

您可以通过使用模运算符 (%) 来实现。 所以你检查你的counter%10=0是否打印出“NEXT”-Line。

您的示例可能如下所示:

private void openFile_Click(object sender, EventArgs e)
    {
        int counter = 0;
        string line;

        System.IO.StreamReader file = new System.IO.StreamReader(@"C:\\Users\\LJ_TEX\\Desktop\\Book1.txt");

        while ((line = file.ReadLine()) != null)
        {
            counter++;               
            tboxreadData.AppendText(line + '\r' + '\n');
            if(counter%10 == 0){
                tboxreadData.AppendText("NEXT");
            }
        }
    }

编辑:

对于每次读取 10 行(如果存在),您可以使用以下代码段。 它不是高性能的,因为您每次都会从头开始阅读:

int _lineCounter = 0;

private void openFile_Click(object sender, EventArgs e)
    {
        int counter = 0;
        string line;

        System.IO.StreamReader file = new System.IO.StreamReader(@"C:\\Users\\LJ_TEX\\Desktop\\Book1.txt");

        while ((line = file.ReadLine()) != null)
        {
            counter++;
            if(counter < _linecounter)
                continue;
            tboxreadData.AppendText(line + '\r' + '\n');
            if(counter%10 == 0){
                tboxreadData.AppendText("NEXT");
                break;
            }
        }
        _lineCounter = counter;
    }

您可以创建自己的扩展方法,该方法采用IEnumerbale<T>并将其划分为块。 从那里您可以使用foreach或任何标准 linq 样式链方法对其进行迭代

给定

// updated, this is completely lazy loaded
public static class Extensions
{
   public static IEnumerable<IEnumerable<TValue>> Partition<TValue>(this IEnumerable<TValue> source, int size)
   {
      using var enumerator = source.GetEnumerator();
      static IEnumerable<T> GetChunk<T>(IEnumerator<T> enumerator, int chunkSize)
      {
         for (var i = 0; i < chunkSize && enumerator.MoveNext(); i++)
            yield return enumerator.Current;
      }

      while (enumerator.MoveNext())
         yield return GetChunk(enumerator, size);
   }
}

用法

var partitions = File
     .ReadLines(@"D:\ids.txt")
     .Partition(10);

foreach (var partition in partitions)
{
   Console.WriteLine("Start partition");
   foreach (var line in partition )
      Console.WriteLine(line);
}

Output

Start partition
1516556 E763794 1773595 33EBM5015703
1516556 E763794 1773657 33EBM5015703
1518933 E764710 1776347 33EBM5015705
1519147 H182989 1776617 33EBM5015702
1519264 H183025 1776745 33EBM5015686
1519310 X186946 1776805 33EBM5015695
1519622 X186992 1777159 33EBM5015704
1519623 E765015 1777160 33EBM5015716
1519818 H183205 1777375 33EBM5015681
1519932 E765141 1777546 33EBM5015700
Start partition
1520345 E765295 1778070 33EBM5015715
1520366 E765303 1778097 33EBM5015684
1520385 X187075 1778117 33EBM5015675
1520420 H183413 1778157 33EBM5015662
1520429 H183418 1778166 33EBM5015654
1520466 X187085 1778203 33EBM5015663
1520468 E765345 1778205 33EBM5015658
1520476 E765349 1778214 33EBM5015677
1520486 H183441 1778224 33EBM5015664
1520496 H183444 1778234 33EBM5015671
Start partition
1520506 E765361 1778244 33EBM5015666
1520510 E765364 1778248 33EBM5015670
1520528 H183462 1778270 33EBM5015680
1520550 H183474 1778292 33EBM5015653
1520553 X187092 1778295 33EBM5015706
1520558 E765382 1778300 33EBM5015650
1520574 E765389 1778316 33EBM5015656
1520585 E765396 1778327 33EBM5015669
1520618 X187102 1778360 33EBM5015682
1520621 E765408 1778363 33EBM5015667

你想要的很常见:你想“每页”阅读你的输入。

换句话说:你有一系列相似的项目,你想把它分成大小相等的子组。

如果您将定期使用它,请考虑为其创建一些类。 这样,您可以将它用于需要“每页”获取项目的几个问题。

我经常使用它从每页的数据库中获取项目。 由于通用类,我可以将 IQueryable / IEnumerable 放入 PageCollection class 并询问页数和 Page[3]。

如果你做的很聪明,你就不必获取你不使用的项目,也不需要重新获取你已经获取的项目。

我们隐藏页面的内部。 因此我们创建了一个接口:

interface IPage<T> : IReadOnlyCollection<T>, IEnumerable<T>
{
    int PageNr {get; }             // the zero based number of the page
    int PageCount {get; }          // the total number of available pages
    int PageLength {get; }         // The number of items on this page

我选择实现IReadOnlyCollection<T>而不是IReadOnlyList<T> ,因为索引通常给人的印象不正确。

例如,如果您有一个ProductPages集合,那么每个ProductPage都有零个或多个Products 但是,如果您在ProductPage[10]上并要求Product[3] ,您会期待什么? 有些人可能会将其与具有主键 3 的Product混淆。

也许以下方法也可能很方便:

    IPage<T> PreviousPage {get;}
    IPage<T> NextPage {get;}
    IPage<T> GetPage(int pageNr);
    IReadOnlyList<T> PageCollection {get;}
}

首先让我们创建 PageCollection。 PageCollection 将创建页面:

class PageCollection<T> : IReadOnlyList<T>
{
    private readonly IDictionary<int, IPage<T>> fetchedPages
        = new Dictionary<int, IPage<T>();

    private int pageCount = -1; // not known yet

    public PageCollection<IEnumerable<T> query, pageSize)
    {
        // TODO: check input parameters for incorrect values
        this.Query = query;
        this.PageSize = pageSize;
    }

    public IEnumerable<T> Query {get;} 
    // TODO: consider IQueryable if you use databases / entity framework

    public int PageSize {get;}
    ...
}

我们需要一些方法来获取页面的数量,并通过索引来获取页面:

public int Count
{
    get
    {
        if (this.pageCount < 0)
           this.pageCount = this.Query.Count();
        return this.pageCount;
    }
}

public IPage this[int pageIndex] => this.GetPage(pageIndex);

最后我们来到创建页面的部分:

public IPage<T> GetPage(int pageIndex)
{
    if (0 < pageIndex || pageIndex >= this.Count)
    {
        // pageIndex out of range.
        // TODO: decide whether to return null or throw exception
    }

    if (!this.fetchedPages.TryGetValue(pageIndex, out Page<T> fetchedPage)
    {
        // page never fetched before, fetch it now
        fetchedPage = this.FetchPage(pageIndex);
        this.FetchedPages.Add(pageIndex, fetchedPage);
    }
    return fetchedPage;
}

我决定将获取的页面保存在字典中,而不是列表中。 这样,您可以在获取页面 0 到 4 之前请求 Page[5]。

private Page<T> FetchPage(int pageIndex)
{
    return new Page(this, pageIndex);
}

好吧,这并没有多大作用:显然它是完成所有工作的页面。 是时候创建页面了。

您必须自己决定是立即阅读完整页面,还是仅在您要求时阅读

class Page<T> : IPage<T>, IReadOnlyCollection<T>, IEnumerable<T>
{
    public Page(PageCollection<T> pageCollection, int pageNr)
    {
         this.PageCollection = pageCollection;
         this.PageNr = pageNr;

         // if you want to fetch the data immediately:
         this.PageContent = this.Query.ToList();
    }

    public PageCollection<T> PageCollection {get;}
    public int PageNr {get;}
    public int PageCount => this.PageCollection.Count;
    public IReadOnlyCollection<T> PageContent {get;}

    public IEnumerable<T> Query => this.PageCollection.Query
        .Skip(this.PageNr * this.PageSize)
        .Take(this.PageSize);
}

IReadOnlyCollection<T>IEnumerable<T>的实现相当简单,方法都调用this.PageContent

IEnumerator<T> GetEnumerator() {return this.PageContent.GetEnumerator();}
int Count => this.PageContent.Count;

等等

像 PreviousPage / NextPage / GetPage 这样的“很高兴”过程是单行的,因为它们可以通过询问 PageCollection 来处理:

IPage<T> PreviousPage => this.PageCollection.GetPage(this.PageNr-1);

当然,您必须决定如果 Page 超出范围该怎么办:异常还是返回 null?

最后使用:

const int pageSize = 25;
IEnumerable<Product> queryProducts = ...
PageCollection<Product> productPages =
   new PageCollection<Product>(queryProducts, pageSize);

Page<Product> productPage = productPages.FirstOrDefault();
// this page can be used as a collection of Products
DisplayProducts(productPage);

// get the next page:
Page<Product> nextPage = productPage.NextPage;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM