テキストファイル内の行数を決定する


209

プログラムでテキストファイル内の行数を簡単に決定する方法はありますか?

回答:


396

大幅に遅れた編集:.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++;
    }
}

編集:効率性に関する質問への回答

2つ目がより効率的であると私が言った理由は、必ずしも速度ではなく、メモリ使用量に関するものでした。最初のものは、ファイルの内容全体を配列にロードします。つまり、少なくともファイルのサイズと同じ量のメモリを割り当てる必要があります。2つ目は一度に1行ずつループするだけなので、一度に複数行分のメモリを割り当てる必要はありません。これは小さなファイルではそれほど重要ではありませんが、大きなファイルでは問題になる可能性があります(たとえば、32ビットシステムで4GBファイルの行数を調べて、単に十分ではない場合)ユーザーモードのアドレス空間で、これほど大きなサイズの配列を割り当てます。

速度に関しては、そこにたくさんあるとは思いません。ReadAllLinesには内部最適化がいくつかある可能性がありますが、一方で、大量のメモリを割り当てる必要がある場合があります。ReadAllLinesは、小さいファイルの場合は速くなるかもしれませんが、大きいファイルの場合はかなり遅くなると思います。ただし、ストップウォッチまたはコードプロファイラーで測定するしか方法はありません。


2
小さなメモ:Stringは参照型なので、配列は行数のサイズxポインターのサイズになりますが、テキストを格納する必要があることは正しいです。各行は単一のStringオブジェクトとして格納されます。
マイクディミック

15
参考:行うには、インクルードにReadLines().Count()を追加する必要がありusing System.Linqます。その追加を要求することはかなり直感的ではないように思われたので、私はそれを言及する理由です。Visual Studioを使用している場合、この追加は自動的に行われる可能性があります。
Nucleon 2013年

2
私は両方のアプローチをテストしましたが、「File.ReadLines.Count()」と「reader.ReadLine()」および「reader.ReadLine()」の方がわずかに高速ですが、マージンがほとんどないため高速です。「ReadAllLines」は緩やかで、2倍の時間がかかり、大量のメモリを消費します)。これは、「File.ReadLines.Count()」と「reader.ReadLine()」がファイルを1行ずつ読み取り、メモリ内のファイル全体をロードせずにRAMで再度読み取る列挙子であるためです。
Yogee

9
ええ、誰も4GB以上のファイルで作業することはありません。それほど大きなログファイルを扱うことは決してありません。あ、ちょっと待って。
グレッグビーチ

2
あなたは(File.ReadLinesの内部を見たい場合は)ここに行く: System.IO.File.cs あなたがオーバーロードをドリルダウンすると、それはここに表示されます:ReadLinesIterator.cs
スティーブKinyon


8

これはより少ないメモリを使用しますが、おそらくより長くかかります

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

5

簡単に言うと、解読は簡単ですが、たまたま非効率的なコード行ですか?

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

他にも多くの方法がありますが、おそらく上記のいずれかを使用します。


3
この方法は非常に非効率的だと私は主張します。なぜなら、ファイル全体をメモリと文字列配列に読み込んでいるからです。ReadLineを使用する場合は、バッファをコピーする必要はありません。@GregBeechからの回答を参照してください。パレードで雨が降ってごめんなさい。
マイククリスチャン

2

あなたはそれを素早く読み込んでカウンターをインクリメントし、ループを使用してインクリメントし、テキストに対しては何もしません。


3
これはコメントではなく、回答である必要があります。
IamBatman 2017年

2

ファイルの読み込み自体には時間がかかりますが、改行文字を数えるためにファイル全体を読み取るため、結果のガベージコレクションは別の問題です。

ある時点で、これがフレームワークであるかコードであるかに関係なく、誰かがファイル内の文字を読み取る必要があります。つまり、メモリをガベージコレクションする必要があるため、ファイルが大きい場合は、ファイルを開いてメモリに読み込む必要があります。これは問題になる可能性があります。

ニマアラはあなたが考慮に入れるかもしれない素晴らしい分析をしました

一度に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;
}

上記では、ラインフィードを表示するためにすべての文字を読み取る必要があるため、基礎となるフレームワークによって行が一度に1文字ずつ読み取られることがわかります。

完了したベイニマとしてプロファイルすると、これがかなり高速で効率的な方法であることがわかります。


1

キャリッジリターン/ラインフィードをカウントします。私はそれらがまだそれぞれ0x000Dと0x000Aであるユニコードを信じています。そうすることで、あなたは好きなだけ効率的または非効率的になり、両方のキャラクターを扱う必要があるかどうかを決定します


1

実行可能なオプション、および私が個人的に使用したオプションは、ファイルの最初の行に独自のヘッダーを追加することです。私は自分のゲームのカスタムモデル形式に対してこれを行いました。基本的に、私は.objファイルを最適化し、不要ながらくたをなくし、それらをより適切なレイアウトに変換し、ライン、面、法線、頂点、およびテクスチャUVの総数を一番最初の行。そのデータは、モデルが読み込まれるときに、さまざまな配列バッファーで使用されます。

行を数えるために1回ではなく、ファイルをロードするためにファイルを1回ループするだけでよいので、これも役立ちます。また、作成したバッファーにデータを読み取るためにもう一度ループします。


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

4
-1:これは遅くなり、多くのメモリを消費し、GCにハードタイムを与えます!
ya23

-2

外部プロセスとして実行される「wc .exe」実行可能ファイル(UnixUtilsに付属し、インストールは不要)を起動できます。さまざまな行カウント方法をサポートしています(UNIX、Mac、Windowsなど)。


これが役に立つほど速くなる方法はありません。実行可能ファイルを呼び出すだけのオーバーヘッドは、単一のインクリメントループの2倍になります(明らかな誇張は明らかです)。
Krythic 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.