Ответы:
Серьезно запоздалое редактирование: если вы используете .NET 4.0 или новее
В File
классе появился новый ReadLines
метод, который лениво перечисляет строки, а не жадно читает их все в виде массива ReadAllLines
. Так что теперь вы можете иметь как эффективность и краткость с:
var lineCount = File.ReadLines(@"C:\file.txt").Count();
Оригинальный ответ
Если вы не слишком обеспокоены эффективностью, вы можете просто написать:
var lineCount = File.ReadAllLines(@"C:\file.txt").Length;
Для более эффективного метода вы можете сделать:
var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
while (reader.ReadLine() != null)
{
lineCount++;
}
}
Изменить: В ответ на вопросы об эффективности
Причина, по которой я сказал, что вторая была более эффективной, касалась использования памяти, а не обязательно скорости. Первый загружает все содержимое файла в массив, что означает, что он должен выделять как минимум столько же памяти, сколько размер файла. Вторая просто зацикливает одну строку за раз, поэтому ей никогда не нужно выделять больше памяти на одну строку за раз. Это не так важно для маленьких файлов, но для больших файлов это может быть проблемой (например, если вы попытаетесь найти число строк в файле 4 ГБ в 32-битной системе, например, там, где его просто недостаточно) адресное пространство пользовательского режима для выделения такого большого массива).
Что касается скорости, я бы не ожидал, что в ней будет много. Возможно, что ReadAllLines имеет некоторую внутреннюю оптимизацию, но, с другой стороны, возможно, ему придется выделить большой кусок памяти. Я предполагаю, что ReadAllLines может быть быстрее для небольших файлов, но значительно медленнее для больших файлов; хотя единственный способ определить это - измерить его с помощью секундомера или профилировщика кода.
ReadLines().Count()
вам нужно добавить using System.Linq
в свои списки. Казалось довольно не интуитивным требовать этого дополнения, поэтому я и упоминаю об этом. Если вы используете Visual Studio, скорее всего, это дополнение будет сделано автоматически.
Если под легким вы подразумеваете строки кода, которые легко расшифровать, но, по всей вероятности, неэффективны?
string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();
Вероятно, это самый быстрый способ узнать, сколько строк.
Вы также можете сделать (в зависимости от того, буферизуете ли вы его)
#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}
Существуют и другие многочисленные способы, но, вероятно, вы пойдете одним из перечисленных выше.
Вы можете быстро прочитать его и увеличить счетчик, просто используя цикл для увеличения, ничего не делая с текстом.
Считывание файла само по себе занимает некоторое время, сбор мусора в результате - еще одна проблема, поскольку вы читаете весь файл только для того, чтобы подсчитать символы новой строки,
В какой-то момент кому-то придется читать символы в файле, независимо от того, является ли это структурой или это ваш код. Это означает, что вы должны открыть файл и прочитать его в память, если файл большой, это может стать проблемой, так как память должна собирать мусор.
Нима Ара сделал хороший анализ, который вы могли бы принять во внимание
Вот предлагаемое решение, так как оно считывает 4 символа за раз, считает символ перевода строки и снова использует тот же адрес памяти для следующего сравнения символов.
private const char CR = '\r';
private const char LF = '\n';
private const char NULL = (char)0;
public static long CountLinesMaybe(Stream stream)
{
Ensure.NotNull(stream, nameof(stream));
var lineCount = 0L;
var byteBuffer = new byte[1024 * 1024];
const int BytesAtTheTime = 4;
var detectedEOL = NULL;
var currentChar = NULL;
int bytesRead;
while ((bytesRead = stream.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
{
var i = 0;
for (; i <= bytesRead - BytesAtTheTime; i += BytesAtTheTime)
{
currentChar = (char)byteBuffer[i];
if (detectedEOL != NULL)
{
if (currentChar == detectedEOL) { lineCount++; }
currentChar = (char)byteBuffer[i + 1];
if (currentChar == detectedEOL) { lineCount++; }
currentChar = (char)byteBuffer[i + 2];
if (currentChar == detectedEOL) { lineCount++; }
currentChar = (char)byteBuffer[i + 3];
if (currentChar == detectedEOL) { lineCount++; }
}
else
{
if (currentChar == LF || currentChar == CR)
{
detectedEOL = currentChar;
lineCount++;
}
i -= BytesAtTheTime - 1;
}
}
for (; i < bytesRead; i++)
{
currentChar = (char)byteBuffer[i];
if (detectedEOL != NULL)
{
if (currentChar == detectedEOL) { lineCount++; }
}
else
{
if (currentChar == LF || currentChar == CR)
{
detectedEOL = currentChar;
lineCount++;
}
}
}
}
if (currentChar != LF && currentChar != CR && currentChar != NULL)
{
lineCount++;
}
return lineCount;
}
Выше вы можете видеть, что строка читается по одному символу за раз также базовой платформой, так как вам нужно прочитать все символы, чтобы увидеть перевод строки.
Если вы профилируете это как готовый залив Нима, вы увидите, что это довольно быстрый и эффективный способ сделать это.
Возможным вариантом, который я лично использовал, было бы добавление собственного заголовка в первую строку файла. Я сделал это для пользовательского формата модели для моей игры. По сути, у меня есть инструмент, который оптимизирует мои файлы .obj, избавляясь от ненужной мне ненужной ерунды, преобразует их в лучший макет, а затем записывает общее количество линий, граней, нормалей, вершин и текстурных UV-объектов на самая первая строка. Эти данные затем используются различными буферами массива при загрузке модели.
Это также полезно, потому что вам нужно только один раз просмотреть файл, чтобы загрузить его, а не один раз, чтобы посчитать строки, и снова, чтобы прочитать данные в созданные вами буферы.
try {
string path = args[0];
FileStream fh = new FileStream(path, FileMode.Open, FileAccess.Read);
int i;
string s = "";
while ((i = fh.ReadByte()) != -1)
s = s + (char)i;
//its for reading number of paragraphs
int count = 0;
for (int j = 0; j < s.Length - 1; j++) {
if (s.Substring(j, 1) == "\n")
count++;
}
Console.WriteLine("The total searches were :" + count);
fh.Close();
} catch(Exception ex) {
Console.WriteLine(ex.Message);
}
Вы можете запустить исполняемый файл " wc .exe" (поставляется с UnixUtils и не требует установки), запущенный как внешний процесс. Он поддерживает различные методы подсчета строк (например, Unix против Mac и Windows).