2010-11-03 31 views
6

Đây là những gì tôi đã cố gắng cho đến nay nhưng không thành công:Đọc một dòng tập tin cục bộ vào một chuỗi sử dụng vòng lặp

std::string ReadPartial(std::ifstream& _file, int _size) 
{ 
    std::istreambuf_iterator<char> first(_file); 
    std::istreambuf_iterator<char> last(_file); 
    std::advance(last, _size); 
    return std::string(first, last); 
} 

tôi biết làm thế nào để đọc toàn bộ tập tin.

std::string Read(std::ifstream& _file) 
{ 
    std::istreambuf_iterator<char> first(_file); 
    std::istreambuf_iterator<char> last(); 
    return std::string(first, last); 
} 

Nhưng đây không phải là điều tôi muốn làm. Tôi nhận được một chuỗi rỗng. Nếu tôi nhìn vào đầu tiên và cuối cùng trong một trình gỡ lỗi họ trỏ đến cùng một điều ngay cả sau khi std :: trước.

+0

kết quả thực tế là gì mà bạn đang nhìn thấy? Ngoài ra, vui lòng đăng * mã * thực mà bạn đã sử dụng. Đoạn mã trên thậm chí không biên dịch (EDIT: trước khi Charles sửa nó…). –

+0

Ok đã khắc phục lỗi biên dịch. Xin lỗi đó là sự cố của tôi. Bị đánh ra khỏi đầu tôi. –

+0

Không cần sử dụng HTML, công cụ đánh dấu hoạt động tuyệt vời. –

Trả lời

5

Có một số lý do cụ thể mà bạn muốn sử dụng trình vòng lặp không? Bạn chỉ có thể đọc các byte trong một đi:

std::string s(_size, '\0'); 
_file.read(&s[0], _size); 

Nếu bạn thực sự muốn đọc sử dụng vòng lặp, bạn có thể làm điều này:

std::string ReadPartial(std::ifstream& _file, int _size) 
{ 
    std::istreambuf_iterator<char> first(_file); 
    std::istreambuf_iterator<char> last; 
    std::string s; 
    s.reserve(_size); 
    while (_size-- && first != last) s += *first++; 
    return s; 
} 
+0

Không cần thiết. Nhưng muốn biết nếu có thể. Cảm ơn câu trả lời –

+2

'tệp.đọc (& s [0], kích thước)' là không di động và không an toàn. basic_string không có bảo đảm lưu trữ liền kề của vectơ. –

+0

@Steve: Đối với những gì thực hiện là đúng? –

5
std::istreambuf_iterator<char> first(_file); 
std::istreambuf_iterator<char> last(_file); 
std::advance(last, _size); 

istreambuf_iterators là vòng lặp Input. Sau khi bạn thăng hạng lần cuối, trình biến đổi khác cũng được sửa đổi. Bạn đang xử lý chúng như các Bộ lặp Iterator, có thuộc tính mà bạn có thể sao chép một trình lặp, trước nó, sau đó nhận được một chuỗi giống hệt nhau bằng cách tiến hành sao chép.

Đối với trường hợp tổng quát:

template<class InIter, class Size, class OutIter> 
void copy_n(InIter begin, InIter end, Size n, OutIter dest) { 
    for (; begin != end && n > 0; ++begin, --n) { 
    *dest++ = *begin; 
    } 
} 

//... 
std::string ReadPartial(std::istream& file, int size) { 
    std::string result; 
    copy_n(istreambuf_iterator<char>(file), istreambuf_iterator<char>(), 
     size, back_inserter(result)); 
    return result; 
} 

Tuy nhiên, trong trường hợp này, bạn sẽ được tốt hơn off thay đổi kích thước của chuỗi, sử dụng istream :: đọc trực tiếp vào & kết quả [0], và cuối cùng là kiểm tra xem bạn đọc số lượng ký tự mong muốn.

+0

Nhưng có cách nào để làm một cái gì đó tương tự bằng cách sử dụng vòng lặp, hoặc cho rằng vấn đề để có được một iterator chuyển tiếp từ một ifstream? –

+0

@Allen_SM: Chắc chắn bạn có thể sử dụng vòng lặp, tôi đã bao gồm copy_n. Bạn có thể viết một loại iterator cho istreams mà là một Iterator Forward (vì istreams có một phương thức seekg), nhưng không cần thiết. –

1

Không có thuật toán tiêu chuẩn có thể giúp bạn ở đây, nhưng bạn có thể sử dụng một:

template< class InputIterator, class OutputIterator> 
OutputIterator copy_n(InputIterator from, 
         size_t n, 
         OutputIterator to) 
{ 
    while (n) 
    { 
     *to = *from; 
     ++from; 
     ++to; 
     --n; 
    } 
    return to; 
} 

Điều này có thể được sử dụng với ReadPartial như thế này:

std::string ReadPartial(std::ifstream& _file, int _size) 
{ 
    std::istreambuf_iterator<char> first(_file); 
    std::string result; 

    copy_n(first, _size, std::back_inserter(result)); 
    return result; 
} 
Các vấn đề liên quan