web-dev-qa-db-ja.com

テキストファイルの特定の行を読み取るにはどうすればよいですか?

テキストファイルが与えられた場合、ファイル内の任意の行を読み取り、それ以外は何を読みますか?

たとえば、test.txtというファイルがあります。ファイルの行番号15を読み取るにはどうすればよいですか?

私が見たのは、テキストファイル全体を文字列配列として保存し、配列から使用する文字列の番号として行番号の値を使用するものです...しかし、いくつかの複雑さがあります:テキストファイルは非常に巨大で、私がコーディングしているアプリケーションが一流のシステムではないということです。速度は最優先事項ではありませんが、間違いなく大きな問題です。

[〜#〜] only [〜#〜]テキストファイルの特定の行を読み取り、結果を文字列として保存する方法はありますか?

ご回答ありがとうございます。ファイルはKINDA構造です。 25行の情報があり、[〜#〜] x [〜#〜]行の数字ですが、最初の25行の17行目は[〜#〜] x [〜#〜]

しかし、その後、1つの空白行があり、ファイル内の2番目のレコードとしてそれ自体を繰り返し、[〜#〜] x [〜#〜]は異なる値を持つことができます各レコード。

私がやりたいのは、最初の25行を独立した値として読み取り、保存してから、次の[〜#〜] x [〜#〜](通常約250)行を保存することです配列として。次に、SQLデータベースに保存し、[〜#〜] y [〜#〜]番目のレコード(番号に達するまでNEXTレコードで繰り返しますファイル内のレコードの3行目)

編集2:わかった、私はあなたのすべての応答の組み合わせに基づいた解決策を得たと思います。

最初の25行を読み取り、配列として保存します。配列の適切な内容をローカル変数にコピーしてから、最初の25行を削除します。次に、情報を使用して、次の[〜#〜] x [〜#〜]行(配列内の項目13の値)を配列として格納し、シリアル化します。それをデータベースに保存し、今読んだ行を削除します。

その後、後続の各レコードに対してプロセスを繰り返すことができます。

もちろん、これは私が行っている1つの仮定に依存していますが、正直なところ、それが真実かどうかはわかりません。 C#内からテキストファイルから最初のn行を削除し、最初のなしで再書き込みすることは可能ですか? n行?

52
ankushg

。NET 4.0編集

.NET 4.0以降では、ファイルの1行に直接アクセスできます。たとえば、行15にアクセスするには:

string line = File.ReadLines(FileName).Skip(14).Take(1).First();

これにより、必要な行のみが返されます


ファイルのi番目の行の位置を予測することはできません(できますか?)ので、前の行もすべて読む必要があります。行番号が小さい場合、これはReadAllLinesメソッドよりも効率的です。

string GetLine(string fileName, int line)
{
   using (var sr = new StreamReader(fileName)) {
       for (int i = 1; i < line; i++)
          sr.ReadLine();
       return sr.ReadLine();
   }
}
95
Mehrdad Afshari

各行が固定長の場合、その周囲のストリームを開き、ファイル内でシーク(1行あたりのバイト数)* nを実行し、そこから行を読み取ることができます。

using( Stream stream = File.Open(fileName, FileMode.Open) )
{
    stream.Seek(bytesPerLine * (myLine - 1), SeekOrigin.Begin);
    using( StreamReader reader = new StreamReader(stream) )
    {
        string line = reader.ReadLine();
    }
}

あるいは、必要な行が見つかるまでStreamReaderを使用して行を読み取ることもできます。その方法は遅くなりますが、それでもすべての単一行を読み取るよりも改善されます。

using( Stream stream = File.Open(fileName, FileMode.Open) )
{
    using( StreamReader reader = new StreamReader(fileStream) )
    {
        string line = null;
        for( int i = 0; i < myLineNumber; ++i )
        {
            line = reader.ReadLine();
        }
    }
}
12
Dave Downs

残念ながらありません。生レベルでは、ファイルは行番号ベースでは機能しません。代わりに、ポジション/オフセットベースで機能します。ルートファイルシステムには行の概念がありません。これは、より高いレベルのコンポーネントによって追加された概念です。

そのため、オペレーティングシステムに通知する方法はありません。何とか行でファイルを開いてください。代わりに、ファイルを開いて、指定した数が渡されるまで新しい行のカウントをスキップする必要があります。次に、次の新しい行に到達するまで、次のバイトセットを配列に格納します。

4
JaredPar

サイズが固定された行がない限り、目的の行に達するまですべての行を読む必要があります。ただし、各行を保存する必要はありませんが、必要な行でない場合は破棄してください。

編集:

前述のように、行の長さが予測可能な場合、ファイルを検索することもできます。つまり、行番号をファイル位置に変換するために何らかの決定的な関数を適用できます。

3
Ron Warholic

Mehrdadが言ったように、ファイルを読み込まずにn行目をシークすることはできません。ただし、ファイル全体をメモリに保存する必要はありません-不要なデータを破棄するだけです。

string line;
using (StreamReader sr = new StreamReader(path))
    for (int i = 0; i<15; i++)
    {
       line = sr.ReadLine();
       if (line==null) break; // there are less than 15 lines in the file
    }
2
VladV

毎回5行を読み、ifステートメントにステートメントを入れてください。

        String str1 = @"C:\Users\TEMP\Desktop\StaN.txt";   

        System.IO.StreamReader file = new System.IO.StreamReader(str1);

        line = file.ReadLine();

        Int32 ctn=0;

        try
        {

            while ((line = file.ReadLine()) != null)
            {

                    if (Counter == ctn)
                    {
                        MessageBox.Show("I am here");
                        ctn=ctn+5;
                        continue;
                    }
                    else
                    {
                        Counter++;
                        //MessageBox.Show(Counter.ToString());
                        MessageBox.Show(line.ToString());
                    } 
                }

            file.Close();
        }
        catch (Exception er)
        {

        }

行がすべて固定長である場合、ストリームのSeekメソッドを使用して、正しい開始位置に移動できます。

行が可変長の場合、オプションはより制限されます。

これが1回だけ使用してから破棄するファイルである場合は、そのファイルを読み取って記憶で作業することをお勧めします。

これが保持するファイルであり、書き込み以上のものを読み取る場合は、各行の開始位置を含むカスタムインデックスファイルを作成できます。次に、そのインデックスを使用してシーク位置を取得します。インデックスファイルを作成するプロセスは、リソースを大量に消費します。ファイルに新しい行を追加するたびに、インデックスを更新する必要があるため、メンテナンスは重要な問題になります。

1
RB Davidson

試し、テストしました。次のように簡単です。

string line = File.ReadLines(filePath).ElementAt(actualLineNumber - 1);

テキストファイルがある限り、これは機能するはずです。後で、読み取るデータに応じて、文字列を適宜キャストして使用できます。

0
Karan Randhawa

バリエーション。行番号が行数より大きい場合にエラーを生成します。

string GetLine(string fileName, int lineNum)
{
    using (StreamReader sr = new StreamReader(fileName))
    {
        string line;
        int count = 1;
        while ((line = sr.ReadLine()) != null)
        {
            if(count == lineNum)
            {
                return line;
            }
            count++;
        }
    }
    return "line number is bigger than number of lines";  
}
0
paparazzo

(ファイルに進んだ行数を数える必要があるため)ファイルのデータを読み取らずに、非対称ファイルでN行目を直接シークすることはできませんが、必要なメモリ量が最も少なく、おそらく最高のパフォーマンスを発揮するライン。

これは、すべてを配列に読み込むよりもメモリ効率が良くなります。ファイルの最後または行番号(どちらか早い方)に達するまでファイルに読み込むだけだからです。完全にはほど遠いですが、おそらくあなたのニーズに合うでしょう:

string line15 = ReadLine(@"C:\File.csv", 15);

public string ReadLine(string FilePath, int LineNumber){
    string result = "";
    try{
    if( File.Exists(FilePath) ){
        using (StreamReader _StreamReader = new StreamReader(FilePath)){
        for (int a = 0; a < LineNumber; a++) {
            result = _StreamReader.ReadLine();
        }
        }
    }
    }catch{}
    return result;
}
0
Dave

ファイルに異なる長さの行が含まれており、頻繁に行を読む必要があり、すぐに読む必要がある場合は、一度読み取ることでファイルのインデックスを作成し、各新しい行の位置を保存してから行を読む必要があるとき、インデックス内の行の位置を検索し、そこを検索してから行を読み取ります。

ファイルに新しい行を追加する場合、新しい行のインデックスを追加するだけで、すべてのインデックスを再作成する必要はありません。ただし、ファイルの行のどこかで既にインデックスを作成している場合は、インデックスを再作成する必要があります。

0
user175779

行ごとに読むことができるので、一度に全部を読む必要はありません(おそらくまったく)

int i=0
while(!stream.eof() && i!=lineNum)
    stream.readLine()
    i++
line = stream.readLine()
0
Samuel