it-swarm.com.de

Was ist der Grund dafür, dass fread/fwrite Größe und Argumente berücksichtigt?

Wir haben hier bei der Arbeit eine Diskussion darüber geführt, warum fread und fwrite eine Größe pro Mitglied annehmen und zählen und die Anzahl der gelesenen/geschriebenen Mitglieder zurückgeben, anstatt nur einen Puffer und eine Größe zu nehmen. Der einzige Nutzen, den wir dafür finden könnten, ist, wenn Sie ein Array von Strukturen lesen/schreiben möchten, die durch die Plattformausrichtung nicht gleichmäßig teilbar sind und daher aufgefüllt wurden, aber dies kann nicht so üblich sein, dass diese Auswahl erforderlich ist im Design.

Von FREAD (3) :

Die Funktion fread () liest nmemb Datenelemente mit jeweils Bytes Länge aus dem Stream, auf den der Stream zeigt, und speichert sie an der angegebenen Stelle von ptr.

Die Funktion fwrite () schreibt nmemb Elemente der Daten mit Bytes jeder Größe long, auf den Stream, auf den der Stream zeigt, und erhalte sie von der Position gegeben durch ptr.

fread () und fwrite () geben die Anzahl der erfolgreich gelesenen oder geschriebenen Elemente zurück (d. h. nicht die Anzahl der Zeichen). Wenn ein Fehler auftritt oder die Ende der Datei erreicht ist, ist der Rückgabewert eine kurze Elementanzahl (oder Null).

81
David Holm

Es basiert darauf, wie fread implementiert wird.

Die Single UNIX-Spezifikation sagt

Größenaufrufe für jedes Objekt lauten gemacht für die fgetc () - Funktion und die Ergebnisse gespeichert in der Reihenfolge gelesen in ein Array von unsignierten Zeichen genau Überlagern des Objekts.

fgetc hat auch diesen Hinweis:

Da fgetc () für Bytes arbeitet, ist Lesen eines Zeichens bestehend aus Mehrere Bytes (oder "ein Multi-Byte-Zeichen ") erfordern möglicherweise mehrere Aufrufe zu fgetc ().

Natürlich geht dies vor fantastischen Zeichencodierungen mit variablen Bytes wie UTF-8 voran.

Die SUS stellt fest, dass dies tatsächlich aus den ISO-C-Dokumenten stammt.

18
Powerlord

Der Unterschied zwischen fread (buf, 1000, 1, stream) und fread (buf, 1, 1000, stream) besteht darin, dass Sie im ersten Fall nur einen Teil von 1000 Bytes oder nuthin erhalten Im zweiten Fall erhalten Sie alles in der Datei weniger als und bis zu 1000 Byte.

58
Peter Miehle

Dies ist eine reine Spekulation, jedoch waren einige Dateisysteme (in einigen Tagen noch immer) nur einfache Byte-Streams auf einer Festplatte. 

Viele Dateisysteme waren datensatzbasiert. Um solche Dateisysteme auf effiziente Weise zu erfüllen, müssen Sie die Anzahl der Elemente ("Datensätze") angeben, sodass fwrite/fread den Speicher als Datensätze und nicht nur als Byte-Streams verarbeiten kann.

12
nos

Hier, lassen Sie mich diese Funktionen korrigieren:

size_t fread_buf( void* ptr, size_t size, FILE* stream)
{
    return fread( ptr, 1, size, stream);
}


size_t fwrite_buf( void const* ptr, size_t size, FILE* stream)
{
    return fwrite( ptr, 1, size, stream);
}

Als Begründung für die Parameter zu fread()/fwrite() habe ich meine Kopie von K & R vor langer Zeit verloren, daher kann ich nur raten. Ich denke, dass eine wahrscheinliche Antwort ist, dass Kernighan und Ritchie einfach gedacht haben, dass das Durchführen von binären E/A am natürlichsten auf Arrays von Objekten erfolgen würde. Möglicherweise haben sie auch gedacht, dass Block-E/A auf einigen Architekturen schneller/einfacher zu implementieren sind oder was auch immer.

Auch wenn der C-Standard festlegt, dass fread() und fwrite() in Form von fgetc() und fputc() implementiert werden, darf nicht vergessen werden, dass der Standard lange nach der Definition von C durch K & R und entstanden ist dass die in der Norm spezifizierten Dinge möglicherweise nicht in den ursprünglichen Designideen enthalten waren. Es ist sogar möglich, dass die Aussagen in K & Rs "The C Programming Language" nicht mit denen übereinstimmen, als die Sprache zum ersten Mal entworfen wurde.

Schließlich ist hier, was P. J. Plauger über fread() in "The Standard C Library" zu sagen hat:

Wenn das (zweite) Argument size größer als eins ist, können Sie nicht feststellen, ob die Funktion zusätzlich zu den angegebenen Zeichen auch bis zu size - 1 zusätzliche Zeichen liest. In der Regel ist es besser, die Funktion als fread(buf, 1, size * n, stream); anstelle von fread(buf, size, n, stream); aufzurufen.

Grundsätzlich sagt er, dass die Benutzeroberfläche von fread() kaputt ist. Für fwrite() merkt er an, dass "Schreibfehler im Allgemeinen selten sind, das ist also kein großer Mangel" - eine Aussage, der ich nicht zustimmen würde.

9
Michael Burr

Wahrscheinlich geht es zurück auf die Art und Weise, wie die Datei-E/A implementiert wurde. (früher am Tag) Das Schreiben/Lesen in Dateien in Blöcken war möglicherweise schneller als das gleichzeitige Schreiben.

3
dolch

Ich denke, es liegt daran, dass C keine Überlastung der Funktion hat. Wenn es welche gäbe, wäre die Größe überflüssig. In C können Sie jedoch nicht die Größe eines Array-Elements bestimmen, sondern Sie müssen eines angeben.

Bedenken Sie:

int intArray[10];
fwrite(intArray, sizeof(int), 10, fd);

Wenn Sie die Anzahl der Bytes akzeptiert haben, können Sie Folgendes schreiben:

int intArray[10];
fwrite(intArray, sizeof(int)*10, fd);

Aber es ist einfach ineffizient. Sie erhalten sizeof (int) times mehr Systemaufrufe.

Ein weiterer Punkt, der berücksichtigt werden sollte, ist, dass Sie normalerweise nicht möchten, dass ein Teil eines Array-Elements in eine Datei geschrieben wird. Sie wollen die ganze Zahl oder nichts. fwrite gibt eine Anzahl von Elementen zurück, die erfolgreich geschrieben wurden. Wenn Sie also feststellen, dass nur 2 Byte eines Elements geschrieben werden, was würden Sie tun?

Auf einigen Systemen können Sie (aufgrund der Ausrichtung) nicht auf ein Byte einer Ganzzahl zugreifen, ohne eine Kopie zu erstellen und zu verschieben.

1
Vanuan

Separate Argumente für Größe und Anzahl können für eine Implementierung von Vorteil sein, die das Lesen von Teildatensätzen verhindert. Wenn man Single-Byte-Lesevorgänge von etwas wie einer Pipe verwenden würde, selbst wenn Daten mit festem Format verwendet würden, müsste man die Möglichkeit berücksichtigen, dass ein Datensatz auf zwei Lesevorgänge aufgeteilt wird. Wenn stattdessen z. Ein nicht blockierender Lesevorgang von bis zu 40 Datensätzen mit jeweils 10 Bytes, wenn 293 Bytes verfügbar sind. Das System muss 290 Bytes (29 ganze Datensätze) zurückgeben, während 3 Bytes für den nächsten Lesevorgang bereitstehen. Dies wäre viel praktischer.

Ich weiß nicht, inwieweit Implementierungen von Fread mit solchen Semantiken umgehen können, aber sie könnten sicherlich hilfreich bei Implementierungen sein, die sie unterstützen könnten.

0
supercat