2016-02-23 2 views
3

Я хотел бы получить оценку количества строк в текстовом файле csv/text, чтобы я мог использовать этот номер для индикатора выполнения. Файл может быть чрезвычайно большим, поэтому получение точного количества строк займет слишком много времени для этой цели.Получить оценку количества строк в текстовом файле

То, что я придумал ниже (читайте в части файла и подсчитать количество строк и использовать размер файла для оценки общего количества строк):

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)

Буду признателен за любую помощь, чтобы сделать эту функцию более надежной.

ответ

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; 
    } 
} 
0
var lineCount = File.ReadLines(@"C:\file.txt").Count(); 

Другой способ:

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

Спасибо, но это именно то, чего я не хочу. Мне нужна оценка, а не точное количество строк. Для большого файла (1 гб) это может занять 10 и более секунд, мне нужен приблизительный метод, например, мой примерный код, который почти мгновен для больших файлов. – tjsmith

0

Вы обманываете! Вы просите больше, чем один вопрос ... Я буду стараться в любом случае, чтобы помочь вам: P

  1. Нет, вы не можете использовать поток, но вы можете использовать StreamReader. Это должно обеспечить необходимую гибкость.

  2. Тест для кодирования, так как я выводю, что вы будете работать с различными. Имейте в виду, однако, что обычно сложно обслуживать ВСЕ сценарии, поэтому сначала выберите несколько важных и продолжите свою программу позже.

  3. Не - позвольте мне показать вам, как:

Во-первых, рассмотрим ваш источник. Будь то поток файлов или памяти, вы должны иметь представление о его размере. Я сделал бит файла, потому что я ленив, и это легко, поэтому вам придется самому вычислить бит потока памяти. То, что я сделал, намного проще, но менее точно: прочитайте первую строку файла и используйте его в процентах от размера файла. Примечание. Я умножил длину строки на 2 как таковую на дельте, другими словами, количество дополнительных байтов, используемых для дополнительного символа в строке. Очевидно, это не очень точно, поэтому вы можете расширить его до количества строк, просто имейте в виду, что вам также придется изменить формулу.

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(); 
    } 
Смежные вопросы