Vì sao ios::ate hoặc seekp(0, ios::end) không dịch chuyển con trỏ về cuối file nhị phân?

Hi mọi người,

Mình xin phép được hỏi về một đoạn code đọc/ghi số nguyên vào file nhị phân như sau:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    int N{1};
    fstream fout("input.dat", ios::out | ios::binary);
    fout.write((char*)&N, sizeof(int));
    fout.close();

    fout.open("input.dat", ios::out | ios::binary);
    fout.seekp(0, ios::end);
    cout << "At " << int64_t(fout.tellp()) << endl;
    ++N;
    fout.write((char*)&N, sizeof(int));
    fout.close();


    fstream fin("input.dat", ios::in | ios::binary);
    int M;
    while (fin.read((char*)&M, sizeof(int))) {
        cout << M << endl;
    }
    fin.close();

    return 0;
}

Mình kỳ vọng đoạn code trên sẽ in ra 1 2, nhưng thực tế là:

At 0
2

Nếu thay vì dùng seekp(0, ios::end) để dịch về cuối file, mình thêm mode ios::ate vào fout thì lúc ghi nó vẫn ghi đè số 2 vào số 1 như trên.
Tuy nhiên, nếu mình kết hợp các mode ios::out | ios::in | ios::ate thì lúc này, con trỏ mới được dịch về cuối file:

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    int N{1};
    fstream fout("input.dat", ios::out | ios::binary);
    fout.write((char*)&N, sizeof(int));
    fout.close();

    fout.open("input.dat", ios::out | ios::binary | ios::ate | ios::in);
    cout << "At " << int64_t(fout.tellp()) << endl;
    ++N;
    fout.write((char*)&N, sizeof(int));
    fout.close();

    fstream fin("input.dat", ios::in | ios::binary);
    int M;
    while (fin.read((char*)&M, sizeof(int))) {
        cout << M << endl;
    }
    fin.close();

    return 0;
}

Output

At 4
1
2

Vì vậy, câu hỏi của mình là: Vì sao ios::ate hoặc seekp(0, ios::end) không dịch con trỏ trong 1 file nhị phân (dùng để ghi) về cuối file được ạ? Và vì sao khi kết hợp thêm mode ios::in vào 1 file dùng để ghi thì nó mới dịch được ạ?

Mình xin cảm ơn.

là do open bằng ios::out mà ko có ios::app hay ios::ate hay ios::in thì khi file đã exist nó sẽ hủy hết nội dung file cũ :V

https://en.cppreference.com/w/cpp/io/basic_filebuf/open

em dòm cột thứ 3 ấy, chỉ có out ko thì nó tương đương với out|trunc mà trunc là xóa nội dung file cũ :V :V

chắc là do khi mở output file lên có 2 lựa chọn, 1 là xóa nội dung cũ, 2 là giữ nội dung cũ, thì có 2 option. Thay vì mặc định “w” là giữ nội dung cũ (truncate thì mới xóa nội dung cũ) thì C chọn “w” là xóa/ghi đè (overwrite) nội dung cũ :V và “a” là giữ nội dung cũ. C++ ăn theo :V :V (nhiều ngôn ngữ khác như Python cũng làm theo như vậy :V)

4 Likes

Ồ dạ, giờ em mới để ý :joy:
Mà nếu 1 luồng bật cả ios::in | ios::out thì bao gồm cả chức năng đọc và ghi, thì mình dùng seekp hay seekg hoặc tellp hay tellg đều được đúng hong anh?

ờm :V :V :V : :V :V :V

2 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?