2010-01-17 17 views
27

tôi không thể tìm thấy bất cứ điều gì làm sẵn, vì vậy tôi đã đưa ra:Cách đơn giản để tạo bộ nhớ C++ từ (char *, size_t), mà không sao chép dữ liệu?

class membuf : public basic_streambuf<char> 
{ 
public: 
    membuf(char* p, size_t n) { 
    setg(p, p, p + n); 
    setp(p, p + n); 
    } 
} 

Cách sử dụng:

char *mybuffer; 
size_t length; 
// ... allocate "mybuffer", put data into it, set "length" 

membuf mb(mybuffer, length); 
istream reader(&mb); 
// use "reader" 

tôi biết stringstream, nhưng nó dường như không có khả năng làm việc với dữ liệu nhị phân có độ dài đã cho.

Tôi có phát minh ra bánh xe của riêng mình ở đây không?

EDIT

  • phải không sao chép các dữ liệu đầu vào, chỉ cần tạo cái gì đó sẽ lặp qua các dữ liệu.
  • Nó phải di động - ít nhất nó phải hoạt động cả dưới gcc và MSVC.
+0

Phiên bản MSVC nào? > 6, tôi hy vọng. ;) –

+0

MSVC 9.0 aka 2008 –

+1

Tôi nghĩ rằng giải pháp của bạn là tốt. :) http://stackoverflow.com/questions/1448467/initializing-ac-stdistringstream-from-an-in-memory-buffer/1449527#1449527 –

Trả lời

26

Tôi giả định rằng dữ liệu đầu vào của bạn là nhị phân (không phải văn bản) và bạn muốn trích xuất khối dữ liệu nhị phân từ nó. Tất cả mà không cần tạo bản sao dữ liệu đầu vào của bạn.

Bạn có thể kết hợp boost::iostreams::basic_array_sourceboost::iostreams::stream_buffer (từ Boost.Iostreams) với boost::archive::binary_iarchive (từ Boost.Serialization) để có thể sử dụng khai thác >> khai thác thuận tiện để đọc khối dữ liệu nhị phân.

#include <stdint.h> 
#include <iostream> 
#include <boost/iostreams/device/array.hpp> 
#include <boost/iostreams/stream.hpp> 
#include <boost/archive/binary_iarchive.hpp> 

int main() 
{ 
    uint16_t data[] = {1234, 5678}; 
    char* dataPtr = (char*)&data; 

    typedef boost::iostreams::basic_array_source<char> Device; 
    boost::iostreams::stream_buffer<Device> buffer(dataPtr, sizeof(data)); 
    boost::archive::binary_iarchive archive(buffer, boost::archive::no_header); 

    uint16_t word1, word2; 
    archive >> word1 >> word2; 
    std::cout << word1 << "," << word2 << std::endl; 
    return 0; 
} 

Với GCC 4.4.1 trên AMD64, nó kết quả đầu ra:

1234,5678

Boost.Serialization là rất mạnh mẽ và biết làm thế nào để serialize tất cả các loại cơ bản, chuỗi, và thậm chí cả các container STL. Bạn có thể dễ dàng làm cho các loại của bạn serializable. Xem tài liệu. Ẩn ở đâu đó trong các nguồn Boost.Serialization là một ví dụ về một kho lưu trữ nhị phân di động biết cách thực hiện trao đổi thích hợp cho tính cuối cùng của máy. Điều này có thể hữu ích cho bạn.

Nếu bạn không cần fanciness của Boost.Serialization và rất vui khi được đọc dữ liệu nhị phân trong một fread() - loại thời trang, bạn có thể sử dụng basic_array_source theo một cách đơn giản hơn:

#include <stdint.h> 
#include <iostream> 
#include <boost/iostreams/device/array.hpp> 
#include <boost/iostreams/stream.hpp> 

int main() 
{ 
    uint16_t data[] = {1234, 5678}; 
    char* dataPtr = (char*)&data; 

    typedef boost::iostreams::basic_array_source<char> Device; 
    boost::iostreams::stream<Device> stream(dataPtr, sizeof(data)); 

    uint16_t word1, word2; 
    stream.read((char*)&word1, sizeof(word1)); 
    stream.read((char*)&word2, sizeof(word2)); 
    std::cout << word1 << "," << word2 << std::endl; 

    return 0; 
} 

tôi nhận được cùng một đầu ra với chương trình này.

+0

Ah, cảm ơn bạn. Nó trông khá phổ biến. –

+0

Công cụ tuyệt vời, Emile. Có lẽ nó không phải là "đơn giản", nhưng nó chắc chắn hơn. Cảm ơn bạn! –

+1

Lý do chỉ các đối tượng fstream có khái niệm nhị phân là văn bản và chế độ nhị phân là chính xác như nhau; ngoài cách họ xử lý hết dòng. Về mặt hành động đối với các hoạt động của luồng, chúng không khác nhau. Cách bạn đang sử dụng các toán tử luồng để thử và đọc các số nguyên từ một luồng char không phải là cách các toán tử luồng được cho là hoạt động. –

5

Tôi không chắc chắn những gì bạn cần, nhưng điều này có làm những gì bạn muốn không?

char *mybuffer; 
size_t length; 
// allocate, fill, set length, as before 

std::string data(mybuffer, length); 
std::istringstream mb(data); 
//use mb 
+1

Không, điều này sẽ cắt ngắn chuỗi thành lần xuất hiện đầu tiên là 0x00 byte trong đệm. Tôi đặc biệt cần tạo một luồng có độ dài cố định để tôi có thể đọc dữ liệu nhị phân, khi tôi có dữ liệu này ở một nơi đã biết trong bộ nhớ. –

+2

Tôi không thấy lý do tại sao nó sẽ xử lý NUL byte đặc biệt. Thông báo chiều dài được chuyển đến std :: string constructor riêng. – Tronic

+2

Bạn có chắc chắn không? String constructor nhận (char *, size_t) không coi char * param là một chuỗi kiểu c (null-terminated). Nó sử dụng độ dài bạn cho nó. – crmoore

4

Bộ đệm dòng tiêu chuẩn có chức năng này.
Tạo luồng. Được bộ đệm của nó sau đó hơn-đi xe nó.

#include <sstream> 
#include <iostream> 
#include <algorithm> 
#include <iterator> 

int main() 
{ 
    // Your imaginary buffer 
    char buffer[] = "A large buffer we don't want to copy but use in a stream"; 

    // An ordinary stream. 
    std::stringstream str; 

    // Get the streams buffer object. Reset the actual buffer being used. 
    str.rdbuf()->pubsetbuf(buffer,sizeof(buffer)); 

    std::copy(std::istreambuf_iterator<char>(str), 
       std::istreambuf_iterator<char>(), 
       std::ostream_iterator<char>(std::cout) 
      ); 
} 
+0

Hmmm ... Tôi đặt điều này để kiểm tra, và nó không có vẻ làm việc theo MSVC và libs của nó. Nó hoạt động trên gcc, mặc dù. –

+0

Tại sao. Điều gì thất bại? –

+0

Dường như basic_streambuf của MSVC :: pubsetbuf không làm gì cả. http://stackoverflow.com/questions/1494182/setting-the-internal-buffer-used-by-a-standard-stream-pubsetbuf –

2

Người hỏi muốn nội dung nào đó không sao chép dữ liệu và giải pháp của anh ấy hoạt động tốt. Đóng góp của tôi là làm sạch nó một chút, vì vậy bạn chỉ có thể tạo một đối tượng duy nhất là luồng đầu vào cho dữ liệu trong bộ nhớ. Tôi đã thử nghiệm này và nó hoạt động.

class MemoryInputStream: public std::istream 
    { 
    public: 
    MemoryInputStream(const uint8_t* aData,size_t aLength): 
     std::istream(&m_buffer), 
     m_buffer(aData,aLength) 
     { 
     rdbuf(&m_buffer); // reset the buffer after it has been properly constructed 
     } 

    private: 
    class MemoryBuffer: public std::basic_streambuf<char> 
     { 
     public: 
     MemoryBuffer(const uint8_t* aData,size_t aLength) 
      { 
      setg((char*)aData,(char*)aData,(char*)aData + aLength); 
      } 
     }; 

    MemoryBuffer m_buffer; 
    }; 
+0

Chết tiệt - nó không hoạt động vì xem, v.v., sẽ không hoạt động theo mặc định - bạn phải ghi đè các hàm streambuf khác nhau. –

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