Mengapa menulis terus menerus meninggalkan 4K byte di buffer?

30

Saya pada dasarnya memiliki kode berikut:

int fileWrite(int file, void * pBuffer, size_t size)
{
    size_t bytesWritten = (size_t)write( file, pBuffer, size ) ;
    if (bytesWritten != size)
    {
       return -1;
    }
    return 0;
}

Ini berfungsi jika ukurannya 1GB, tetapi ketika ukurannya ~ 2GB, ia mendapatkan 4K byte tersisa secara konsisten. Saya dapat memperbaikinya dengan membungkus tulis dalam satu lingkaran dan memindahkan buffer ke atas tapi saya ingin tahu mengapa selalu gagal.

Misalnya jika ukurannya adalah 2147483648, tulis hanya tulislah 2147479552, meninggalkan 4096 tidak tertulis. Mengapa ini terjadi dan apakah benar untuk selalu membungkus tulis dalam satu lingkaran?

TreeWater
sumber
2
Apakah Anda menjalankannya dalam mode 32-bit? 2gig adalah jumlah maksimum 32-bit.
Barmar
2
Aturan untuk berapa banyak data yang writeakan dikonsumsi sekaligus tergantung pada apa jenis wastafel data file(misalnya file "biasa", pipa, soket aliran, soket datagram, ...). Bisakah Anda lebih spesifik?
zwol
7
Tunggu, apakah Anda mencoba writeseluruh file sekaligus? Pendekatan yang biasa dilakukan adalah mengalirkan data dalam ukuran buffer pada satu waktu sampai Anda menulis semuanya.
Luaan
4
@Luaan Jika Anda sudah memiliki semua data, saya tidak melihat ada yang salah dengan menulis semuanya sekaligus tetapi seperti yang digambarkan oleh pertanyaan dan jawaban ini, write()tidak harus menulis semuanya (yang berlaku untuk buffer kecil juga)
pipe
8
"Saya dapat memperbaikinya dengan membungkus tulis dalam satu lingkaran" dan Anda harus melakukannya, terlepas dari SSIZE_MAXbatasannya. The write()Spec mengatakan tidak berkewajiban untuk menulis buffer penuh, bahkan jika itu hampir selalu tidak. Kode loop-less dalam pertanyaan adalah bug.
Adam

Jawaban:

50

Anda dapat menemukan jawabannya di man 2 write:

Ini bukan kesalahan jika jumlah ini lebih kecil dari jumlah byte yang diminta; ini dapat terjadi misalnya karena perangkat disk terisi.


Dan dari write()deskripsi halaman manual:

ssize_t write(int fd, const void *buf, size_t count);

Menurut POSIX.1, jika countlebih besar dari SSIZE_MAX, hasilnya ditentukan implementasi; lihat CATATAN untuk batas atas di Linux.

CATATAN

Di Linux, write()(dan panggilan sistem serupa) akan mentransfer paling banyak 0x7ffff000(2.147.479.552) byte, mengembalikan jumlah byte yang sebenarnya ditransfer. (Ini berlaku untuk sistem 32-bit dan 64-bit.)

bobah
sumber