2013-07-08 49 views
11

Tôi có một tệp đã chứa một số dữ liệu (ví dụ: 8 kB). Tôi muốn đọc một cái gì đó từ đầu của tập tin, và sau đó ghi đè lên dữ liệu bắt đầu từ nơi tôi đọc xong. Vì vậy, tôi cố gắng sử dụng đoạn mã sau:Đọc và ghi vào cùng một tệp bằng cách sử dụng cùng một fstream

std::fstream stream("filename", std::ios::in | std::ios::out | std::ios::binary); 

char byte; 
stream.read(&byte, 1); 

// stream.seekp(1); 

int bytesCount = 4096; 

auto bytesVec = std::vector<char>(bytesCount, 'c'); 
char* bytes = bytesVec.data(); 

std::cout << stream.bad() << std::endl; 

stream.write(bytes, bytesCount); 

std::cout << stream.bad() << std::endl; 

Nếu tôi thực thi mã này, bad() lợi nhuận đầu tiên false, nhưng một trong những thứ hai trả true và không có gì thực sự được viết ra.

Nếu tôi giảm bytesCount xuống bất kỳ thứ gì nhỏ hơn 4096 (có lẽ là kích thước của một số bộ đệm bên trong), thì bad() thứ hai trả về false, nhưng vẫn không có gì được viết.

Nếu tôi bỏ ghi chú dòng seekp(), văn bản bắt đầu hoạt động: bad() trả lại false và các byte thực sự được viết.

Tại sao cần seekp() ở đây? Tại sao nó không hoạt động mà không có nó? seekp() có đúng cách để thực hiện việc này không?

Tôi đang sử dụng Visual Studio 2012 trên Windows 7.

Trả lời

19

Bạn đang rơi hôi của một hạn chế khi xen chút của thao tác đọc và ghi trên một tập tin đã mở trong chế độ cập nhật thư viện fstream MS của thừa hưởng từ từ việc thực hiện C <stdio.h> của nó.

C Standard (tôi trích dẫn C99, nhưng nó không khác nhau về điểm này từ C89) tại 7.19.5.3/6 trạng thái:

Khi một tập tin được mở ra với chế độ cập nhật ('+ 'làm ký tự thứ hai hoặc thứ ba trong số danh sách giá trị đối số ở trên), cả đầu vào và đầu ra có thể được thực hiện trên luồng liên kết . Tuy nhiên, đầu ra không được trực tiếp theo sau bởi đầu vào mà không cần gọi số can thiệp vào chức năng fflush hoặc chức năng định vị tệp (fseek, fsetpos hoặc tua lại) và đầu vào không được theo dõi trực tiếp bởi đầu ra mà không cần gọi số với chức năng định vị tệp, trừ khi thao tác nhập gặp sự cố kết thúc của tệp.

(nhấn mạnh của tôi).

Vì vậy, giải pháp stream.seekp(1) của bạn, được chuyển thành C fseek, là chính xác.

Thư viện GNU C không có giới hạn tiêu chuẩn này, vì vậy mã của bạn được đăng hoạt động như mong đợi khi được xây dựng với GCC.

Thư viện MS <fstream> tuân thủ Tiêu chuẩn C++ khi kế thừa hạn chế này. fstream s được triển khai sử dụng basic_filebuf<charT,traits>. Trong (C++ 11) tài khoản Standard của mẫu này, tại § 27.9.1.1/2, nó chỉ đơn giản nói:

Các hạn chế đối với việc đọc và viết một chuỗi điều khiển bởi một đối tượng của lớp basic_filebuf đều giống nhau để đọc và viết với các thư viện FILE tiêu chuẩn C.

+0

Tài liệu này có được ghi nhận cho luồng C++ không? Hoặc thực hiện MS không tuân thủ các tiêu chuẩn trong lĩnh vực này? – svick

+0

@svick Xem cập nhật. –

0

Bạn có thể muốn nhìn vào suối gắn - http://www.cplusplus.com/reference/ios/ios/tie/

Điều này làm cho mỗi lần một đầu vào đọc đầu ra sẽ tự động được đỏ mặt, đó là tôi nghĩ rằng hành vi mà bạn muốn, mặc dù nó đòi hỏi một đầu vào riêng biệt và luồng đầu ra

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