Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

ฟังก์ชัน fread() ใน C++: อ่านข้อมูลจากไฟล์แบบ Binary

fread() เป็นฟังก์ชันมาตรฐาน C สำหรับอ่านข้อมูลแบบ binary จากไฟล์ (stream) ลงใน buffer ใช้กับ FILE* จาก <cstdio>

Prototype

size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream);

พารามิเตอร์

พารามิเตอร์คำอธิบาย
ptrPointer ไปยัง buffer ที่จะเก็บข้อมูล (ต้องมีขนาด ≥ size × nmemb bytes)
sizeขนาดของแต่ละ element (bytes)
nmembจำนวน elements ที่ต้องการอ่าน
streamFILE* ที่เปิดอยู่ (จาก 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/fwriteifstream/ofstream
InterfaceC-style (FILE*)C++ streams (RAII)
Type Safetyต่ำ (void*)สูง (templates)
Performanceเร็ว (low-level)ช้ากว่าเล็กน้อย
Binary SupportNativeต้อง ios::binary
Exception SafetyManualAutomatic (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);
}