2011-06-28 34 views
8

Tôi muốn đọc một tệp vào một chuỗi. Tôi đang tìm những cách khác nhau để làm thế nào để làm điều đó một cách hiệu quả.Cách sử dụng istream với các chuỗi

Sử dụng một kích thước cố định * char buffer

Tôi đã nhận được một answer từ Tony những gì tạo ra một 16 kb đệm và đọc vào bộ đệm đó và gắn thêm bộ đệm cho đến khi không có gì hơn để đọc được. Tôi hiểu nó hoạt động như thế nào và tôi thấy nó rất nhanh. Những gì tôi không hiểu là trong các ý kiến ​​của câu trả lời đó người ta nói rằng cách này sao chép tất cả mọi thứ hai lần. Nhưng khi tôi hiểu nó, nó chỉ xảy ra trong bộ nhớ, không phải từ đĩa, vì vậy nó gần như không đáng kể. Nó là một vấn đề mà nó sao chép từ bộ đệm vào chuỗi trong bộ nhớ?

Sử dụng istreambuf_iterator

Các other answer tôi đã nhận được sử dụng istreambuf_iterator. Mã trông đẹp và tối thiểu, nhưng nó rất chậm. Tôi không biết tại sao nó lại xảy ra. Tại sao những người lặp lại chậm như vậy?

Sử dụng memcpy()

Đối this question tôi đã nhận được ý kiến ​​mà tôi nên sử dụng memcpy() vì nó là phương pháp tự nhiên nhanh nhất. Nhưng làm thế nào tôi có thể sử dụng memcpy() với một chuỗi và một đối tượng ifstream? Không phải ifstream phải làm việc với chức năng đọc riêng của nó? Tại sao sử dụng memcpy() làm hỏng tính di động? Tôi đang tìm một giải pháp tương thích với VS2010 cũng như GCC. Tại sao memcpy() không làm việc với chúng?

+ Bất kỳ cách hiệu quả nào khác có thể?

Bạn đề xuất gì, tôi sử dụng vỏ gì cho các tệp nhị phân nhỏ < 10 MB?

(Tôi không muốn chia câu hỏi này trong phần, như tôi quan tâm nhiều hơn trong việc so sánh giữa các cách khác nhau như thế nào tôi có thể đọc một ifstream thành một chuỗi)

+0

memcpy() chú thích dùng để chỉ đọc bằng cách sử dụng tệp ánh xạ bộ nhớ, không đọc bằng istream. Tệp ánh xạ bộ nhớ không thể di chuyển được vì nó phụ thuộc vào API OS. – Dikei

+0

Khi bạn đo lường hiệu suất, bạn có đang thực hiện nó trong chế độ phát hành hoặc gỡ lỗi không? Bạn có bật tối ưu hóa không? Bạn đã tắt kiểm tra vòng lặp? Theo mặc định, studio trực quan có kiểm tra vòng lặp tiêu chuẩn bổ sung có thể làm giảm hiệu suất. – luke

+0

có thể trùng lặp của [cách phân bổ bộ nhớ trước cho một đối tượng chuỗi std ::] (http://stackoverflow.com/questions/3303527/how-to-pre-allocate-memory-for-a-stdstring-object/ 3304059 # 3304059)? Có lẽ bản sao chính xác nhất mà tôi từng thấy. Toàn bộ câu đầu tiên hầu như giống hệt nhau (khác biệt duy nhất là "Tôi cần ..." và "Tôi muốn ...") –

Trả lời

7

nó chỉ xảy ra trong bộ nhớ, không phải từ đĩa, vì vậy nó gần như là unnoticable

Đó là thực sự chính xác. Tuy nhiên, một giải pháp không làm điều đó có thể nhanh hơn.

Tại sao các trình vòng lặp lại quá chậm?

Mã này là chậm không phải vì các vòng lặp nhưng vì chuỗi không biết bao nhiêu bộ nhớ để phân bổ: các istreambuf_iterator s chỉ có thể đi qua một lần vì vậy các chuỗi được về cơ bản buộc phải thực hiện concatenations lặp lại với kết quả bộ nhớ reallocations, rất chậm.

yêu thích one-liner của tôi, từ another answer đang trình chiếu trực tiếp từ bộ đệm cơ bản:

string str(static_cast<stringstream const&>(stringstream() << in.rdbuf()).str()); 

Trên nền tảng gần đây điều này sẽ thực sự trước cấp phát bộ đệm. Tuy nhiên nó vẫn sẽ dẫn đến một bản sao dự phòng (từ stringstream đến chuỗi cuối cùng).

+1

Tôi đã chỉ là thời gian giải pháp khác nhau, và của bạn là khoảng 8 lần nhanh hơn tất cả những người dựa trên iterator. Rất tốt. –

3

Cách chung nhất sẽ là có lẽ là phản ứng bằng cách sử dụng istreambuf_iterator:

std::string s((std::istreambuf_iterator<char>(source)), 
       (std::istreambuf_iterator<char>())); 

Mặc dù hiệu suất chính xác là rất phụ thuộc vào việc thực hiện, đó là chắc chắn rằng đây là giải pháp nhanh nhất.

Một thay thế thú vị sẽ là:

std::istringstream tmp; 
tmp << source.rdbuf(); 
std::string s(tmp.str()); 

Điều này có thể rất nhanh chóng, nếu việc thực hiện có làm một công việc tốt trên các operator<< bạn đang sử dụng, và trong cách nó phát triển chuỗi trong vòng số istringstream. Một số triển khai trước đó (và có thể sone hơn những cái gần đây cũng) là rất xấu lúc này, tuy nhiên.

Nói chung, hiệu suất sử dụng std::string sẽ phụ thuộc vào cách thực hiện hiệu quả việc phát triển chuỗi; việc thực hiện không thể xác định mức độ lớn để thực hiện ban đầu.Bạn có thể muốn so sánh các thuật toán đầu tiên sử dụng cùng mã với std::vector<char> thay vì std::string, hoặc nếu bạn có thể làm cho một ước lượng tốt về kích thước tối đa , sử dụng reserve, hoặc một cái gì đó như:

std::string s(expectedSize, '\0'); 
std::copy(std::istreambuf_iterator<char>(source), 
      std::istreambuf_iterator<char>(), 
      s.begin()); 

memcpy không thể đọc từ một tệp và với trình biên dịch tốt, sẽ không được nhanh bằng cách sử dụng std::copy (với cùng loại dữ liệu).

Tôi có xu hướng sử dụng giải pháp thứ hai, ở trên, với << trên rdbuf(), nhưng đó là một phần vì lý do lịch sử; Tôi đã quen với việc sử dụng làm điều này (sử dụng istrstream) trước khi STL được thêm vào thư viện chuẩn . Đối với vấn đề đó, bạn có thể muốn thử nghiệm với istrstream và bộ đệm được phân bổ trước (giả sử bạn có thể tìm thấy kích thước thích hợp cho bộ đệm ).

+0

Nếu luồng nguồn có thể tìm kiếm được, bạn có thể nhận được kích thước của nó bằng cách thực hiện 'nguồn. seekg (0, tiêu chuẩn :: ios_base :: end); std :: streampos pos = source.tellg(); source.seekg (0, std :: ios_base :: beg); '. Sau đó, nếu 'nguồn' vẫn là Ok và' pos! = - 1', 'pos' sẽ là, ví dụ: kích thước của tệp. Tôi đã sử dụng điều này trong quá khứ. – sbi

+0

@sbi Điều đó sẽ hoạt động trên hầu hết các triển khai Unix, nhưng không hoạt động trên Windows, ít nhất là nếu tệp được mở ở chế độ văn bản. Và nó không được đảm bảo để thậm chí biên dịch. –

+0

@James: Bạn có thể xây dựng được không? Tôi biết tôi đã sử dụng nó trong một ứng dụng đa nền tảng, và tôi nghĩ nó hoạt động trên Win32, OSX, BSD, Linux, Solaris và một số ứng dụng khác. – sbi

Các vấn đề liên quan