Tentukan jumlah baris dalam file teks

209

Apakah ada cara mudah untuk secara program menentukan jumlah baris dalam file teks?

TK.
sumber

Jawaban:

396

Sunting terlambat: Jika Anda menggunakan .NET 4.0 atau lebih baru

The Filekelas memiliki baru ReadLinesmetode yang malas menyebutkan garis daripada rakus membaca mereka semua ke dalam array seperti ReadAllLines. Jadi sekarang Anda dapat memiliki efisiensi dan keringkasan dengan:

var lineCount = File.ReadLines(@"C:\file.txt").Count();

Jawaban Asli

Jika Anda tidak terlalu peduli dengan efisiensi, Anda cukup menulis:

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;

Untuk metode yang lebih efisien, Anda dapat melakukan:

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

Sunting: Menanggapi pertanyaan tentang efisiensi

Alasan saya mengatakan yang kedua lebih efisien adalah tentang penggunaan memori, belum tentu kecepatan. Yang pertama memuat seluruh isi file ke dalam array yang berarti harus mengalokasikan setidaknya memori sebanyak ukuran file. Baris kedua hanya memotong satu baris pada satu waktu sehingga tidak perlu mengalokasikan lebih dari satu memori dalam satu waktu. Ini tidak begitu penting untuk file kecil, tetapi untuk file yang lebih besar itu bisa menjadi masalah (jika Anda mencoba dan menemukan jumlah baris dalam file 4GB pada sistem 32-bit, misalnya, di mana hanya ada tidak cukup ruang alamat mode pengguna untuk mengalokasikan array sebesar ini).

Dalam hal kecepatan, saya tidak berharap ada banyak hal di dalamnya. Ada kemungkinan bahwa ReadAllLines memiliki beberapa optimasi internal, tetapi di sisi lain itu mungkin harus mengalokasikan sejumlah besar memori. Saya menduga bahwa ReadAllLines mungkin lebih cepat untuk file kecil, tetapi secara signifikan lebih lambat untuk file besar; meskipun satu-satunya cara untuk mengetahuinya adalah dengan mengukurnya dengan Stopwatch atau kode profiler.

Greg Beech
sumber
2
Catatan kecil: karena String adalah tipe referensi array akan menjadi ukuran jumlah baris x ukuran pointer, tetapi Anda benar bahwa itu masih perlu menyimpan teks, setiap baris sebagai objek String tunggal.
Mike Dimmick
16
FYI: Untuk melakukan ini, ReadLines().Count()Anda harus menambahkan using System.Linqke dalam menyertakan Anda. Tampaknya tidak intuitif untuk memerlukan penambahan itu, jadi itu sebabnya saya menyebutkannya. Jika Anda menggunakan Visual Studio, kemungkinan penambahan ini dilakukan untuk Anda secara otomatis.
Nucleon
2
Saya telah menguji kedua pendekatan, "File.ReadLines.Count ()" v / s "reader.ReadLine ()" dan "reader.ReadLine ()" sedikit lebih cepat tetapi lebih cepat dengan margin yang sangat sedikit. "ReadAllLines" lebih longgar yang membutuhkan waktu dua kali lipat dan makan banyak memori). Ini karena "File.ReadLines.Count ()" dan "reader.ReadLine ()" adalah enumerator yang membaca file baris demi baris dan tidak memuat seluruh file dalam memori, membacanya dalam RAM lagi.
Yogee
9
Ya, tidak ada yang pernah bekerja dengan file 4GB +. Kita tentu tidak pernah berurusan dengan file log yang besar. Oh tunggu.
Greg Beech
2
Jika Anda ingin melihat bagian dalam File.ReadLines () buka di sini: System.IO.File.cs Ketika Anda menelusuri lebih dari kelebihannya, Anda akan dibawa ke sini: ReadLinesIterator.cs
Steve Kinyon
12

Termudah:

int lines = File.ReadAllLines("myfile").Length;
leppie
sumber
8

Ini akan menggunakan lebih sedikit memori, tetapi mungkin membutuhkan waktu lebih lama

int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
  count++;
}
reader.Close();
benPearce
sumber
5

Jika dengan mudah maksud Anda adalah baris kode yang mudah diuraikan tetapi per kesempatan tidak efisien?

string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();

Itu mungkin cara tercepat untuk mengetahui berapa banyak baris.

Anda juga bisa melakukannya (tergantung apakah Anda melakukan buffering)

#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}

Ada banyak cara lain tetapi salah satu di atas mungkin adalah apa yang akan Anda gunakan.

pengguna8456
sumber
3
Saya berpendapat bahwa metode ini sangat tidak efisien; karena, Anda membaca seluruh file ke dalam memori, dan ke dalam array string, tidak kurang. Anda tidak perlu menyalin buffer, saat menggunakan ReadLine. Lihat jawabannya dari @GregBeech. Maaf hujan di parade Anda.
Mike Christian
2

Anda dapat dengan cepat membacanya, dan menambah penghitung, cukup gunakan satu lingkaran untuk menambah, tidak melakukan apa-apa dengan teks.

Penjual Mitchel
sumber
3
Ini harus berupa komentar, bukan jawaban.
IamBatman
2

Membaca file dengan sendirinya membutuhkan waktu, pengumpulan sampah adalah masalah lain saat Anda membaca seluruh file hanya untuk menghitung karakter baris baru,

Pada titik tertentu, seseorang harus membaca karakter dalam file, terlepas dari apakah kerangka ini atau apakah itu kode Anda. Ini berarti Anda harus membuka file dan membacanya ke dalam memori jika file besar ini berpotensi menjadi masalah karena memori perlu dikumpulkan sampah.

Nima Ara membuat analisis bagus yang bisa Anda pertimbangkan

Berikut adalah solusi yang diusulkan, karena membaca 4 karakter sekaligus, menghitung karakter umpan baris dan menggunakan kembali alamat memori yang sama lagi untuk perbandingan karakter berikutnya.

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;
}

Di atas Anda dapat melihat bahwa suatu baris dibaca satu karakter pada suatu waktu juga oleh kerangka kerja yang mendasarinya karena Anda perlu membaca semua karakter untuk melihat umpan baris.

Jika Anda memprofilkannya sebagai selesai Nima Anda akan melihat bahwa ini adalah cara yang agak cepat dan efisien untuk melakukan ini.

Walter Vehoeven
sumber
1

hitung carriage return / line feeds. Saya percaya pada unicode mereka masing-masing masih 0x000D dan 0x000A. dengan begitu Anda bisa seefisien atau seefisien yang Anda inginkan, dan memutuskan apakah Anda harus berurusan dengan kedua karakter atau tidak

geocoin
sumber
1

Opsi yang layak, dan yang telah saya gunakan secara pribadi, adalah menambahkan header Anda sendiri ke baris pertama file. Saya melakukan ini untuk format model khusus untuk game saya. Pada dasarnya, saya memiliki alat yang mengoptimalkan file .obj saya, menyingkirkan omong kosong yang tidak saya butuhkan, mengubahnya menjadi tata letak yang lebih baik, dan kemudian menulis jumlah total garis, wajah, normals, simpul, dan tekstur UV pada baris pertama. Data itu kemudian digunakan oleh berbagai buffer array ketika model dimuat.

Ini juga berguna karena Anda hanya perlu mengulang-ulang file sekali untuk memuatnya, daripada sekali menghitung baris, dan lagi untuk membaca data ke buffer yang Anda buat.

Krythic
sumber
-1
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);
}         
Muhammad Usman -kai hiwatari
sumber
5
-1: ini akan menjadi PERLAHAN, mengkonsumsi banyak memori dan memberikan waktu yang sulit bagi GC!
ya23
-2

Anda dapat meluncurkan " wc .exe" yang dapat dieksekusi (dilengkapi dengan UnixUtils dan tidak perlu instalasi) berjalan sebagai proses eksternal. Ini mendukung metode penghitungan baris yang berbeda (seperti unix vs mac vs windows).

Sklivvz
sumber
1
Tidak mungkin ini cukup cepat untuk berguna. Overhead hanya dengan memanggil executable akan menjadi dua kali lebih banyak (pembesaran yang jelas jelas) sebagai satu loop tambahan.
Krythic