2011-09-01 36 views
6

Tôi cần đọc dòng thứ n của tệp văn bản (ví dụ: textfile.findline(0) sẽ tìm dòng đầu tiên của tệp văn bản được tải bằng ifstream textfile). Điều này có thể không? Tôi không cần phải đặt nội dung của tập tin trong một mảng/vector, tôi cần phải chỉ định một dòng cụ thể của tập tin văn bản cho một varible (cụ thể là một int).Lấy dòng thứ n của tệp văn bản trong C++

P.S. Tôi đang tìm giải pháp đơn giản nhất sẽ không yêu cầu tôi sử dụng bất kỳ thư viện bên ngoài lớn nào (ví dụ: Tăng cường) Cảm ơn bạn trước.

+0

Bạn có thể bọc này trong một vòng lặp và sử dụng một bộ đếm: http://stackoverflow.com/questions/3910326/c-read -file-line-by-line-then-split-each-line-using-the-delimiter/3910610 # 3910610 - Nhưng bạn có thể muốn lưu trữ toàn bộ nội dung tệp trong bộ nhớ để nếu bạn thực hiện nhiều lần tra cứu, nó sẽ là nhanh hơn rất nhiều. – jweyrich

Trả lời

6

Làm thế nào về điều này?

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

Chắc chắn là có thể. Có các ký tự (n-1) '\ n' trước dòng thứ n. Đọc các dòng cho đến khi bạn đến được dòng bạn đang tìm kiếm. Bạn có thể làm điều này một cách nhanh chóng mà không lưu trữ bất cứ điều gì ngoại trừ dòng hiện tại đang được xem xét.

3

Nếu bạn muốn đọc phần bắt đầu của dòng thứ n, bạn có thể dùng stdin :: ignore để bỏ qua các dòng n-1 đầu tiên, sau đó đọc từ dòng tiếp theo để gán cho biến.

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

Giải pháp của Armen là câu trả lời đúng, nhưng tôi nghĩ tôi sẽ đưa ra một giải pháp thay thế dựa trên ý tưởng bộ nhớ đệm của jweyrich. Đối với tốt hơn hoặc tồi tệ hơn, điều này đọc trong toàn bộ tệp lúc xây dựng, nhưng chỉ lưu các vị trí dòng mới (không lưu trữ toàn bộ tệp, vì vậy nó phát tốt với các tệp lớn.) Sau đó, bạn có thể chỉ cần gọi ReadNthLine và nó sẽ ngay lập tức nhảy đến dòng đó và đọc trong một dòng bạn muốn. Mặt khác, điều này chỉ tối ưu nếu bạn muốn chỉ nhận được một phần nhỏ của các dòng tại một thời điểm, và các số dòng không được biết tại thời gian biên dịch.

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

Thông minh! Đây là giải pháp tốt nhất IMO. – jweyrich

+0

Tôi đã tìm thấy vấn đề với việc nhảy đến một vị trí tùy ý bằng cách sử dụng seekg() khi tệp được mở ở chế độ văn bản và tệp được lưu ở định dạng tệp MS-Windows. Điều này là do việc sử dụng các đầu cuối dòng khác nhau. Giải pháp Mooning Duck sẽ hoạt động tốt nếu tệp được lưu ở định dạng tệp unix (trong vim do: set ff = unix). Bạn sẽ tìm thấy một cuộc thảo luận liên quan ở đây: "[vấn đề với seekg] (https://www.daniweb.com/programming/software-development/threads/110602/problem-with-seekg)". – npras

+0

@npras: Về mặt lý thuyết, điều này không nên có vấn đề đó bởi vì tôi không tự tính toán bù trừ, nhưng đang sử dụng 'tellg()', luôn khớp với 'seekg', ngay cả trên Windows. –

0

Đây là một hoạt động và ví dụ sử dụng gọn gàng 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; 
} 
Các vấn đề liên quan