Pourquoi l'écriture laisse-t-elle en continu 4K octets dans le tampon?

30

J'ai essentiellement le code suivant:

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;
}

Cela fonctionne si la taille est de 1 Go, mais lorsque la taille est de ~ 2 Go, il reste systématiquement 4 octets. Je peux résoudre ce problème en enveloppant l'écriture dans une boucle et en déplaçant le tampon vers le haut, mais je suis curieux de savoir pourquoi il échoue toujours.

Par exemple, si la taille est 2147483648, l'écriture écrit uniquement 2147479552, laissant 4096 non écrit. Pourquoi cela arriverait-il et est-il correct de toujours boucler l'écriture dans une boucle?

TreeWater
la source
2
Le lancez-vous en mode 32 bits? 2gig est le nombre maximal de 32 bits.
Barmar
2
Les règles concernant la quantité de données writeconsommées à la fois dépendent du type de récepteur de données file(par exemple, fichier "normal", pipe, socket de flux, socket de datagramme, ...). Peux-tu être plus précis?
Zwol
7
Attendez, essayez-vous writele fichier entier à la fois? L'approche habituelle consiste à diffuser les données une taille de tampon à la fois jusqu'à ce que vous écriviez tout.
Luaan
4
@Luaan Si vous avez déjà toutes les données, je ne vois rien de mal à tout écrire en même temps, mais comme l'illustre cette question et réponse, il write()n'est pas nécessaire de tout écrire (ce qui vaut également pour les petits tampons)
pipe
8
"Je peux résoudre ce problème en enveloppant l'écriture dans une boucle" et vous devez le faire, quelle que soit la SSIZE_MAXrestriction. La write()spécification indique qu'elle n'est pas obligée d'écrire le tampon complet, même si c'est presque toujours le cas. Le code sans boucle dans la question est un bogue.
Adam

Réponses:

50

Vous pouvez trouver la réponse dans man 2 write:

Ce n'est pas une erreur si ce nombre est inférieur au nombre d'octets demandés; cela peut se produire par exemple parce que le périphérique de disque a été rempli.


Et à partir de la write()description de la page de manuel:

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

Selon POSIX.1, si countest supérieur à SSIZE_MAX, le résultat est défini par l'implémentation; voir NOTES pour la limite supérieure sous Linux.

REMARQUES

Sous Linux, write()(et les appels système similaires) transfèrent au plus 0x7ffff000(2 147 479 552) octets, renvoyant le nombre d'octets réellement transférés. (Cela est vrai sur les systèmes 32 bits et 64 bits.)

bobah
la source