fread() เป็นฟังก์ชันมาตรฐาน C สำหรับอ่านข้อมูลแบบ binary จากไฟล์ (stream) ลงใน buffer ใช้กับ FILE* จาก <cstdio>
Prototype
size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream);
พารามิเตอร์
| พารามิเตอร์ | คำอธิบาย |
ptr | Pointer ไปยัง buffer ที่จะเก็บข้อมูล (ต้องมีขนาด ≥ size × nmemb bytes) |
size | ขนาดของแต่ละ element (bytes) |
nmemb | จำนวน elements ที่ต้องการอ่าน |
stream | FILE* ที่เปิดอยู่ (จาก fopen) |
คืนค่า
- จำนวน elements ที่อ่านสำเร็จ (type
size_t)
- ถ้าคืนค่า < code>nmemb → อ่านสำเร็จทั้งหมด
- ถ้าคืนค่า < code>nmemb → EOF หรือ error (ตรวจสอบด้วย
feof(), ferror())
ตัวอย่างโค้ด: เขียน/อ่าน Struct (Binary)
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct Student {
int id;
char name[32];
float gpa;
void print() const {
printf("ID: %d, Name: %s, GPA: %.2f\n", id, name, gpa);
}
};
int main() {
const char* filename = "students.dat";
// --- เขียนไฟล์ ---
FILE* fp = fopen(filename, "wb"); // wb = write binary
if (!fp) {
perror("fopen write failed");
return 1;
}
Student students[] = {
{1, "Alice", 3.75f},
{2, "Bob", 3.20f},
{3, "Charlie", 3.90f}
};
size_t written = fwrite(students, sizeof(Student), 3, fp);
cout << "Written " << written << " records\n";
fclose(fp);
// --- อ่านไฟล์ ---
fp = fopen(filename, "rb"); // rb = read binary
if (!fp) {
perror("fopen read failed");
return 1;
}
Student readBuf[10];
size_t readCount = fread(readBuf, sizeof(Student), 10, fp);
cout << "Read " << readCount << " records\n";
for (size_t i = 0; i < readCount; ++i) {
readBuf[i].print();
}
fclose(fp);
// --- อ่านบางส่วน (seek) ---
fp = fopen(filename, "rb");
fseek(fp, 1 * sizeof(Student), SEEK_SET); // ข้าม record แรก
Student oneStudent;
fread(&oneStudent, sizeof(Student), 1, fp);
cout << "\nRecord at index 1:\n";
oneStudent.print();
fclose(fp);
return 0;
}
ผลลัพธ์
Written 3 records
Read 3 records
ID: 1, Name: Alice, GPA: 3.75
ID: 2, Name: Bob, GPA: 3.20
ID: 3, Name: Charlie, GPA: 3.90
Record at index 1:
ID: 2, Name: Bob, GPA: 3.20
ตัวอย่าง: อ่าน Array ของ int
#include <cstdio>
#include <iostream>
int main() {
const char* filename = "numbers.bin";
// เขียน
int data[] = {10, 20, 30, 40, 50};
FILE* fp = fopen(filename, "wb");
fwrite(data, sizeof(int), 5, fp);
fclose(fp);
// อ่าน
fp = fopen(filename, "rb");
int buffer[10];
size_t count = fread(buffer, sizeof(int), 10, fp);
cout << "Read " << count << " integers: ";
for (size_t i = 0; i < count; ++i) {
cout << buffer[i] << " ";
}
cout << endl;
fclose(fp);
return 0;
}
ข้อควรระวัง
- Portability: Binary format ขึ้นกับ endianness, struct padding, sizeof types
- Alignment: Struct อาจมี padding ใช้
#pragma pack หรือ alignas ถ้าต้องการควบคุม
- C++ Objects: ไม่ควร fread/fwrite object ที่มี virtual functions, pointers, หรือ non-POD types
- Error Handling: ต้องตรวจสอบ
ferror() และ feof() หลังอ่าน
เปรียบเทียบ fread vs C++ Streams
| ด้าน | fread/fwrite | ifstream/ofstream |
| Interface | C-style (FILE*) | C++ streams (RAII) |
| Type Safety | ต่ำ (void*) | สูง (templates) |
| Performance | เร็ว (low-level) | ช้ากว่าเล็กน้อย |
| Binary Support | Native | ต้อง ios::binary |
| Exception Safety | Manual | Automatic (RAII) |
แนวทางปฏิบัติที่ดี
// RAII wrapper สำหรับ FILE*
class FileHandle {
FILE* fp;
public:
FileHandle(const char* filename, const char* mode) : fp(fopen(filename, mode)) {}
~FileHandle() { if (fp) fclose(fp); }
operator FILE*() { return fp; }
bool isOpen() const { return fp != nullptr; }
};
// ใช้งาน
FileHandle f("data.bin", "rb");
if (f.isOpen()) {
MyStruct s;
fread(&s, sizeof(s), 1, f);
}