2012-03-09 14 views
6

tôi cần tạo cờ mới cho định dạng của tệp đầu ra. tôi có một lớpC++ fstream - tạo cờ định dạng riêng

class foo{ 
    bar* members; 
    ofstream& operator<<(ofstream&); 
    ifstream& operator>>(ifstream&); 
}; 

và tôi muốn sử dụng nó như:

fstream os('filename.xml'); 
foo f; 
os << xml << f; 
os.close(); 

này sẽ tiết kiệm được một xml tập tin.

fstream os('filename.json'); 
foo f; 
os << json << f; 
os.close(); 

và điều này một json tập tin.

Tôi làm cách nào để thực hiện việc này?

Trả lời

6

Bạn có thể dễ dàng tạo ra thao tác riêng Yor, hoặc là cướp một cờ hiện có hoặc sử dụng std::ios_base::xalloc để có được bộ nhớ mới cụ thể, ví dụ: (Trong file thi hành Foo:

static int const manipFlagId = std::ios_base::xalloc(); 

enum 
{ 
    fmt_xml,  // Becomes the default. 
    fmt_json 
}; 

std::ostream& 
xml(std::ostream& stream) 
{ 
    stream.iword(manipFlagId) = fmt_xml; 
    return stream; 
} 

std::ostream& 
json(std::ostream& stream) 
{ 
    stream.iword(manipFlagId) = fmt_json; 
    return stream; 
} 

std::ostream& 
operator<<(std::ostream& dest, Foo const& obj) 
{ 
    switch (dest.iword(manipFlagId)) { 
    case fmt_xml: 
     // ... 
     break; 
    case fmt_json: 
     // ... 
     break; 
    default: 
     assert(0); // Or log error, or abort, or... 
    } 
    return dest; 
} 

Declare xmljson trong tiêu đề của bạn, và công việc được thực hiện

(Nói xong, tôi thay vì nghĩ rằng đây là một chút của sự lạm dụng. thao tác. các định dạng như xml đi ngoài đơn giản, định dạng địa phương, và được xử lý tốt nhất bởi một lớp riêng biệt, công ty sở hữu các ostream, và viết toàn bộ dòng, và không phải đối tượng chỉ cá nhân.)

0

Cách đơn giản nhất mà đến với tâm là bắt đầu bằng cách tạo ra một loại thẻ và một trường hợp duy nhất của chúng:

struct JsonStreamTag {} json; 

Sau đó, chúng ta hãy một thẻ như xây dựng một đối tượng để bọc các dòng:

class JsonStream { 
public: 

    // (1) 
    friend JsonStream operator<<(std::ostream& ostream, const JsonStreamTag&) { 
     return JsonStream(ostream); 
    } 

    // (2) 
    template<class T> 
    friend JsonStream& operator<<(JsonStream& json_stream, const T& value) { 
     write_json(json_stream.ostream, value); // (3) 
     return json_stream; 
    } 

protected: 

    JsonStream(std::ostream& ostream) : ostream(ostream) {} 

private: 

    std::ostream& ostream; 

}; 

Nhà xây dựng là protected để đảm bảo rằng bạn chỉ có thể sử dụng some_ostream << json (1) để xây dựng JsonStream. Toán tử chèn khác (2) thực hiện định dạng thực tế. sau đó bạn xác định một tình trạng quá tải của write_json() (3) cho tất cả các loại có liên quan:

void write_json(std::ostream& stream, int value) { 
    stream << value; 
} 

void write_json(std::ostream& stream, std::string value) { 
    stream << '"' << escape_json(value) << '"'; 
} 

// Overloads for double, std::vector, std::map, &c. 

Ngoài ra, bỏ qua (2) và thêm quá tải cho operator<<(JsonStream&, T) để thay thế.

Sau đó, chỉ cần làm theo quy trình tương tự để viết XmlStream tương ứng bằng cách sử dụng XmlStreamTagwrite_xml(). Điều này giả định rằng đầu ra của bạn có thể được xây dựng hoàn toàn từ các giá trị cụ thể mà bạn đang viết; nếu bạn cần một số header hay footer đó là giống nhau trên tất cả các tập tin bạn sẽ viết, chỉ cần sử dụng constructor và destructor:

XmlStream(std::ostream& ostream) : ostream(ostream) { 
    ostream << "<?xml version=\"1.0\"?><my_document>" 
} 

~XmlStream() { 
    ostream << "</my_document>"; 
} 
+1

Tôi không nghĩ rằng đây là một ý tưởng hay. Nó không hoạt động với những thứ như 'out << json <<" Tiêu đề: "<< obj;' chẳng hạn. (Tất nhiên, đối với một cái gì đó như XML, điều này sẽ không có ý nghĩa anyway. Nhưng đó là một đối số cho không sử dụng thao tác ở nơi đầu tiên.) –

+0

@JamesKanze: Câu hỏi không được xác định rõ ràng. Với mục đích trả lời câu hỏi theo nghĩa đen, tôi đã giả thiết rằng một “luồng JSON” sẽ coi mọi thứ như một giá trị JSON. Nhưng tôi nghĩ rằng một điều như vậy là sai lầm ngay từ đầu. –

+0

XML (và JSON, theo như tôi biết) không phải là luồng; chúng là những cấu trúc phức tạp hơn. Một loại không liên quan không được xuất XML hoặc JSON thành 'ostream'; nó sẽ chèn nó vào một số ví dụ của một cấu trúc dữ liệu XML hoặc JSON, sau đó sẽ xử lý đầu ra được truyền trực tiếp, ở mức tệp. –

1

Vấn đề này là lỗ hổng lớn nhất trong thư viện iostream.

Giải pháp của James Kanze là giải pháp một phần sẽ hoạt động trong các lớp học của riêng bạn nhưng trong các đối tượng chung được cung cấp một cách phát trực tuyến riêng biệt.

Phương tiện thông thường của tôi là tạo lớp trình bao bọc của riêng tôi với chức năng mà bạn có thể chuyển vào luồng của mình và với xml sẽ chứa quá tải đến xml_node() hoặc xml_attribute() ví dụ:

os << xml_attribute("Id", id); 

sẽ đặt Id thuộc tính thành bất kỳ biến nào trong định dạng xml.

Tôi cũng đã viết phạm vi nút quá để chúng sẽ ghi luồng luồng văn bản mở nút đang được xây dựng và tự động viết logic kết thúc khi hủy.

Lợi thế của phương pháp của tôi đối với giải pháp của James Kanze là nó có thể mở rộng được. Tôi nghĩ rằng bình luận đóng của James Kanze cho thấy anh ta không tán thành giải pháp của anh ta và có lẽ sẽ sử dụng một thứ gì đó giống tôi hơn. Với giải pháp trên, để thêm các định dạng khác, bạn phải chỉnh sửa toán tử < < tất cả các địa điểm, trong khi mã định dạng json sẽ là một bộ chức năng hoàn toàn khác và nếu bạn thêm một định dạng khác, bạn sẽ thêm mã cho nó mà không cần phải chỉnh sửa bất kỳ mã hiện có nào.

Để nhập, bằng cách này, đối với XML, bạn sẽ sử dụng trình phân tích cú pháp DOM hoặc SAX hiện tại và sẽ không sử dụng trực tiếp iostream theo cách này.

+0

Tôi không nghĩ rằng việc sử dụng luồng trực tiếp để xuất XML là một giải pháp thích hợp. Luồng là luồng trừu tượng của luồng chứ không phải cấu trúc dữ liệu phân cấp. Để xuất XML, tôi sẽ sử dụng một thư viện như Xerces; cái gì đó cho phép chèn vào một cấu trúc phân cấp. Đối với phần còn lại: các lớp wrapper rất hữu ích nếu bạn cần định dạng bất thường cho một kiểu dựng sẵn hoặc cho các cấu trúc rất phức tạp, nhưng các trình xử lý hoạt động tốt trong một số lượng lớn các trường hợp. –

+0

Để chính xác hơn (và có lẽ đó là ý nghĩa của bạn): việc xuất ra một định dạng khác nhau trên toàn cầu phải được thực hiện bằng một cơ chế khác với luồng: các trình xử lý tùy chỉnh dành cho các loại tùy chỉnh đơn lẻ, không ảnh hưởng đến đầu ra của tất cả các loại . (Và bạn không thể thêm các tùy chọn định dạng vào 'int'). –