2012-09-25 26 views
6

Tôi gặp sự cố khi lưu trữ dữ liệu Protobuf vào đĩa. Ứng dụng tôi đã sử dụng Protocol Buffer để chuyển dữ liệu qua một ổ cắm (hoạt động tốt), nhưng khi tôi cố gắng lưu trữ dữ liệu vào đĩa thì nó không thành công. Thực ra, lưu các báo cáo dữ liệu không có vấn đề gì, nhưng tôi dường như không thể tải lại chúng một cách chính xác. Bất kỳ mẹo nào cũng sẽ được đánh giá cao.Bộ đệm giao thức; lưu dữ liệu vào đĩa & tải lại sự cố

void writeToDisk(DataList & dList) 
{ 
    // open streams 
    int fd = open("serializedMessage.pb", O_WRONLY | O_CREAT); 
    google::protobuf::io::ZeroCopyOutputStream* fileOutput = new google::protobuf::io::FileOutputStream(fd); 
    google::protobuf::io::CodedOutputStream* codedOutput = new google::protobuf::io::CodedOutputStream(fileOutput); 

    // save data 
    codedOutput->WriteLittleEndian32(PROTOBUF_MESSAGE_ID_NUMBER); // store with message id 
    codedOutput->WriteLittleEndian32(dList.ByteSize()); // the size of the data i will serialize 
    dList.SerializeToCodedStream(codedOutput); // serialize the data 

    // close streams 
    delete codedOutput; 
    delete fileOutput; 

    close(fd); 
} 

Tôi đã xác minh dữ liệu bên trong hàm này, dList chứa dữ liệu tôi mong đợi. Các luồng báo cáo rằng không có lỗi nào xảy ra và một lượng byte hợp lý được ghi vào đĩa. (cũng là tập tin có kích thước hợp lý) Nhưng khi tôi cố gắng đọc lại dữ liệu, nó không hoạt động. Hơn nữa, điều thực sự lạ lùng, là nếu tôi nối thêm nhiều dữ liệu vào tập tin này, tôi có thể đọc các tin nhắn đầu tiên (nhưng không đọc được tin nhắn cuối cùng).

void readDataFromFile() 
{ 
    // open streams 
    int fd = open("serializedMessage.pb", O_RDONLY); 
    google::protobuf::io::ZeroCopyInputStream* fileinput = new google::protobuf::io::FileInputStream(fd); 
    google::protobuf::io::CodedInputStream* codedinput = new google::protobuf::io::CodedInputStream(fileinput); 

    // read back 
    uint32_t sizeToRead = 0, magicNumber = 0; 
    string parsedStr = ""; 

    codedinput->ReadLittleEndian32(&magicNumber); // the message id-number i expect 
    codedinput->ReadLittleEndian32(&sizeToRead); // the reported data size, also what i expect 
    codedinput->ReadString(&parsedstr, sizeToRead)) // the size() of 'parsedstr' is much less than it should (sizeToRead) 

    DataList dl = DataList(); 

    if (dl.ParseFromString(parsedstr)) // fails 
    { 
     // work with data if all okay 
    } 

    // close streams 
    delete codedinput; 
    delete fileinput; 
    close(fd); 
} 

Rõ ràng là tôi đã bỏ qua một số mã ở đây để đơn giản hóa mọi thứ. Là một lưu ý phụ tôi cũng đã cố gắng sắp xếp lại thông báo tới một chuỗi & lưu chuỗi đó thông qua CodedOutputStream. Điều này không hoạt động. Tôi đã xác minh các nội dung của chuỗi đó mặc dù, vì vậy tôi đoán thủ phạm phải là các chức năng dòng.

Đây là môi trường cửa sổ, C++ với bộ đệm giao thức và Qt.

Cảm ơn bạn đã dành thời gian!

+0

Tại sao địa ngục bạn sử dụng 'mới' và gọi phá hủy rõ ràng? Điều đó làm cho không có ý nghĩa gì. –

+0

Tôi đã chỉnh sửa để khắc phục vấn đề này. Tôi không biết tại sao điều đó có vẻ như là một ý tưởng hay vào thời điểm đó. Tốt, nhưng không đủ để khắc phục vấn đề của tôi. – almagest

+0

Bạn thực sự chỉ cố định một nửa vấn đề: sử dụng con trỏ và 'mới' ở đây vẫn không có ý nghĩa. Nhưng có, điều đó có thể không liên quan đến vấn đề của bạn. –

Trả lời

4

Tôi đã giải quyết vấn đề này bằng cách chuyển từ bộ mô tả tệp sang fstream và FileCopyStream thành OstreamOutputStream.

Mặc dù tôi đã xem các ví dụ bằng cách sử dụng trước đây, nó không hoạt động đối với tôi.

Tôi đã tìm thấy một ví dụ mã đẹp được ẩn trong tiêu đề google coded_stream. link #1

Ngoài ra, vì tôi cần phải tuần tự hóa nhiều thư đến cùng một tệp bằng cách sử dụng bộ đệm giao thức, liên kết này đã được khai sáng. link #2

Vì một số lý do, tệp đầu ra không 'hoàn thành' cho đến khi tôi thực sự desctruct các đối tượng dòng.

-1

cố gắng sử dụng

codedinput->readRawBytes INSEAD của ReadString

dl.ParseFromArray thay vì ParseFromString

Không phải rất quen thuộc với bộ đệm giao thức nhưng ReadString chỉ có thể đọc một lĩnh vực loại strine.

+0

Ý tưởng hay , nhưng nó dẫn đến hành vi tương tự như trước đây. – almagest

2

Sự thất bại đọc là vì các tập tin không được mở cho việc đọc với O_BINARY - thay đổi tập tin mở này và nó hoạt động:

int fd = open("serializedMessage.pb", O_RDONLY | O_BINARY);

Nguyên nhân sâu xa là giống như ở đây: "read() only reads a few bytes from file". Bạn rất có khả năng làm theo một ví dụ trong tài liệu protobuf mở tệp theo cách tương tự, nhưng nó dừng phân tích cú pháp trên Windows khi nó chạm vào một ký tự đặc biệt trong tệp.

Ngoài ra, trong các phiên bản mới hơn của thư viện, bạn có thể sử dụng protobuf::util::ParseDelimitedFromCodedStream để đơn giản hóa kích thước đọc + cặp tải trọng.

... câu hỏi có thể cũ, nhưng vấn đề vẫn còn tồn tại và câu trả lời này gần như chắc chắn là bản sửa lỗi cho vấn đề ban đầu.

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