2008-11-17 28 views
74

Chúng tôi đã có một cuộc thảo luận ở đây tại nơi làm việc liên quan đến lý do tại sao fread và fwrite mất một kích thước cho mỗi thành viên và đếm và trả về số lượng thành viên đọc/viết thay vì chỉ lấy một bộ đệm và kích thước. Việc sử dụng duy nhất cho nó chúng tôi có thể đưa ra là nếu bạn muốn đọc/viết một mảng các cấu trúc mà không thể chia đều cho nền tảng và do đó đã được đệm nhưng không thể quá phổ biến như để đảm bảo lựa chọn này trong thiết kế.Lý do cơ bản cho kích thước fread/fwrite là gì và được tính là đối số?

Từ fread (3):

Chức năng fread() đọc yếu tố nmemb dữ liệu, mỗi kích thước byte dài, từ dòng trỏ đến bởi dòng, lưu trữ chúng tại địa điểm trao bởi ptr.

Hàm fwrite() ghi các phần tử nmemb của dữ liệu, mỗi byte kích thước dài, đến luồng được trỏ tới theo luồng, lấy chúng từ vị trí do ptr cung cấp.

fread() và fwrite() trả lại số mục được đọc hoặc viết thành công (nghĩa là, không phải số ký tự). Nếu một lỗi xảy ra, hoặc đạt đến kết thúc của tập tin , giá trị trả về là số đếm ngắn (hoặc số không).

+9

hey đây là một câu hỏi hay. Tôi luôn luôn tự hỏi về nó –

+1

Hãy kiểm tra chủ đề này: http://stackoverflow.com/questions/8589425/how-does-fread-really-work – Franken

Trả lời

18

Được dựa trên cách thực hiện fread.

Single UNIX Specification nói

Đối với mỗi đối tượng, gọi điện kích thước được thực hiện cho các fgetc() chức năng và kết quả được lưu trữ, theo thứ tự đọc, trong một mảng của char unsigned chính xác che phủ đối tượng.

fgetc cũng có ghi chú này:

Kể từ fgetc() hoạt động trên byte, đọc một nhân vật bao gồm nhiều byte (hoặc "đa-byte nhân vật") có thể đòi hỏi nhiều cuộc gọi để fgetc().

Tất nhiên, điều này đặt trước mã hóa ký tự thay đổi byte ưa thích như UTF-8.

SUS lưu ý rằng điều này thực sự được lấy từ tài liệu ISO C.

50

Sự khác biệt trong fread (buf, 1000, 1, stream) và fread (buf, 1, 1000, stream) là, trong trường hợp đầu tiên bạn chỉ nhận được một đoạn 1000 byte hoặc nuthin, nếu tệp nhỏ hơn và trong trường hợp thứ hai, bạn nhận được mọi thứ trong tệp nhỏ hơn và tối đa 1000 byte.

+3

Mặc dù đúng, điều đó chỉ nói một phần nhỏ của câu chuyện. Nó sẽ là tốt hơn để tương phản một cái gì đó đọc, nói, một mảng các giá trị int, hoặc một mảng các cấu trúc. –

+2

Điều này sẽ làm cho một câu trả lời tuyệt vời nếu biện minh được hoàn thành. –

+0

câu trả lời thực tế. cảm ơn – austin

3

Có khả năng nó quay trở lại cách tệp I/O được triển khai. (trở lại trong ngày) Nó có thể đã nhanh hơn để viết/đọc các tập tin trong các khối sau đó để viết tất cả mọi thứ cùng một lúc.

+0

Không thực sự. Đặc điểm kỹ thuật C cho ghi chú fwrite mà nó thực hiện các cuộc gọi lặp lại đến fputc: http://www.opengroup.org/onlinepubs/009695399/functions/fwrite.html – Powerlord

9

Ở đây, hãy để tôi sửa chữa những chức năng:

size_t fread_buf(void* ptr, size_t size, FILE* stream) 
{ 
    return fread(ptr, 1, size, stream); 
} 


size_t fwrite_buf(void const* ptr, size_t size, FILE* stream) 
{ 
    return fwrite(ptr, 1, size, stream); 
} 

Đối với một lý do cho các thông số để fread()/fwrite(), tôi đã đánh mất bản sao của tôi của K & R từ lâu nên tôi chỉ có thể đoán. Tôi nghĩ rằng một câu trả lời có khả năng là Kernighan và Ritchie có thể chỉ đơn giản nghĩ rằng thực hiện nhị phân I/O sẽ được tự nhiên thực hiện nhất trên mảng các đối tượng. Ngoài ra, họ có thể nghĩ rằng khối I/O sẽ nhanh hơn/dễ dàng hơn để thực hiện hoặc bất cứ điều gì trên một số kiến ​​trúc.

Mặc dù tiêu chuẩn C xác định rằng fread()fwrite() được thực hiện trong điều kiện của fgetc()fputc(), hãy nhớ rằng tiêu chuẩn ra đời rất lâu sau khi C được xác định bởi K & R và rằng những điều quy định trong tiêu chuẩn có thể không có được trong các ý tưởng thiết kế ban đầu. Thậm chí có thể những điều được nói trong "Ngôn ngữ lập trình C" của K & R có thể không giống như khi ngôn ngữ được thiết kế lần đầu tiên.

Cuối cùng, đây là những gì PJ Plauger đã nói về fread() trong "Tiêu chuẩn Thư viện C":

Nếu (thứ hai) lập luận size lớn hơn, bạn có thể không xác định xem chức năng cũng đọc tối đa size - 1 các ký tự bổ sung ngoài những gì nó báo cáo. Như một quy luật, bạn có khấm khá hơn gọi hàm như fread(buf, 1, size * n, stream); thay vì fread(buf, size, n, stream);

Bascially, anh ấy nói rằng giao diện fread() 's bị hỏng. Đối với fwrite() ông lưu ý rằng, "Viết lỗi thường hiếm, vì vậy đây không phải là một thiếu sót lớn" - một tuyên bố tôi sẽ không đồng ý với.

+16

Thực ra tôi thường thích làm theo cách khác: 'fread (buf, size) * n, 1, stream); 'Nếu đọc không đầy đủ là một điều kiện lỗi, đơn giản hơn để sắp xếp cho' fread' chỉ đơn giản là trả về 0 hoặc 1 chứ không phải là số byte được đọc. Sau đó, bạn có thể làm những việc như 'if (! Fread (...))' thay vì phải so sánh kết quả với số byte được yêu cầu (yêu cầu mã C bổ sung và mã máy phụ). –

12

Đây là những suy đoán thuần túy, tuy nhiên ngược lại trong những ngày (Một số vẫn còn xung quanh) nhiều hệ thống tệp không phải là luồng byte đơn giản trên ổ cứng.

Nhiều hệ thống tệp được ghi lại, do đó, để thỏa mãn hệ thống tệp một cách hiệu quả, bạn sẽ phải chỉ định số lượng mục ("bản ghi"), cho phép fwrite/fread hoạt động trên bộ nhớ dưới dạng bản ghi chứ không phải chỉ các luồng byte.

+1

Tôi rất vui khi có ai đó mang nó lên. Tôi đã làm rất nhiều công việc với thông số kỹ thuật hệ thống tập tin và FTP và hồ sơ/trang và các khái niệm chặn khác được hỗ trợ rất vững chắc, mặc dù không ai sử dụng những phần của thông số kỹ thuật nữa. –

1

Tôi nghĩ đó là vì C thiếu quá tải hàm. Nếu có một số, kích thước sẽ là dư thừa. Nhưng trong C bạn không thể xác định kích thước của phần tử mảng, bạn phải chỉ định một phần tử.

Hãy xem xét điều này:

int intArray[10]; 
fwrite(intArray, sizeof(int), 10, fd); 

Nếu fwrite chấp nhận số byte, bạn có thể viết như sau:

int intArray[10]; 
fwrite(intArray, sizeof(int)*10, fd); 

Nhưng nó chỉ là không hiệu quả. Bạn sẽ có nhiều cuộc gọi hệ thống hơn (int) lần.

Một điểm khác cần được cân nhắc là bạn thường không muốn một phần của phần tử mảng được ghi vào tệp. Bạn muốn toàn bộ số nguyên hoặc không có gì. fwrite trả về một số thành phần được viết thành công. Vì vậy, nếu bạn phát hiện ra rằng chỉ có 2 byte thấp của một phần tử được viết thì bạn sẽ làm gì?

Trên một số hệ thống (do căn chỉnh), bạn không thể truy cập một byte của số nguyên mà không tạo bản sao và dịch chuyển.

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