2017-12-30 158 views
5

trường hợp của tôi là như sau:C++ hoạt động std :: stringstream tối ưu hóa

  1. Tôi có một tập tin nhị phân Tôi đang đọc từ với std :: fstream đọc hoạt động như (char *)
  2. Mục tiêu của tôi là để tận dụng mọi byte từ tập tin, hex định dạng, và sau đó thêm nó vào một chuỗi biến
  3. chuỗi biến nên giữ toàn bộ nội dung của tập tin định dạng theo mục 2.

Ví dụ, giả sử Tôi có thùng sau nội dung tập tin ary:

D0 46 98 57 A0 24 99 56 A3

Con đường tôi đang định dạng mỗi byte là như sau:

stringstream fin;; 

for (size_t i = 0; i < fileb_size; ++i) 
{ 
fin << hex << setfill('0') << setw(2) << static_cast<uint16_t>(fileb[i]); 
} 

// this would yield the output "D0469857A0249956A3" 

return fin.str(); 

Trên phương pháp công trình như mong đợi, tuy nhiên, nó là cực kỳ chậm cho các tệp lớn, mà tôi hiểu; stringstream có nghĩa là cho định dạng đầu vào!

Câu hỏi của tôi là, có cách nào để tối ưu hóa mã như vậy hoặc cách tiếp cận mà tôi đang tập hợp tất cả cùng nhau không? Hạn chế duy nhất của tôi là đầu ra phải ở định dạng chuỗi như được hiển thị ở trên.

Cảm ơn bạn.

+3

iostream không được thiết kế để có hiệu quả. Đối với các trường hợp sử dụng cụ thể, bạn không thể đánh bại tệp I/O của tệp triển khai gốc cụ thể. Hoặc, trong trường hợp xấu hơn, hãy lấy 'FILE *' của C và cuộn mã chuyển đổi hex được tối ưu hóa thủ công của riêng bạn. Không thể đánh bại điều đó cho hiệu quả. Nó không phải là khoa học tên lửa. Ít nhất là trong những ngày tôi đã học C và C++, đây là một bài tập về nhà điển hình: đọc thập lục phân và chuyển đổi nó. –

+1

“Cực kỳ chậm” so với những gì? –

+1

bạn có thử [kích thước đặt trước] (https://stackoverflow.com/q/1941064/995714) cho chuỗi đầu ra không? Bạn đã biết kích thước của đầu vào vì vậy thật dễ dàng để tính toán kích thước của đầu ra và tránh tái phân bổ mảng nhiều lần –

Trả lời

4

std::stringstream khá chậm. Nó sẽ không preallocate và nó luôn luôn liên quan đến việc sao chép chuỗi, ít nhất một lần để lấy nó. Ngoài ra việc chuyển đổi sang hex có thể được mã hóa bằng tay để nhanh hơn.

Tôi nghĩ rằng một cái gì đó như thế này có thể là performant hơn:

// Quick and dirty 
char to_hex(unsigned char nibble) 
{ 
    assert(nibble < 16); 

    if(nibble < 10) 
     return char('0' + nibble); 

    return char('A' + nibble - 10); 
} 

std::string to_hex(std::string const& filename) 
{ 
    // open file at end 
    std::ifstream ifs(filename, std::ios::binary|std::ios::ate); 

    // calculate file size and move to beginning 
    auto end = ifs.tellg(); 
    ifs.seekg(0, std::ios::beg); 
    auto beg = ifs.tellg(); 

    // preallocate the string 
    std::string out; 
    out.reserve((end - beg) * 2); 

    char buf[2048]; // larger = faster (within limits) 

    while(ifs.read(buf, sizeof(buf)) || ifs.gcount()) 
    { 
     for(std::streamsize i = 0; i < ifs.gcount(); ++i) 
     { 
      out += to_hex(static_cast<unsigned char>(buf[i]) >> 4); // top nibble 
      out += to_hex(static_cast<unsigned char>(buf[i]) & 0b1111); // bottom nibble 
     } 
    } 

    return out; 
} 

Nó gắn với một chuỗi trước được phân bổ để giảm thiểu việc sao chép và tránh tái phân bổ.

+0

Cảm ơn @Galik vì giải pháp chi tiết. Thật là một cải tiến đáng kể về hiệu suất với phương pháp này. – Xigma