2011-09-01 14 views
6

テキストファイルのn番目の行を読み取る必要があります(たとえば、textfile.findline(0)は、テキストファイルの最初の行にifstream textfileが読み込まれています)。これは可能ですか? ファイルの内容を配列/ベクトルに入れる必要はありません。テキストファイルの特定の行をvarible(特にint)に割り当てる必要があります。C++でテキストファイルのn番目の行を取得する

P.S.私は大きな外部ライブラリ(Boostなど)を使用する必要のない最も簡単なソリューションを探しています ありがとうございます。

+0

あなたがループでこれをラップし、カウンタを使用することができます。http://stackoverflow.com/questions/3910326/c-read -file-line-by-line-then-split-each-line-the-delimiter/3910610#3910610 - しかし、ファイルの内容全体をメモリに保存して、複数の検索を実行すると、すばらしく速い。 – jweyrich

答えて

6

これはいかがですか?

std::string ReadNthLine(const std::string& filename, int N) 
{ 
    std::ifstream in(filename.c_str()); 

    std::string s; 
    //for performance 
    s.reserve(some_reasonable_max_line_length);  

    //skip N lines 
    for(int i = 0; i < N; ++i) 
     std::getline(in, s); 

    std::getline(in,s); 
    return s; 
} 
0

確かに可能です。 n番目の行の前に(n-1) '\ n'文字があります。あなたが探しているものに達するまで行を読む。考慮する現在の行以外のものを保存することなく、即座に実行することができます。

3

n番目の行の先頭を読みたい場合は、stdin :: ignoreを使用して最初のn-1行をスキップし、次の行から読み込んで変数に代入することができます。

template<typename T> 
void readNthLine(istream& in, int n, T& value) { 
    for (int i = 0; i < n-1; ++i) { 
    in.ignore(numeric_limits<streamsize>::max(), '\n'); 
    } 
    in >> value; 
} 
2

Armenの解答は正解ですが、私はjweyrichのキャッシュアイディアに基づいて代替案を捨てると思いました。より良いか悪いかにかかわらず、これは構築時にファイル全体を読み込みますが、改行位置だけを保存します(ファイル全体を格納しないので大量のファイルでうまくいきます)。次に、ReadNthLineを呼び出すだけですぐに呼び出すことができますその行にジャンプし、必要な1行を読み込みます。一方、これは、一度に行の一部を取得したいだけで、コンパイル時に行番号がわからない場合にのみ最適です。ここで

class TextFile { 
    std::ifstream file_stream; 
    std::vector<std::ifstream::streampos> linebegins; 
    TextFile& operator=(TextFile& b) = delete; 
public; 
    TextFile(std::string filename) 
    :file_stream(filename) 
    { 
     //this chunk stolen from Armen's, 
     std::string s; 
     //for performance 
     s.reserve(some_reasonable_max_line_length); 
     while(file_stream) { 
      linebegins.push_back(file_stream.tellg()); 
      std::getline(file_stream, s); 
     } 
    } 
    TextFile(TextFile&& b) 
    :file_stream(std::move(b.file_stream)), 
    :linebegins(std::move(b.linebegins)) 
    {} 
    TextFile& operator=(TextFile&& b) 
    { 
     file_stream = std::move(b.file_stream); 
     linebegins = std::move(b.linebegins); 
    } 
    std::string ReadNthLine(int N) { 
     if (N >= linebegins.size()-1) 
      throw std::runtime_error("File doesn't have that many lines!"); 
     std::string s; 
     // clear EOF and error flags 
     file_stream.clear(); 
     file_stream.seekg(linebegins[N]); 
     std::getline(file_stream, s); 
     return s; 
    } 
}; 
+0

賢い!これはIMOの最適解です。 – jweyrich

+0

ファイルがテキストモードで開かれ、MS-Windowsファイル形式で保存されているときに、seekg()を使用して任意の位置にジャンプする際に問題が見つかりました。これは、異なる終端のターミネータを使用しているためです。 Mooning Duckのソリューションは、ファイルがunixファイル形式で保存されていれば正常に動作します(vim do:set ff = unix)。ここで関連する議論があります: "[seekg with problem](https://www.daniweb.com/programming/software-development/threads/110602/problem-with-seekg)" – npras

+0

@npras:理論的には、自分自身でオフセットを計算するのではなく、 'tellg()'を使用しているので、Windowsでは 'seekg'と常に一致するはずです。 –

0

std::getline()を使用して作業し、きちんとした例である:

#include <iostream> 
#include <fstream> 
#include <string> 

const int LENGTH = 50; 
const int LINE = 4; 

int main() { 
std::ifstream f("FILE.txt"); 
std::string s; 

for (int i = 1; i <= LINE; i++) 
     std::getline(f, s); 

std::cout << s; 
return 0; 
} 
関連する問題