Wir hatten hier bei der Arbeit eine Diskussion darüber, warum fread und fwrite eine Größe pro Mitglied annehmen und die Anzahl der gelesenen / geschriebenen Mitglieder zählen und zurückgeben, anstatt nur einen Puffer und eine Größe zu nehmen. Die einzige Verwendung, die wir finden könnten, ist, wenn Sie ein Array von Strukturen lesen / schreiben möchten, die nicht gleichmäßig durch die Plattformausrichtung teilbar sind und daher aufgefüllt wurden, aber dies kann nicht so häufig sein, dass diese Auswahl gerechtfertigt ist im Design.
Aus FREAD (3) :
Die Funktion fread () liest nmemb-Datenelemente mit einer Größe von jeweils Bytes aus dem Stream, auf den der Stream zeigt, und speichert sie an der von ptr angegebenen Stelle.
Die Funktion fwrite () schreibt nmemb-Datenelemente mit einer Größe von jeweils Byte in den Stream, auf den der Stream zeigt, und erhält sie von der durch ptr angegebenen Position.
fread () und fwrite () geben die Anzahl der erfolgreich gelesenen oder geschriebenen Elemente zurück (dh nicht die Anzahl der Zeichen). Wenn ein Fehler auftritt oder das Dateiende erreicht ist, ist der Rückgabewert eine kurze Anzahl von Elementen (oder Null).
Antworten:
Es basiert darauf, wie Fread implementiert wird.
Die Single UNIX-Spezifikation besagt
fgetc hat auch diesen Hinweis:
Dies geht natürlich auf ausgefallene Zeichencodierungen mit variablen Bytes wie UTF-8 zurück.
Die SUS stellt fest, dass dies tatsächlich den ISO C-Dokumenten entnommen ist.
quelle
Der Unterschied zwischen fread (buf, 1000, 1, stream) und fread (buf, 1, 1000, stream) besteht darin, dass Sie im ersten Fall nur einen Block von 1000 Bytes oder nuthin erhalten, wenn die Datei kleiner ist und in der Im zweiten Fall erhalten Sie alles in der Datei mit weniger als und bis zu 1000 Byte.
quelle
Dies ist reine Spekulation, aber in den Tagen (einige gibt es noch) waren viele Dateisysteme keine einfachen Byte-Streams auf einer Festplatte.
Viele Dateisysteme waren auf Datensätzen basierend. Um solche Dateisysteme auf effiziente Weise zu erfüllen, müssen Sie die Anzahl der Elemente ("Datensätze") angeben, damit fwrite / fread den Speicher als Datensätze und nicht nur als Byte-Streams bearbeiten kann.
quelle
Lassen Sie mich hier diese Funktionen korrigieren:
Als Begründung für die Parameter zu
fread()
/fwrite()
habe ich meine Kopie von K & R vor langer Zeit verloren, sodass ich nur raten kann. Ich denke, dass eine wahrscheinliche Antwort darin besteht, dass Kernighan und Ritchie einfach gedacht haben, dass das Ausführen von binären E / A am natürlichsten für 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 dies spezifiziert
fread()
undfwrite()
in Bezug auffgetc()
und implementiert werden sollfputc()
, denken Sie daran, dass der Standard lange nach der Definition von C durch K & R entstanden ist und dass die im Standard angegebenen Dinge möglicherweise nicht in den ursprünglichen Designerideen 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.Zum Schluss sagt PJ Plauger
fread()
in "The Standard C Library" Folgendes :Grundsätzlich sagt er, dass
fread()
die Benutzeroberfläche defekt ist. Dennfwrite()
er merkt an, dass "Schreibfehler im Allgemeinen selten sind, daher ist dies kein großes Manko" - eine Aussage, der ich nicht zustimmen würde.quelle
fread(buf, size*n, 1, stream);
Wenn unvollständige Lesevorgänge eine Fehlerbedingung sind, ist es einfacherfread
, einfach 0 oder 1 zurückzugeben, als die Anzahl der gelesenen Bytes. Dann können Sie beispielsweiseif (!fread(...))
das Ergebnis mit der angeforderten Anzahl von Bytes vergleichen (was zusätzlichen C-Code und zusätzlichen Maschinencode erfordert).Wahrscheinlich geht es auf die Art und Weise zurück, wie Datei-E / A implementiert wurde. (damals) Es war möglicherweise schneller, in Blöcken in Dateien zu schreiben / zu lesen, als alles auf einmal zu schreiben.
quelle
Bei einer Implementierung, bei der das Lesen von Teildatensätzen vermieden werden kann, kann es vorteilhaft sein, separate Argumente für Größe und Anzahl zu haben. Wenn man Einzelbyte-Lesevorgänge aus einer Pipe verwenden würde, selbst wenn man Daten mit festem Format verwenden würde, müsste man die Möglichkeit berücksichtigen, dass ein Datensatz auf zwei Lesevorgänge aufgeteilt wird. Wenn stattdessen z. B. ein nicht blockierender Lesevorgang von bis zu 40 Datensätzen mit jeweils 10 Bytes angefordert werden könnte, wenn 293 Bytes verfügbar sind, und das System 290 Bytes (29 ganze Datensätze) zurückgeben könnte, während 3 Bytes für den nächsten Lesevorgang bereit bleiben, wäre dies der Fall viel bequemer sein.
Ich weiß nicht, inwieweit Implementierungen von fread mit einer solchen Semantik umgehen können, aber sie könnten sicherlich bei Implementierungen nützlich sein, die versprechen, sie zu unterstützen.
quelle
fread(buffer, 10000, 2, stdin)
und der Benutzer nach Eingabe von 18.000 Bytes newline-ctrl-D eingibt, wäre es schön, wenn die Funktion die ersten 10.000 Bytes zurückgeben könnte, während die verbleibenden 8.000 für zukünftige kleinere Leseanforderungen ausstehen, aber vorhanden sind Gibt es Implementierungen, bei denen dies passieren würde? Wo würden die 8.000 Bytes bis zu diesen zukünftigen Anforderungen gespeichert?size
mehr als 1 verwenden, na ja ... Für den Datensatz gibt es möglicherweise auch Ioctls oder anderen Unsinn, den Sie auf den Stream anwenden können, um ihn zu erstellen benimm dich anders, ich habe mich nicht so tief damit beschäftigt.fread
Arbeit, wie Sie sie für solche Streams beschrieben haben, wäre nützlich, wenn es eine Möglichkeit gäbe, Streams zu identifizieren, die auf diese Weise funktionieren.Ich denke, das liegt daran, dass C keine Funktionsüberladung aufweist. Wenn es welche gäbe, wäre die Größe überflüssig. In C können Sie jedoch keine Größe eines Array-Elements bestimmen, sondern müssen eine angeben.
Bedenken Sie:
Wenn fwrite die Anzahl der Bytes akzeptiert, können Sie Folgendes schreiben:
Aber es ist einfach ineffizient. Sie haben eine Größe von (int) mal mehr Systemaufrufen.
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 ganze Zahl oder nichts. fwrite gibt eine Reihe von Elementen zurück, die erfolgreich geschrieben wurden. Was würden Sie tun, wenn Sie feststellen, dass nur 2 niedrige Bytes eines Elements geschrieben sind?
Auf einigen Systemen (aufgrund der Ausrichtung) können Sie nicht auf ein Byte einer Ganzzahl zugreifen, ohne eine Kopie zu erstellen und zu verschieben.
quelle