Dlaczego zapis ciągle pozostawia bajty 4K w buforze?

30

Mam zasadniczo następujący kod:

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

Działa, jeśli rozmiar wynosi 1 GB, ale gdy rozmiar wynosi ~ 2 GB, konsekwentnie pozostaje 4K bajtów. Mogę to naprawić, owijając zapis w pętli i przesuwając bufor w górę, ale jestem ciekawy, dlaczego zawsze zawodzi.

Na przykład, jeśli rozmiar to 2147483648, tylko do zapisu zapisuje 2147479552, pozostawiając 4096 niepisany. Dlaczego tak się dzieje i czy poprawne jest zawsze zawijanie zapisu w pętli?

TreeWater
źródło
2
Czy używasz go w trybie 32-bitowym? 2gig to maksymalna liczba 32-bitowa.
Barmar
2
Zasady określające, ile danych writezostanie zużyte jednocześnie, zależą od typu ujścia danych file(np. „Zwykły” plik, potok, gniazdo strumienia, gniazdo datagramu, ...). Czy mógłbyś to sprecyzować?
zwolnienie
7
Czekaj, próbujesz writejednocześnie otworzyć cały plik? Zwykle stosuje się przesyłanie strumieniowe danych wielkości bufora na raz, dopóki nie napisze się wszystkiego.
Luaan
4
@Luaan Jeśli masz już wszystkie dane nie widzę, że nie ma nic złego pisząc to wszystko na raz, ale za to pytanie i odpowiedź ilustruje, write()nie musi to wszystko (co idzie do małych buforów zbyt) napisać
rury
8
„Mogę to naprawić przez zawijanie zapisu w pętli” i musisz to robić, niezależnie od SSIZE_MAXograniczeń. write()Spec mówi, że nie ma obowiązku, aby napisać cały bufor, nawet jeśli jest prawie zawsze. Kod bez pętli w pytaniu jest błędem.
Adam

Odpowiedzi:

50

Odpowiedź znajdziesz w man 2 write:

Nie jest błędem, jeśli liczba ta jest mniejsza niż liczba żądanych bajtów; może się to zdarzyć na przykład dlatego, że urządzenie dyskowe zostało zapełnione.


I z write()opisu strony man:

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

Zgodnie z POSIX.1, jeśli countjest większy niż SSIZE_MAX, wynik jest zdefiniowany w implementacji; patrz UWAGI na górny limit w systemie Linux.

UWAGI

W systemie Linux write()(i podobne wywołania systemowe) przesyła najwyżej 0x7ffff000(2 147 479 552) bajtów, zwracając liczbę faktycznie przesłanych bajtów. (Dotyczy to zarówno systemów 32-bitowych, jak i 64-bitowych.)

Bobah
źródło