Sind Sie immer noch beunruhigt über die Eingabe jedes Mal, wenn Sie das Programm öffnen? Dieser Artikel wird Sie nicht verwirren

In den Programmen, die wir zuvor geschrieben haben, müssen wir immer einige Daten eingeben, die das Programm zur Berechnung verwenden soll. Wenn wir das Programm jedoch verlassen, werden die eingegebenen Daten zerstört, da die Daten zu diesem Zeitpunkt im Speicher gespeichert sind. Wenn das Programm das nächste Mal ausgeführt wird, müssen die Daten erneut eingegeben werden, was sehr unangenehm ist.

Wir müssen uns eine Möglichkeit überlegen, die eingegebenen Daten dauerhaft zu machen. Zu diesem Zeitpunkt kann ich Dateioperationen verwenden, um die eingegebenen Daten in der Datei zu speichern, sodass die eingegebenen Daten bis zum nächsten Mal beibehalten werden können. Sie können sie weiterhin verwenden Die Daten in der Datei nach dem Öffnen des Programms, sehr einfach zu bedienen! ! !

Schauen wir uns die Dateien genauer an.

Inhaltsverzeichnis

Was ist eine Datei?

 Programmdateien 

 Datendatei

Dateiname

Öffnen und Schließen von Dateien 

Dateizeiger

 Öffnen und Schließen von Dateien

Sequentielles Lesen und Schreiben von Dateien

Einführung in sequentielle Lese- und Schreibfunktionen

 Zufälliges Lesen und Schreiben von Dateien

fseek-Funktion

ftell-Funktion

​Rücklauffunktion bearbeiten

 Textdateien und Binärdateien

 Urteil über das Ende der Aktenlesung

 missbrauchte Feof-Funktion

Dateipuffer


Was ist eine Datei?

Dateien auf der Festplatte sind Dateien. Beim Programmdesign sprechen wir jedoch im Allgemeinen von zwei Arten von Dateien: Programmdateien und Datendateien (klassifiziert aus der Perspektive der Dateifunktionen).

 Programmdateien 

Einschließlich Quellprogrammdatei (Suffix .c), Objektdatei (Windows-Umgebungssuffix .obj), ausführbares Programm (Windows-Umgebungssuffix .exe).

 Datendatei

Der Inhalt der Datei ist nicht unbedingt das Programm, sondern die Daten, die beim Ausführen des Programms gelesen und geschrieben werden, z. B. die Datei, aus der das Programm Daten lesen muss, oder die Datei, die den Inhalt ausgibt.

In diesem Blog sprechen wir über Datendateien 

Im vorherigen Inhalt basiert die gesamte Ausgabe und Eingabe unserer Verarbeitungsdaten auf dem Terminal, dh die Tastatur des Terminals gibt Daten ein und das Operationsergebnis wird auf dem Bildschirm ausgegeben. Tatsächlich geben wir manchmal die Informationen auf die Festplatte aus und lesen dann die Daten von der Festplatte in den Speicher, um sie bei Bedarf zu verwenden. Wir beschäftigen uns hier mit der Datei auf der Festplatte.

Dateiname

Eine Datei muss über eine eindeutige Dateikennung zur Benutzeridentifizierung und -referenz verfügen.

Der Dateiname besteht aus 3 Teilen: Dateipfad + Dateiname Stamm + Dateisuffix

Beispiel: c:\code\test.txt 

Unter normalen Umständen ist der Dateiname unter demselben Pfad eindeutig und kann nicht wiederholt werden!

Der Einfachheit halber wird die Datei-ID oft als Dateiname bezeichnet .

Öffnen und Schließen von Dateien 


Dateizeiger

Im Cache-Dateisystem ist das Schlüsselkonzept „ Dateitypzeiger “, der als „ Dateizeigerbezeichnet wird .

Jede verwendete Datei hat einen entsprechenden Dateiinformationsbereich im Speicher geöffnet, in dem die relevanten Informationen der Datei gespeichert werden (z. B. der Name der Datei, der Status der Datei und der aktuelle Speicherort der Datei usw.). ). Diese Informationen werden in einer Strukturvariablen gespeichert. Der Strukturtyp wird vom System mit dem Namen FILE deklariert.

Beispielsweise verfügt die von der VS2013-Kompilierungsumgebung bereitgestellte Headerdatei stdio.h über die folgende Dateitypdeklaration:

struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
       };
typedef struct _iobuf FILE;

 Der Inhalt des FILE-Typs verschiedener C-Compiler ist nicht genau gleich, aber ähnlich. Immer wenn eine Datei geöffnet wird, erstellt das System automatisch eine Variable der FILE-Struktur entsprechend der Situation der Datei und gibt die Informationen ein, ohne dass sich der Benutzer um die Details kümmern muss. Im Allgemeinen werden die Variablen dieser FILE-Struktur über einen FILE-Zeiger verwaltet, was bequemer zu verwenden ist. Nachfolgend können wir eine FILE*-Zeigervariable erstellen: 

 FILE* pf;//Dateizeigervariable

Definieren Sie pf als Zeigervariable, die auf Daten vom Typ FILE zeigt. Sie können pf auf den Dateiinformationsbereich einer bestimmten Datei verweisen lassen (es handelt sich um eine Strukturvariable). Auf die Datei kann über die Informationen im Dateiinformationsbereich zugegriffen werden. Das heißt, die zugehörige Datei kann über die Dateizeigervariable gefunden werden. 

 Öffnen und Schließen von Dateien

Dateien sollten vor dem Lesen und Schreiben geöffnet und nach der Verwendung geschlossen werden .

Beim Schreiben eines Programms wird beim Öffnen einer Datei eine Zeigervariable FILE* zurückgegeben, die auf die Datei zeigt, was dem Herstellen einer Beziehung zwischen dem Zeiger und der Datei entspricht.

 ANSIC schreibt vor, dass die Funktion fopen zum Öffnen der Datei und die Funktion fclose zum Schließen der Datei verwendet wird.

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

Der erste Parameter in der Funktion fopen ist sehr offensichtlich: Er erstellt einen Dateinamen, der im Allgemeinen durch eine Zeichenfolge dargestellt wird. Aber was bedeutet der zweite Parameter? Dies entspricht der Art und Weise, wie die Datei geöffnet wird. Öffnen Sie wie folgt:

Dateinutzung Bedeutung Wenn die angegebene Datei nicht existiert
„r“ (schreibgeschützt) Um Daten einzugeben, öffnen Sie eine vorhandene Textdatei schief gehen
„w“ (nur Schreiben) Um Daten auszugeben, öffnen Sie eine Textdatei eine neue Datei erstellen
„a“ (anhängen) Fügen Sie Daten am Ende der Textdatei hinzu eine neue Datei erstellen
„rb“ (schreibgeschützt) Um Daten einzugeben, öffnen Sie eine Binärdatei schief gehen
„wb“ (nur Schreiben) Um Daten auszugeben, öffnen Sie eine Binärdatei eine neue Datei erstellen
„ab“ (anhängen) Daten an das Ende einer Binärdatei anhängen eine neue Datei erstellen
„r+“ (lesen und schreiben) Öffnen Sie eine Textdatei zum Lesen und Schreiben schief gehen
„w+“ (lesen und schreiben) Schlagen Sie zum Lesen und Schreiben eine neue Datei vor eine neue Datei erstellen
„a+“ (lesen und schreiben) Öffnen Sie eine Datei zum Lesen und Schreiben am Ende der Datei eine neue Datei erstellen
„rb+“ (lesen und schreiben) Öffnen Sie eine Binärdatei zum Lesen und Schreiben schief gehen
„wb+“ (lesen und schreiben) Erstellen Sie eine neue Binärdatei zum Lesen und Schreiben eine neue Datei erstellen
„ab+“ (lesen und schreiben) Öffnen Sie eine Binärdatei zum Lesen und Schreiben am Ende der Datei eine neue Datei erstellen

Nachfolgend verwenden wir:

#include<stdio.h>

int main()
{
	FILE* fp = fopen("data.txt", "r");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	//关闭文件
	return 0;
}

Im aktuellen Pfad öffnen wir die Datei data.txt im schreibgeschützten Format „r“. Aber wir haben in diesem Pfad keine data.txt-Datei erstellt, daher erhält FILE*fp einen Nullzeiger. Wir verwenden if zur Beurteilung und verwenden die perror-Funktion zum Drucken des Fehlers. Wir können sehen: Aber wenn wir in diesem Pfad erstellen  Pfad Was passiert, wenn eine Datei wieder schreibgeschützt geöffnet wird?  Der Code meldet keinen Fehler und läuft normal. 

#include<stdio.h>

int main()
{
	FILE* fp = fopen("data.txt", "w");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	//关闭文件
	return 0;
}

Wir behalten den Code unverändert bei, ändern aber den schreibgeschützten Modus in den schreibgeschützten Modus. Wenn keine solche Datei im Pfad vorhanden ist, wird eine neue Datei erstellt.

Und das Schließen der Datei ist sehr einfach. Verwenden Sie einfach die Funktion fclose, um den Dateizeiger darauf zu platzieren. Vergessen Sie nicht, den Zeiger nach dem Schließen der Datei auf einen Nullzeiger zu setzen.

#include<stdio.h>

int main()
{
	FILE* fp = fopen("data.txt", "w");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	//关闭文件
    fclose(fp);
    fp = NULL;
	return 0;
}

 Wie sollen wir also Dateien lesen und schreiben? Hier gibt es zwei Möglichkeiten: 1. Sequentielles Lesen und Schreiben 2. Zufälliges Lesen und Schreiben.

Sequentielles Lesen und Schreiben von Dateien

Einführung in sequentielle Lese- und Schreibfunktionen

Warum öffnet die Scanf-Funktion, die wir zuvor verwendet haben, nicht den Standard-Eingabestream und den Standard-Ausgabestream? Geben Sie einfach den gewünschten Inhalt direkt in die Funktion ein und geben Sie ihn aus. Denn solange das C-Sprachprogramm läuft, werden standardmäßig 3 Streams geöffnet. Der Standardausgabestream stdin, der Standardausgabestream stdout und der Standardfehlerstream strerr. Wir müssen es also nicht erneut öffnen, aber der Datenstrom muss für die Dateieingabe und -ausgabe geöffnet werden.

Lassen Sie uns die oben genannten Funktionen einzeln erklären:

Die Funktionen fgetc und fputc gelten für alle Eingabe- und Ausgabestreams. Wir können sowohl Standard-Eingabe- und Ausgabestreams als auch Dateien verwenden.

 fputc verwendet das gewünschte Zeichen als Parameter und der folgende Parameter ist ein Dateizeiger, der auf die zu schreibende Datei zeigt. Wenn wir auf dem Bildschirm ausgeben möchten, können wir stdout verwenden.

#include<stdio.h>

int main()
{
	FILE* fp = fopen("data.txt", "w");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	fputc('w', fp);
	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

Wir geben das W-Zeichen in die Datei data.txt ein. Wir können diese Datei im selben Pfad finden, um den Inhalt zu sehen:

Auf diese Weise können wir den Inhalt in die Datei eingeben. Jetzt möchten wir den Inhalt der Datei lesen und müssen nur noch die Funktion fgetc verwenden, um den Dateizeiger anzugeben.

int main()
{
	FILE* fp = fopen("data.txt", "w");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	for (int i = 0; i < 3; i++)
	{
		fputc('a' + i, fp);
	}
	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

Wir können die for-Schleife verwenden, um abc kontinuierlich einzugeben.

Dies ist sequentielles Lesen und Schreiben.

Die Funktion fgetc ist die Funktion, die den Inhalt der Datei liest. Der Rückgabewert ist die Anzahl der jedes Mal gelesenen Inhalte.

int main()
{
	FILE* fp = fopen("data.txt", "r");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	for (int i = 0; i < 3; i++)
	{
		int ch = fgetc(fp);
		printf("%c ", ch);
	}
	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

 Der gerade in der Datei data.txt gespeicherte Inhalt ist abc, und das Lesen von fgetc ist ebenfalls ein sequentielles Lesen. Wir können den Inhalt aus der Datei lesen, indem wir die for-Schleife zum dreimaligen Lesen verwenden.

Als nächstes folgen die Textzeilen-Eingabe- und Ausgabefunktionen fgets, fputs. Sie gelten auch für alle Eingabe- und Ausgabeströme.

 Die Funktion fputs ähnelt der Funktion fputc, außer dass der erste Parameter eine Zeichenfolge ist. Die zweite Datei ist der Zeiger auf den Speicherort, den Sie eingeben möchten. Dabei kann es sich entweder um die Bildschirm-Standardausgabe oder eine Datei handeln.

int main()
{
	FILE* fp = fopen("data.txt", "w");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fputs("hello world", fp);
	fputs("hehe", fp);
	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

 Wir geben die beiden Zeichenfolgen „Hallo Welt“ und „Hehe“ in die Datei „data.txt“ ein. Werden diese beiden Zeichenfolgen also in einer oder zwei Zeilen in der Datei platziert?

Es wird in einer Zeile platziert, daher müssen wir ein Zeilenumbruchzeichen \n hinzufügen, wenn wir die Zeile ändern möchten.

int main()
{
	FILE* fp = fopen("data.txt", "w");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	fputs("hello world", stdout);
	fputs("hehe", stdout);
	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

Wenn wir den zweiten Parameter von fputs als stdout schreiben, wird die Funktion zur Standardeingabe, die auf dem Bildschirm ausgegeben wird.

Parameter der fgets-Funktion:  Die allgemeine Funktion liest den zweiten Parameter num-1 Zeichen oder stoppt vorzeitig, wenn sie auf \n trifft.

int main()
{
	FILE* fp = fopen("data.txt", "r");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	char arr[10] = { 0 };
	fgets(arr, 10, pf);
	printf("%s", arr);
    fgets(arr, 10, fp);
	printf("%s", arr);
	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

 Die Datei data.txt enthält die Zeichenfolge hello worldhehexxxxxxxxxx. Jetzt lesen wir 10-1 Zeichen aus der Datei, fügen sie in das erstellte Zeichenarray ein und geben sie dann auf dem Bildschirm aus:

Lesen Sie nur 9 Zeichen und beenden Sie die Zeichenfolge mit \0 am Ende.

Wenn wir einmal lesen:

Es werden weiterhin 9 Zeichen am Ende des gerade gelesenen Zeichens gelesen und dann am Ende \0 hinzugefügt.

Die beiden eben genannten Funktionen sind sehr eingeschränkt und können Inhalte nur in einem Format schreiben. Die Funktionen fscanf und fprintf können jedoch alle Daten im Format ein- und ausgeben.

Lassen Sie uns diese beiden Funktionen verstehen:

 Tatsächlich gibt es zwischen diesen beiden Funktionen und printf und scanf nur einen Unterschied, nämlich einen Dateizeigerparameter. Erklären Sie, dass diese beiden Funktionen auch für alle Streams gelten.

struct S
{
	int a;
	float s;
};

int main()
{
	FILE* fp = fopen("data.txt", "w");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件
	struct S s = { 100,3.14f };
	fprintf(fp, "%d, %f", s.a, s.s);

	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

 Wir erstellen eine Struktur mit Mitgliedern eines int-Typs und eines float-Typs. Wir möchten den Inhalt der Struktur in die Datei schreiben und verwenden fprintf für den Betrieb (ähnlich wie printf, fügen Sie einfach einen Dateizeiger voran).

Dann können wir den Text lesen:

Wir können auch den Inhalt der Datei lesen:

int main()
{
	FILE* fp = fopen("data.txt", "r");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	struct S s = { 0 };
	fscanf(fp, "%d, %f", &(s.a), &(s.s));
	printf("%d %f\n", s.a, s.s);
	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

Nachdem wir die gerade eingegebenen Daten beibehalten haben, verwenden wir die Funktion fscanf, um sie aus der Datei in unsere Struktur einzulesen, und drucken dann die Strukturelemente aus, um die Antwort zu erhalten.

  

scanf: Formatierte Daten aus dem Standardeingabestream lesen.

printf: Schreibt formatierte Daten in den Standardausgabestream.

fscanf: formatierte Eingabefunktion für alle Eingabestreams

fprintf: formatierte Ausgabefunktion für alle Ausgabestreams

Es gibt auch zwei Funktionen, die scanf und printf sehr ähnlich sind: sscanf und sprintf. Wozu dienen diese beiden Funktionen?

Diese beiden Funktionen fügen die formatierten Daten in die Zeichenfolge ein und extrahieren die formatierten Daten aus der Zeichenfolge.

 sscanf: Formatierte Daten aus einem String lesen

sprintf: Konvertiert formatierte Daten in Strings

Wir können den Dateizeiger in einen Array-Zeiger umwandeln, ähnlich den Funktionen fprintf und fscanf, damit jeder sie unterscheiden und nicht verwechseln kann.

 Binärer Ein- und Ausgang

Suchen Sie ausgehend von der Position ptr nach Inhaltsteilen mit einer Größe von size bytes und fügen Sie sie in den Dateistream ein.

struct S
{
	int a;
	float s;
	char str[10];
};

int main()
{
	FILE* fp = fopen("data.txt", "wb");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	struct S s = { 100,3.14f,"world"};
	fwrite(&s, sizeof(struct S),1,fp);

	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

 Bei Verwendung der Binärausgabe sollte die Datei mit „wb“ im Binärformat geöffnet werden. Verwenden Sie fwrite, um den Inhalt von Strukturmitgliedern in binärer Form in Text zu schreiben.

Der binär geschriebene Inhalt ist im Allgemeinen unverständlich. 

 Die fread-Funktion hat die gleichen Parameter wie die fwrite-Funktion und bewirkt genau das Gegenteil.

Suchen Sie den Inhalt von count size in der Datei und fügen Sie ihn in str ein.

struct S
{
	int a;
	float s;
	char str[10];
};

int main()
{
	FILE* fp = fopen("data.txt", "rb");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	struct S s = { 0 };
	fread(&s, sizeof(struct S), 1, fp);
	printf("%d %f %s\n", s.a, s.s, s.str);
	//关闭文件
	fclose(fp);
	fp = NULL;
	return 0;
}

Verwenden Sie den binären Lesemodus, um den Inhalt des Textes in die Struktur einzulesen und ihn dann auszudrucken.

 Zufälliges Lesen und Schreiben von Dateien

fseek-Funktion

Positioniert den Dateizeiger basierend auf der Position und dem Offset des Dateizeigers.

 Unter der Annahme, dass abcdefghi in die Datei eingefügt wird und wir das f-Zeichen lesen möchten, verwenden wir die Funktion fseek, um den Dateizeiger anzugeben, der Offset ist 5 und der letzte wird vom Anfang der Datei gelesen: SEEK_SET.

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror(fopen);
		return 1;
	}
	//读文件
	//定位文件指针到f
	fseek(pf, 5, SEEK_SET);
	int ch = fgetc(pf);
	printf("%c\n", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

 Wir können das f-Zeichen in der Datei lesen.

Wenn wir das f-Zeichen vom Ende der Datei lesen möchten, müssen wir nur den Offset-Parameter in der fseek-Funktion durch -4 ersetzen und vom Ende der Datei lesen: SEEK_END.

fseek(pf,-4,SEEK_END);

Wenn wir zuerst drei Zeichen abc drucken und dann a drucken möchten, können wir fseek(pf,-3,SEEK_CUR);

ftell-Funktion

Gibt den Offset des Dateizeigers relativ zur Startposition zurück.

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror(fopen);
		return 1;
	}
	//读文件
	int ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	int pos = ftell(pf);
	printf("%d\n", pos);
	fclose(pf);
	pf = NULL;
	return 0;
}

Wenn die Funktion fgetc verwendet wird, um den Inhalt der Datei dreimal zu drucken, kann die Funktion ftell verwendet werden, um zu ermitteln, dass der Versatz zwischen der aktuellen Position der Datei und der Position des ersten Elements 3 beträgt. 

 Rückspulfunktion

Gibt die Position des Dateizeigers an den Anfang der Datei zurück.

Wenn wir den Dateizeiger verwenden und der Dateizeiger einen Offset relativ zum ersten Element hat, verwenden Sie die Rückspulfunktion, um den Dateizeiger zum Anfang zurückkehren zu lassen.

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror(fopen);
		return 1;
	}
	//读文件
	int ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	ch = fgetc(pf);
	printf("%c\n", ch);
	rewind(pf);
	ch = fgetc(pf);
	printf("%c\n", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

 Textdateien und Binärdateien

Je nachdem, wie die Daten organisiert sind, werden Datendateien als Textdateien oder Binärdateien bezeichnet .

Daten werden in binärer Form im Speicher gespeichert. Wenn sie ohne Konvertierung an einen externen Speicher ausgegeben werden, handelt es sich um eine Binärdatei .

Wenn es in Form eines ASCII-Codes auf dem externen Speicher gespeichert werden soll, muss es vor der Speicherung konvertiert werden. Eine in Form von ASCII-Zeichen gespeicherte Datei ist eine Textdatei .

Wie werden Daten im Speicher gespeichert?

Alle Zeichen werden im ASCII-Format gespeichert und numerische Daten können entweder im ASCII- oder Binärformat gespeichert werden. Wenn es beispielsweise eine Ganzzahl 10000 gibt und diese in Form eines ASCII-Codes auf die Festplatte ausgegeben wird, belegt sie 5 Bytes (ein Byte für jedes Zeichen) auf der Festplatte, und wenn sie in binärer Form ausgegeben wird, belegt sie 5 Bytes (ein Byte für jedes Zeichen) auf der Festplatte belegt nur 4 Bytes auf der Festplatte.

 Urteil über das Ende der Aktenlesung

 missbrauchte Feof-Funktion

Beachten Sie: Während des Dateilesevorgangs kann der Rückgabewert der feof-Funktion nicht verwendet werden, um direkt zu bestimmen, ob die Datei beendet ist.

Die Funktion von feof besteht darin: Wenn das Lesen der Datei endet, beurteilen Sie, ob der Grund für das Ende des Lesens darin besteht, dass das Ende der Datei erreicht ist.

 1. Beurteilen Sie, ob das Lesen der Textdatei abgeschlossen ist, ob der Rückgabewert EOF (fgetc) oder NULL (fgets) ist.

Beispiel: fgetc beurteilt, ob es EOF ist. fgets beurteilt, ob der Rückgabewert NULL ist.

2. Beurteilen Sie das Ende des Lesens der Binärdatei und beurteilen Sie, ob der Rückgabewert kleiner als die tatsächlich zu lesende Zahl ist.

Beispiel: fread beurteilt, ob der Rückgabewert kleiner als die tatsächlich zu lesende Zahl ist. Richtige Benutzung:

Beispiel einer Textdatei:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int c; // 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) {
        perror("File opening failed");
        return EXIT_FAILURE;
   }
 //fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
    while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环
   {
       putchar(c);
   }
//判断是什么原因结束的
    if (ferror(fp))
        puts("I/O error when reading");
    else if (feof(fp))
        puts("End of file reached successfully");
    fclose(fp);
}

Beispiel einer Binärdatei:

#include <stdio.h>
enum { SIZE = 5 };
int main(void)
{
    double a[SIZE] = {1.,2.,3.,4.,5.};
    FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
    fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
    fclose(fp);
    double b[SIZE];
    fp = fopen("test.bin","rb");
    size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
    if(ret_code == SIZE) {
        puts("Array read successfully, contents: ");
        for(int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
        putchar('\n');
   } else { // error handling
       if (feof(fp))
          printf("Error reading test.bin: unexpected end of file\n");
       else if (ferror(fp)) {
           perror("Error reading test.bin");
       }
   }
    fclose(fp);
}

Dateipuffer

Der ANSIC-Standard verwendet das „ Pufferdateisystem “ zur Verarbeitung von Datendateien. Das sogenannte Pufferdateisystem bedeutet, dass das System für jede im Programm verwendete Datei automatisch einen „ Dateipuffer “ im Speicher erstellt. Die vom Speicher auf die Festplatte ausgegebenen Daten werden zuerst an den Puffer im Speicher gesendet und dann zusammen an die Festplatte gesendet, nachdem der Puffer gefüllt ist. Wenn Daten von der Festplatte zum Computer gelesen werden, werden die aus der Festplattendatei gelesenen Daten in den Speicherpuffer eingegeben (voller Puffer) und dann werden die Daten vom Puffer an den Programmdatenbereich (Programmvariablen usw.) gesendet .) Einer nach dem anderen. Die Größe des Puffers wird durch das C-Kompilierungssystem bestimmt.

#include <stdio.h>
#include <windows.h>
int main()
{
 FILE*pf = fopen("test.txt", "w");
 fputs("abcdef", pf);//先将代码放在输出缓冲区
 printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
 Sleep(10000);
 printf("刷新缓冲区\n");
 fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
 //注:fflush 在高版本的VS上不能使用了
 printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
 Sleep(10000);
 fclose(pf);
 //注:fclose在关闭文件的时候,也会刷新缓冲区
 pf = NULL;
 return 0;
}

 Hier kann eine Schlussfolgerung gezogen werden: Aufgrund der Existenz des Puffers muss die C-Sprache beim Bearbeiten der Datei den Puffer aktualisieren oder die Datei am Ende des Dateivorgangs schließen.

Andernfalls kann es zu Problemen beim Lesen und Schreiben von Dateien kommen.

Ich denke du magst

Origin blog.csdn.net/m0_74755811/article/details/131892565
Empfohlen
Rangfolge