Respostas:
Edição seriamente tardia: se você estiver usando o .NET 4.0 ou posterior
A File
classe possui um novo ReadLines
método que enumera preguiçosamente as linhas, em vez de lê-las avidamente em uma matriz semelhante ReadAllLines
. Portanto, agora você pode ter eficiência e concisão com:
var lineCount = File.ReadLines(@"C:\file.txt").Count();
Resposta original
Se você não está muito preocupado com a eficiência, basta escrever:
var lineCount = File.ReadAllLines(@"C:\file.txt").Length;
Para um método mais eficiente, você pode fazer:
var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
while (reader.ReadLine() != null)
{
lineCount++;
}
}
Edit: Em resposta a perguntas sobre eficiência
A razão pela qual eu disse que o segundo era mais eficiente foi em relação ao uso de memória, não necessariamente à velocidade. O primeiro carrega todo o conteúdo do arquivo em uma matriz, o que significa que ele deve alocar pelo menos tanta memória quanto o tamanho do arquivo. O segundo apenas faz um loop de uma linha de cada vez, para nunca precisar alocar mais do que uma linha de memória por vez. Isso não é importante para arquivos pequenos, mas para arquivos maiores pode ser um problema (se você tentar encontrar o número de linhas em um arquivo de 4 GB em um sistema de 32 bits, por exemplo, onde simplesmente não há o suficiente espaço de endereço no modo de usuário para alocar uma matriz desse tamanho).
Em termos de velocidade, eu não esperaria que houvesse muito nele. É possível que o ReadAllLines tenha algumas otimizações internas, mas, por outro lado, pode ser necessário alocar um grande pedaço de memória. Eu acho que o ReadAllLines pode ser mais rápido para arquivos pequenos, mas significativamente mais lento para arquivos grandes; embora a única maneira de saber seja medi-lo com um cronômetro ou um criador de perfil de código.
ReadLines().Count()
isso, você precisará adicionar um using System.Linq
às suas inclusões. Parecia bastante intuitivo exigir essa adição, e é por isso que eu a menciono. Se você estiver usando o Visual Studio, é provável que essa adição seja feita automaticamente.
Se por fácil você quer dizer linhas de código fáceis de decifrar, mas por acaso ineficientes?
string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();
Essa é provavelmente a maneira mais rápida de saber quantas linhas.
Você também pode fazer (dependendo se você está armazenando o buffer)
#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}
Existem outras maneiras, mas uma das opções acima é provavelmente a que você irá usar.
Você pode ler rapidamente e incrementar um contador, basta usar um loop para incrementar, sem fazer nada com o texto.
A leitura de um arquivo por si só leva algum tempo, a coleta de lixo é outro problema, à medida que você lê o arquivo inteiro apenas para contar os caracteres da nova linha,
Em algum momento, alguém terá que ler os caracteres no arquivo, independentemente se esse for o framework ou se for o seu código. Isso significa que você precisa abrir o arquivo e lê-lo na memória, se o arquivo for grande, isso poderá ser um problema, pois a memória precisa ser coletada como lixo.
Nima Ara fez uma boa análise que você pode levar em consideração
Aqui está a solução proposta, que lê 4 caracteres por vez, conta o caractere de alimentação de linha e reutiliza o mesmo endereço de memória novamente para a próxima comparação de caracteres.
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;
}
Acima, você pode ver que uma linha é lida com um caractere de cada vez, além da estrutura subjacente, pois você precisa ler todos os caracteres para ver o feed da linha.
Se você criar um perfil como o bay Nima concluído, verá que essa é uma maneira bastante rápida e eficiente de fazer isso.
Uma opção viável, e que eu pessoalmente usei, seria adicionar seu próprio cabeçalho à primeira linha do arquivo. Eu fiz isso para um formato de modelo personalizado para o meu jogo. Basicamente, eu tenho uma ferramenta que otimiza meus arquivos .obj, livrando-se da porcaria de que não preciso, os converte em um layout melhor e depois grava o número total de linhas, faces, normais, vértices e UVs de textura em a primeira linha. Esses dados são usados por vários buffers de matriz quando o modelo é carregado.
Isso também é útil porque você só precisa percorrer o arquivo uma vez para carregá-lo, em vez de contar uma vez as linhas e novamente ler os dados nos buffers criados.
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);
}
Você pode iniciar o executável " wc .exe" (fornecido com o UnixUtils e não precisa de instalação) executado como um processo externo. Ele suporta diferentes métodos de contagem de linhas (como unix vs mac vs windows).