2008-11-17 9 views
74

Wir hatten hier eine Diskussion darüber, warum fread und fwrite eine Größe pro Element annehmen und die Anzahl der gelesenen/geschriebenen Elemente zählen und zurückgeben, anstatt nur einen Puffer und eine Größe zu nehmen. Die einzige Verwendung dafür wäre, wenn Sie ein Array von Strukturen lesen/schreiben möchten, die nicht durch die Plattformausrichtung teilbar sind und daher gepolstert wurden, aber das kann nicht so üblich sein, um diese Wahl zu rechtfertigen im Design.Was ist der Grund dafür, dass fread/fwrite Größe und Argumente zählt?

Von FREAD (3):

Die Funktion fread() nmemb Elemente der Daten liest, lange jede Größe Bytes aus dem Strom, auf den Strom, so dass sie an der Stelle gegeben Speicherung von ptr.

Die Funktion fwrite() schreibt nmemb Elemente von Daten, die jeweils eine Größe Bytes lange, bis der Strom durch Strom zugespitzt, um sie von dem Ort gegeben durch PTR zu erhalten.

fred() 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 das Dateiende erreicht ist, ist der Rückgabewert eine kurze Elementanzahl (oder Null).

+9

hey das ist eine gute Frage. Ich habe mich immer gefragt –

+1

Bitte überprüfen Sie diesen Thread: http://StackOverflow.com/Questions/8589425/how-does-fread-really-work – Franken

Antwort

18

Es basiert darauf, wie fread implementiert ist.

Die Single UNIX Specification sagt

Für jedes Objekt Größe Anrufe werden werden zum fgetc() -Funktion und die Ergebnisse gespeichert sind, in der Reihenfolge gelesen, genau in ein Array von unsigned char gemacht überlagert das Objekt.

fgetc hat auch diese Notiz:

Seit fgetc() arbeitet auf Bytes, ein Zeichen zu lesen, bestehend aus mehreren Bytes (oder "ein Multi-Byte- Zeichen") können mehrere Anrufe erfordern zu fgetc().

Natürlich ist dies vor der Phantasie variable Byte-Zeichencodierungen wie UTF-8.

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

50

Der Unterschied in fread (buf, 1000, 1, Bach) und fread (buf, 1, 1000, Strom) ist, dass im ersten Fall nur ein Stück von 1000 Bytes oder nuthin erhalten, wenn die Datei ist kleiner und im zweiten Fall erhalten Sie alles in der Datei weniger als und bis zu 1000 Bytes.

+3

Obwohl wahr, das erzählt nur einen kleinen Teil der Geschichte. Es wäre besser, etwas zu kontrastieren, zum Beispiel ein Array von int-Werten oder ein Array von Strukturen. –

+2

Dies würde eine gute Antwort geben, wenn die Begründung abgeschlossen ist. –

+0

praktische Antwort. Danke – austin

3

Wahrscheinlich geht es zurück zu der Art, wie Datei-I/O implementiert wurde. (früher am Tag) Es wäre vielleicht schneller gewesen, in Blöcke zu schreiben/zu lesen und dann alles auf einmal zu schreiben.

+0

Nicht wirklich. Die C - Spezifikation für fwrite merkt an, dass es wiederholt Aufrufe an fputc macht: http://www.opengroup.org/onlinepubs/009695399/functions/fwrite.html – Powerlord

9

Hier, lassen Sie mich diese Funktionen beheben:

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

Was eine Begründung für die Parameter fread()/fwrite(), ich habe schon vor langer Zeit meine Kopie von K & R verloren, so kann ich nur raten. Ich denke, dass eine wahrscheinliche Antwort ist, dass Kernighan und Ritchie einfach gedacht haben, dass die Durchführung von binären I/O am natürlichsten auf Arrays von Objekten durchgeführt werden würde. Außerdem haben sie vielleicht gedacht, dass Block-I/O schneller/einfacher zu implementieren oder was auch immer auf einigen Architekturen sein könnte.

Auch wenn die C-Standard legt fest, dass fread() und fwrite() in Bezug auf fgetc() und fputc() umgesetzt werden, denken Sie daran, dass der Standard entstand lange nach C von K & R definiert wurde und dass die Dinge in der Norm festgelegten Umständen nicht gewesen sein in den ursprünglichen Designerideen. Es ist sogar möglich, dass Dinge, die in K & R "Die C-Programmiersprache" gesagt werden, möglicherweise nicht das gleiche wie wenn die Sprache zuerst entworfen wurde.

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

Wenn die size (zweite) Argument größer als eins ist, kann man nicht auch lesen bestimmen kann , ob die Funktion bis zu size - 1 zusätzliche Zeichen über was es berichtet. In der Regel sind Sie besser dran, die Funktion als fread(buf, 1, size * n, stream); Aufruf statt fread(buf, size, n, stream);

Bascially, er sagt, dass fread() ‚s-Schnittstelle ist gebrochen. Für fwrite() stellt er fest, dass "Schreibfehler im Allgemeinen selten sind, also ist dies kein großer Mangel" - eine Aussage, der ich nicht zustimmen würde.

+16

Eigentlich mag ich es oft andersrum: 'fread (buf, size * n, 1, stream); 'Wenn unvollständige Lesevorgänge eine Fehlerbedingung darstellen, ist es einfacher, dafür zu sorgen, dass' fread' einfach 0 oder 1 zurückgibt, anstatt die Anzahl der gelesenen Bytes. Dann können Sie Dinge wie 'if (! Fread (...))' tun, anstatt das Ergebnis mit der angeforderten Anzahl von Bytes vergleichen zu müssen (was zusätzlichen C-Code und zusätzlichen Maschinencode erfordert). –

12

Dies ist reine Spekulationen, aber zurück in den Tagen (einige sind immer noch) viele Dateisysteme waren nicht einfache Byte-Streams auf einer Festplatte.

Viele Dateisysteme basieren auf Datensätzen. Um solche Dateisysteme effizient zu bedienen, müssen Sie die Anzahl der Elemente ("Datensätze") angeben, damit fwrite/fread nicht als Datensätze auf dem Speicher arbeiten kann nur Byteströme.

+1

Ich bin froh, dass jemand das heraufgebracht hat. Ich habe viel mit Dateisystemspezifikationen gearbeitet und FTP und Datensätze/Seiten und andere Blockierungskonzepte werden sehr stark unterstützt, obwohl niemand diese Teile der Spezifikationen mehr verwendet. –

1

Ich denke, es ist, weil C Funktion Überladung fehlt. Wenn es welche gab, wäre die Größe überflüssig. Aber in C können Sie die Größe eines Array-Elements nicht bestimmen, Sie müssen eines angeben.

Bedenken Sie:

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

Aber es ist nur ineffizient:

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

Wenn Fwrite akzeptiert Anzahl von Bytes, wird die folgende schreiben konnte. Sie werden sizeof (int) mal mehr Systemaufrufe haben.

Ein weiterer Punkt, der in Betracht gezogen 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 erfolgreich geschriebenen Elementen zurück. Wenn Sie also feststellen, dass nur 2 niedrige Bytes eines Elements geschrieben sind, was würden Sie tun?

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