2009-12-02 12 views
8

Tôi có mã điều khiển các tệp nhị phân bằng cách sử dụng fstream với cờ nhị phân được đặt và sử dụng các hàm I/O chưa được định dạng đọc và ghi. Điều này hoạt động chính xác trên tất cả các hệ thống mà tôi từng sử dụng (các bit trong tệp chính xác như mong đợi), nhưng về cơ bản tất cả đều là tiếng Anh của Hoa Kỳ. Tôi đã tự hỏi về tiềm năng cho các byte được sửa đổi bởi một codecvt trên một hệ thống khác nhau.Viết các tệp nhị phân bằng C++: có phải vấn đề địa phương mặc định không?

Có vẻ như tiêu chuẩn cho biết sử dụng I/O chưa được định dạng hoạt động giống như đặt ký tự vào streambuf bằng sputc/sgetc. Điều này sẽ dẫn đến các chức năng tràn hoặc tràn trong streambuf nhận được gọi, và nó âm thanh như những dẫn đến công cụ đi qua một số codecvt (ví dụ, xem 27.8.1.4.3 trong tiêu chuẩn C++). Đối với basic_filebuf việc tạo codecvt này được xác định trong 27.8.1.1.5. Điều này làm cho nó trông giống như kết quả sẽ phụ thuộc vào những gì basic_filebuf.getloc() trả về. Vì vậy, câu hỏi của tôi là, tôi có thể giả định rằng một mảng ký tự được viết bằng cách sử dụng of.write trên một hệ thống có thể được phục hồi nguyên văn bằng cách sử dụng ifstream.read trên một hệ thống khác, không có vấn đề gì cấu hình địa phương hoặc người có thể được sử dụng trên của họ hệ thống? Tôi sẽ làm cho các giả định sau:

  1. Chương trình được sử dụng mặc định locale (ví dụ: chương trình là không thay đổi các thiết lập miền địa phương tự ở tất cả).
  2. Cả hai hệ thống đều có CHAR_BIT 8, có cùng thứ tự bit trong mỗi byte, lưu trữ tệp dưới dạng octet, v.v.
  3. Đối tượng luồng có cờ nhị phân được đặt.
  4. Chúng tôi không cần phải lo lắng về bất kỳ sự khác biệt về cuối cùng nào ở giai đoạn này. Nếu bất kỳ byte nào trong mảng được hiểu là giá trị nhiều byte, thì các chuyển đổi cuối cùng sẽ được xử lý theo yêu cầu ở giai đoạn sau.

Nếu ngôn ngữ mặc định không được đảm bảo truyền tải nội dung này chưa được sửa đổi trên một số cấu hình hệ thống (Tôi không biết, tiếng Ả Rập hoặc gì đó), cách tốt nhất để viết tệp nhị phân bằng C++ là gì?

+1

Tôi nghĩ bạn nên thêm cùng thứ tự byte vào giả định của mình. Hay tôi hoàn toàn ở ngoài đó? –

+0

@TheScottMachine: Space_C0wb0y là đúng, thêm cùng thứ tự byte vào các giả định của bạn – Stan

+0

Cảm ơn, tôi đã thêm một giả định bổ sung để làm rõ. – TheScottMachine

Trả lời

0

Trên Windows, bạn nên sử dụng hệ điều hành khác nhưng trên hệ điều hành khác, bạn cũng nên kiểm tra kết thúc dòng (an toàn). Ngôn ngữ mặc định C/C++ là "C" là không phụ thuộc vào ngôn ngữ của hệ thống.

Đây không phải là sự đảm bảo. Như bạn biết trình biên dịch C/C++ và các máy mục tiêu của chúng thay đổi rất nhiều. Vì vậy, bạn đang chờ đợi những rắc rối đến nếu bạn giữ tất cả những giả định đó. Có chi phí không đáng kể để thay đổi ngôn ngữ trừ khi bạn cố gắng làm cho nó hàng trăm lần mỗi giây.

+0

Cảm ơn, thông tin về ngôn ngữ mặc định là những gì tôi đang tìm kiếm. Tôi nghĩ rằng dòng kết thúc không thành vấn đề miễn là cờ nhị phân được đặt trên luồng. – TheScottMachine

1

Nếu bạn đặt cờ nhị phân, mọi thứ bạn viết sẽ được ghi vào nguyên văn tệp. Không có chuyển đổi. Cách bạn diễn giải byte tùy thuộc vào bạn (và có thể là ngôn ngữ).

Một điều nữa: Có khả năng vỡ ở các miền địa phương khác nhau. Ví dụ, nếu nguồn dữ liệu của bạn tạo ra dữ liệu nhị phân dựa trên ngôn ngữ (và định dạng của dữ liệu này sẽ thay đổi tùy thuộc vào miền địa phương - đây là một ý tưởng tồi btw). Điều này sẽ gây ra sự cố khi tải dữ liệu trên các máy có miền địa phương khác nhau. Đây là một lỗi thiết kế mặc dù.

Nếu bạn chỉ sử dụng các loại/cấu trúc dữ liệu chuẩn có cùng định dạng/bố cục bất kể ngôn ngữ nào được tạo trong mọi thứ đều OK.

1

Cảm ơn sự giúp đỡ. Tôi chỉ nghĩ rằng nó có thể hữu ích để đăng một số thông tin bổ sung về điều này mà sẽ không phù hợp trong một bình luận.

Ngôn ngữ mặc định cho các chương trình C++ luôn là ngôn ngữ "C" (http://www.cplusplus.com/reference/clibrary/clocale/setlocale/). Nếu đây là ngôn ngữ duy nhất được sử dụng trong chương trình của bạn, điều đó có nghĩa là hành vi không phụ thuộc vào cấu hình miền địa phương cụ thể của máy mà nó đang chạy. Nó cũng có nghĩa là I/O chưa định dạng cho một char không trải qua bất kỳ chuyển đổi mã nào (wchar_t có thể là một câu chuyện khác). Điều này có nghĩa rằng (cho các giả định trong câu hỏi) đọc và ghi nên cho phép dữ liệu nhị phân được phục hồi chưa sửa đổi. Bạn có thể thiết lập toàn bộ miền địa phương của ứng dụng để phù hợp với hệ thống mặc định bằng cách gọi setlocale (LC_ALL, ""), nghĩa là các luồng được xây dựng từ điểm đó sẽ sử dụng ngôn ngữ mặc định của hệ thống. Để đặt nó trở lại miền địa phương "C", bạn có thể gọi setlocale (LC_ALL, "C"), điều này có nghĩa là những luồng được xây dựng trong tương lai sẽ sử dụng. Bạn cũng có thể chỉ định rằng địa chỉ "C" nên được sử dụng cho luồng đã được tạo bằng cách gọi stream.imbue (locale :: classic()).