【问题标题】:Get Estimate of Line Count in a text file获取文本文件中行数的估计值
【发布时间】:2016-02-23 05:40:14
【问题描述】:

我想估计 csv/文本文件中的行数,以便我可以将该数字用作进度条。该文件可能非常大,因此获取确切的行数将花费很长时间。

我想出的如下(读入文件的一部分并计算行数并使用文件大小来估计总行数):

    public static int GetLineCountEstimate(string file)
    {
        double count = 0;
        using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read))
        {
            long byteCount = fs.Length;
            int maxByteCount = 524288;
            if (byteCount > maxByteCount)
            {
                var buf = new byte[maxByteCount];
                fs.Read(buf, 0, maxByteCount);
                string s = System.Text.Encoding.UTF8.GetString(buf, 0, buf.Length);
                count = s.Split('\n').Length * byteCount / maxByteCount;
            }
            else
            {
                var buf = new byte[byteCount];
                fs.Read(buf, 0, (int)byteCount);
                string s = System.Text.Encoding.UTF8.GetString(buf, 0, buf.Length);
                count = s.Split('\n').Length;
            }
        }
        return Convert.ToInt32(count);
    }

这似乎工作正常,但我有一些顾虑:

1) 我想让我的参数简单地作为 Stream(而不是文件名),因为我也可能从剪贴板 (MemoryStream) 读取。但是 Stream 似乎无法一次将 n 个字节读入缓冲区或获取 Stream 的总长度(以字节为单位),就像 FileStream 一样。 Stream 是 MemoryStream 和 FileStream 的父类。

2) 我不想假设像 UTF8 这样的编码

3) 我不想假设行尾字符(它应该适用于 CR、CRLF 和 LF)

我将不胜感激任何帮助,使这个功能更健壮。

【问题讨论】:

    标签: c# stream filestream memorystream line-count


    【解决方案1】:

    这是我想出的更强大的估计行数的解决方案。

    public static int EstimateLineCount(string file)
    {
        using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read))
        {
            return EstimateLineCount(fs);
        }
    }
    
    public static int EstimateLineCount(Stream s)
    {
        //if file is larger than 10MB estimate the line count, otherwise get the exact line count
        const int maxBytes = 10485760; //10MB = 1024*1024*10 bytes
    
        s.Position = 0;
        using (var sr = new StreamReader(s, Encoding.UTF8))
        {
            int lineCount = 0;
            if (s.Length > maxBytes)
            {
                while (s.Position < maxBytes && sr.ReadLine() != null)
                    lineCount++;
    
                return Convert.ToInt32((double)lineCount * s.Length / s.Position);
            }
    
            while (sr.ReadLine() != null)
                lineCount++;
            return lineCount;
        }
    }
    

    【讨论】:

      【解决方案2】:
      var lineCount = File.ReadLines(@"C:\file.txt").Count();
      

      另一种方式:

      var lineCount = 0;
      using (var reader = File.OpenText(@"C:\file.txt"))
      {
          while (reader.ReadLine() != null)
          {
              lineCount++;
          }
      }
      

      【讨论】:

      • 谢谢,但这正是我不想要的。我想要一个估计,而不是确切的行数。对于大文件 (1gb),这可能需要 10 秒或更长时间,我想要一个近似方法,例如我的示例代码,对于大文件来说几乎是瞬时的。
      【解决方案3】:

      你在作弊!你问的不止一个问题......无论如何我都会尽力帮助你:P

      1. 不,您不能使用 Stream,但可以使用 StreamReader。这应该提供您需要的灵活性。

      2. 测试编码,因为我推断您将使用各种编码。但请记住,通常很难满足所有场景,因此请先选择一些重要的场景,然后再扩展您的程序。

      3. 不要 - 让我告诉你怎么做:

      首先,考虑您的来源。无论是文件还是内存流,您都应该知道它的大小。我已经完成了文件位,因为我很懒而且很容易,所以您必须自己弄清楚内存流位。我所做的更简单但不太准确:读取文件的第一行,并将其用作文件大小的百分比。请注意,我将字符串的长度乘以 2,因为这是增量,换句话说,字符串中每个额外字符使用的额外字节数。显然这不是很准确,因此您可以将其扩展到 x 行,但请记住您还必须更改公式。

      static void Main(string[] args)
          {
              FileInfo fileInfo = new FileInfo((@"C:\Muckabout\StringCounter\test.txt"));
              using (var stream = new StreamReader(fileInfo.FullName))
              {
                  var firstLine = stream.ReadLine(); // Read the first line.
                  Console.WriteLine("First line read. This is roughly " + (firstLine.Length * 2.0) / fileInfo.Length * 100 + " per cent of the file.");
              }
              Console.ReadKey();
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-09-09
        • 1970-01-01
        • 2012-09-16
        • 2011-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多