[Lenguaje C] Explicación detallada de las operaciones de archivos

Tabla de contenido

1. ¿Por qué utilizar archivos?

2. ¿Qué es un archivo?

        1. Archivos de programa

        2. Archivos de datos

        3. Nombre del archivo

3. Abrir y cerrar archivos

        1. puntero de archivo

        2. Abrir y cerrar archivos

4. Lectura y escritura secuencial de archivos.

        1. Introducción a las funciones de lectura y escritura secuenciales.

        2. Función de salida de caracteres fputc

        3. Función de entrada de caracteres fgetc

        4. Entradas de función de salida de línea de texto

        5. Función de entrada de línea de texto fgets

        6. Función de salida formateada fprintf

        7. Función de entrada formateada fscanf

        8. Escritura de salida binaria

        9. Entrada binaria

        10, ​​​​​​sprintf

        11,sscanf

5. Lectura y escritura aleatoria de archivos.

        1, buscar

        2, contar

        3, rebobinar

6. Archivos de texto y archivos binarios.

7. Determinación del final de la lectura del archivo.

        1. Fefo se utiliza incorrectamente

8. Búfer de archivos


1. ¿Por qué utilizar archivos?

Cuando estudiamos la estructura anteriormente, escribimos el programa de libreta de direcciones. Cuando la libreta de direcciones se está ejecutando, podemos agregar y eliminar datos a la libreta de direcciones. En este momento, los datos se almacenan en la memoria;

Cuando el programa se cierra, los datos en la libreta de direcciones naturalmente ya no existirán. La próxima vez que ejecute el programa de la libreta de direcciones, deberá volver a ingresar los datos. Será muy incómodo usar dicha libreta de direcciones;

Estamos pensando que al ser una libreta de direcciones la información se debe registrar, solo cuando decidamos borrar los datos los datos ya no existirán;

Esto implica la cuestión de la persistencia de los datos. Nuestros métodos generales de persistencia de datos incluyen almacenar datos en archivos de disco, almacenar datos en bases de datos, etc.;

Utilizando archivos podemos almacenar datos directamente en el disco duro del ordenador, logrando la persistencia de los datos.

 

2. ¿Qué es un archivo?

Los archivos en el disco son archivos. Pero en programación, generalmente hablamos de dos tipos de archivos: archivos de programa y archivos de datos (clasificados desde la perspectiva de la función del archivo).

        1. Archivos de programa

Incluyendo archivos de programa fuente (sufijo .c), archivos de destino (sufijo .obj en entorno Windows) y programas ejecutables (sufijo .exe en entorno Windows).

        2. Archivos de datos

El contenido del archivo no es necesariamente el programa, sino los datos leídos y escritos cuando el programa se está ejecutando, como el archivo del que el programa necesita leer datos o el archivo que genera el contenido.

Este capítulo analiza los archivos de datos. La entrada y salida de los datos procesados ​​en los capítulos anteriores están dirigidas al terminal, es decir, los datos se ingresan desde el teclado del terminal y los resultados de la ejecución se muestran en el monitor.

De hecho, a veces enviamos información al disco y, cuando es necesario, leemos los datos del disco en la memoria para su uso. Lo que se procesa aquí es el archivo en el disco.

         3. Nombre del archivo

Un archivo debe tener un identificador de archivo único para que los usuarios puedan identificarlo y hacer referencia a él. El nombre del archivo contiene 3 partes: ruta del archivo + tronco del nombre del archivo + sufijo del archivo. Por ejemplo: c:\code\test.txt Por conveniencia, el identificador del archivo a menudo se denomina nombre del archivo.

 

3. Abrir y cerrar archivos

        1. puntero de archivo

En el sistema de archivos almacenado en búfer, el concepto clave es el "puntero de tipo de archivo" , o "puntero de archivo" para abreviar .

Cada archivo utilizado abre un área de información de archivo correspondiente en la memoria para almacenar información relacionada con el archivo (como el nombre del archivo, el estado del archivo y la ubicación actual del archivo, etc.). Esta información se almacena en una variable de estructura . El tipo de estructura lo declara el sistema y se denomina ARCHIVO.

Por ejemplo, el archivo de encabezado stdio.h proporcionado por el entorno de compilación VS2013 tiene la siguiente declaración de tipo de archivo :

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

El contenido del tipo FILE de diferentes compiladores de C no es exactamente el mismo, pero sí similar;

Cada vez que se abre un archivo, el sistema creará automáticamente una variable de la estructura del ARCHIVO según la condición del archivo y completará la información que contiene. El usuario no necesita preocuparse por los detalles;

 Generalmente las variables de esta estructura ARCHIVO se mantienen a través de un puntero ARCHIVO , lo que la hace más cómoda de usar;

A continuación podemos crear una variable de puntero de ARCHIVO* :

FILE* pf;//文件指针变量

Defina pf como una variable de puntero que apunta a datos de tipo ARCHIVO ;

Puede hacer que pf apunte al área de información del archivo de un determinado archivo (es una variable de estructura). Se puede acceder al archivo a través de la información en el área de información del archivo. En otras palabras , el archivo asociado a él se puede encontrar a través de la variable de puntero de archivo.

Por ejemplo:

         2. Abrir y cerrar archivos

El archivo debe abrirse antes de leerlo o escribirlo y debe cerrarse después de su uso ;

Al escribir un programa, cuando se abre un archivo, se devolverá una variable de puntero FILE* que apunta al archivo, lo que equivale a establecer una relación entre el puntero y el archivo;

 ANSIC estipula que la función fopen se usa para abrir el archivo y fclose se usa para cerrar el archivo.

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

Abrir de la siguiente manera:

Cómo usar archivos                                     significado Si el archivo especificado no existe
"r"(solo lectura) Para ingresar datos, abra un archivo de texto existente Error
"w" (sólo escritura) Para generar los datos, abra un archivo de texto Crear un nuevo archivo
"a" (añadir) Agregar datos al final del archivo de texto Crear un nuevo archivo
"rb" (solo lectura) Para ingresar datos, abra un archivo binario Error
"wb" (sólo escritura) Para generar datos, abra un archivo binario Crear un nuevo archivo
"ab" (añadir) Agregar datos al final de un archivo binario Crear un nuevo archivo
"r+" (leer y escribir) Para leer y escribir, abra un archivo de texto Error
"w+" (leer y escribir) Para leer y escribir, cree un nuevo archivo. Crear un nuevo archivo
"a+" (leer y escribir) Abra un archivo y lea y escriba al final del archivo. Crear un nuevo archivo
"rb+" (lectura y escritura) Abrir un archivo binario para leer y escribir. Error
"wb+" (lectura y escritura) Para leer y escribir, cree un nuevo archivo binario Crear un nuevo archivo
"ab+" (lectura y escritura) Abra un archivo binario y lea y escriba al final del archivo. Crear un nuevo archivo

 Código de ejemplo:

#include <stdio.h>
int main()
{
	FILE * pFile;
	//打开文件
	pFile = fopen("myfile.txt", "w");
	//文件操作
	if (pFile != NULL)
	{
		fputs("fopen example", pFile);
		//关闭文件
		fclose(pFile);
	}
	return 0;
}

Este archivo no existía antes. Después de ejecutar el programa, se crea nuevamente en el directorio test.c ;

 El contenido también se genera;

 

4. Lectura y escritura secuencial de archivos.

        1. Introducción a las funciones de lectura y escritura secuenciales.

Función Nombre de la función Aplicable a
Función de entrada de caracteres fgetc todos los flujos de entrada
función de salida de caracteres fputc Todos los flujos de salida
Función de salida de línea de texto fgets todos los flujos de entrada
Función de salida de línea de texto salidas todos los flujos de entrada
Función de entrada de formato fscaf Todos los flujos de salida
Función de formato de salida fprintf Todos los flujos de salida
salida binaria miedo documento
salida binaria escribir documento

          2. Función de salida de caracteres fputc

int fputc ( int charcter , FILE * stream); 

Función: escriba el valor del carácter constante de cadena en el archivo señalado por la secuencia del puntero del archivo (excluyendo '\0'). Si la escritura es exitosa, el valor de retorno es el carácter de salida; de lo contrario, se devuelve EOF.

Por ejemplo:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//写文件
	fputc('a', pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

En este momento, el archivo test.txt se genera en el directorio test.c ;

El carácter 'a'  se almacena en el archivo ;

       3. Función de entrada de caracteres fgetc

int fgetc ( FILE * stream ); 

Función: leer un carácter del archivo señalado por la secuencia y asignarlo al carácter variable. Si el archivo no se puede leer, se devuelve EOF.
El tipo de retorno es int y se devuelve el valor del código ASCII del carácter.

Por ejemplo:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//读文件
	int ch = fgetc(pf);
	if (ch != EOF)
	printf("%c", ch);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

 

        4. Entradas de función de salida de línea de texto

int fputs ( const char * str , FILE * stream )

Función: envía el contenido de la cadena representado por srt (excluyendo el último '\0' de la cadena) al archivo señalado por la secuencia. Si tiene éxito, devuelve un número no negativo; de lo contrario, devuelve EOF.

 Por ejemplo:

#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//读文件
	fputs("hello world", pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

         5. Función de entrada de línea de texto fgets

char * fgets ( char * str, int num, FILE * stream ); 

Función: leer (n-1) caracteres del archivo al que apunta la secuencia (el enésimo carácter está preparado para '\0');

Colóquelo en el espacio de almacenamiento donde str es la dirección real (str puede ser el nombre de una matriz de caracteres). Si el carácter de avance de línea de la tecla de retorno de carro o la marca de fin de archivo se encuentra antes de n-1 caracteres, el la operación de lectura finaliza y la cadena de lectura se añade con un carácter '\0' al final;

Si la operación es exitosa, devuelve la dirección inicial de str; de lo contrario, devuelve NULL

Por ejemplo:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//读文件
	char arr[30];
	fgets(arr, 5, pf);
	printf("%s", arr);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

El quinto carácter es '\0' ;

        6. Función de salida formateada fprintf

int fprintf ( FILE * stream , const char * format ) ; 

Función: De acuerdo con el formato de salida dado por formato, escriba el valor de... en el archivo señalado por la secuencia;


Aquí lo comparamos con print y encontramos que solo hay una diferencia entre sus parámetros y printf, que es un nombre de archivo adicional.

Por ejemplo:

#include <stdio.h>
#include <string.h>
#include <errno.h>
struct student
{
	char name[20];
	int age;
	float weight;
};
int main()
{
	struct student s = { "changsan",20,50.0 };
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//写文件
	fprintf(pf, "%s %d %f", s.name, s.age, s.weight);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

 

          7. Función de entrada formateada fscanf

int fscanf ( FILE * stream , const char * format , ... ) ; 

Función: De acuerdo con los caracteres de control de entrada dados por formato, asignar los contenidos leídos del flujo a las variables respectivamente...;


Aquí también lo comparamos con scanf. fscanf solo tiene un parámetro de archivo más.

Por ejemplo:

#include <stdio.h>
#include <string.h>
#include <errno.h>
struct student
{
	char name[20];
	int age;
	float weight;
};
int main()
{
	struct student s = {0};
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//读文件
	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.weight));
	printf("%s %d %f", s.name, s.age, s.weight);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

          8. Escritura de salida binaria

size_t fwrite ( const void * ptr , size_t size , size_t count , FILE * stream ) ; 

ptr: la dirección de los datos

tamaño: el tamaño de cada dato

contar: cuantos datos

secuencia: nombre del archivo

Por ejemplo:

#include <stdio.h>
#include <string.h>
#include <errno.h>
struct student
{
	char name[20];
	int age;
	float weight;
};
int main()
{
	struct student s = { "changsan",20,50.0 };
	FILE* pf = fopen("text.txt", "wb");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//二进制的方式写文件
	fwrite(&s, sizeof(struct student), 1, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

 

 Lo que se almacena en este momento son datos binarios;

         9. Entrada binaria

size_t fread ( void * ptr , size_t size , size_t count , FILE * stream ) ; 

Aquí encontramos que los parámetros de fread y los parámetros de fwrite son los mismos;


fwrite escribe datos de tamaño y cuenta desde ptr hasta la secuencia;


Fread hace exactamente lo contrario, lee datos de tamaño y cuenta desde el flujo hasta el prt;

Por ejemplo:

#include <stdio.h>
#include <string.h>
#include <errno.h>
struct student
{
	char name[20];
	int age;
	float weight;
};
int main()
{
	struct student s = { 0};
	FILE* pf = fopen("text.txt", "rb");
	if (pf == NULL)
	{
		printf("%s", strerror(errno));
		return 0;
	}
	//二进制的形式读文件
	fread(&s, sizeof(struct student), 1, pf);
	printf("%s %d %f", s.name, s.age, s.weight);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

         10,​​​​​​​​​​​​​​sprintf

int sprintf ( char * str , const char * format ) ; 

Escriba datos formateados en una cadena;

De hecho, se trata de escribir datos formateados en una cadena;

Por ejemplo:

#include <stdio.h>
#include <string.h>
#include <errno.h>
struct student
{
	char name[20];
	int age;
	float weight;
};
int main()
{
	struct student s = { "changsan",20,50.0 };

	char buf[100] = { 0 };
	sprintf(buf, "%s %d %f", s.name, s.age, s.weight);
	printf("%s", buf);
	return 0;
}

         11,sscanf

int sscanf ( sonst char * s , const char * format , ... ) ; 

Convertir una cadena en datos formateados;

Por ejemplo:

#include <stdio.h>
#include <string.h>
#include <errno.h>
struct student
{
	char name[20];
	int age;
	float weight;
};
int main()
{
	struct student s = { "changsan",20,50.0 };
	struct student tmp = { 0 };

	char buf[100] = { 0 };
	//把s中的格式化数据转换成字符串放到buf中
	sprintf(buf, "%s %d %f", s.name, s.age, s.weight);
	printf("%s\n", buf);
	//把buf中的字符串转换成格式化数据放到tmp中
	sscanf(buf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.weight));
	printf("%s %d %f", tmp.name, tmp.age, tmp.weight);
	return 0;
}

5. Lectura y escritura aleatoria de archivos.

        1, buscar

Coloque el puntero del archivo según su posición y desplazamiento.

int fseek ( FILE * stream, long int offset, int origin );

 Por ejemplo:

#include<stdio.h>
int main()
{
	FILE * pFile;
	pFile = fopen("example.txt", "wb");
	fputs("This is an apple.", pFile);
	fseek(pFile, 9, SEEK_SET);
	fputs("sam", pFile);
	fclose(pFile);
	return 0;
}

Primero cree y cree automáticamente un archivo example.txt , que debería generar  This is an apple ;

 

 Salida real  Esto es un ejemplo. 

La salida de sam comienza en una posición desplazada en 9 desde la posición inicial;

         2, contar

Devuelve el desplazamiento del puntero del archivo con respecto a la posición inicial.

long int ftell ( FILE * stream );

 Por ejemplo:

#include <stdio.h>
int main()
{
	FILE * pFile;
	long size;
	pFile = fopen("myfile.txt", "rb");
	if (pFile == NULL) perror("Error opening file");
	else
	{
		fseek(pFile, 0, SEEK_END);   // non-portable
		size = ftell(pFile);
		fclose(pFile);
		printf("Size of myfile.txt: %ld bytes.\n", size);
	}
	return 0;
}

En este momento el desplazamiento es 9;

        3, rebobinar

Devuelve el puntero del archivo al principio del archivo.

void rewind ( FILE * stream );

 

6. Archivos de texto y archivos binarios.

Dependiendo de cómo estén organizados los datos, los archivos de datos se denominan archivos de texto o archivos binarios ;

Los datos se almacenan en forma binaria en la memoria . Si se envía a la memoria externa sin conversión, es un archivo binario;

Si es necesario almacenarlo en código ASCII en un almacenamiento externo , es necesario convertirlo antes del almacenamiento. Los archivos almacenados en forma de caracteres ASCII son archivos de texto;

¿Cómo se almacenan los datos en la memoria? Los caracteres siempre se almacenan en formato ASCII y los datos numéricos se pueden almacenar en formato ASCII o binario ;

Por ejemplo, si hay un número entero 10000, si se envía al disco en forma de código ASCII, ocupará 5 bytes en el disco (un byte por cada carácter), mientras que si se envía en formato binario, Solo ocupará 4 bytes en el disco ( prueba

 Por ejemplo:

#include<stdio.h>
int main()
{
	int a = 10000;
	FILE * pf = fopen("test.txt", "wb");
	fwrite(&a, 4, 1, pf);
	fclose(pf);
	pf = NULL;
	return 0;
}

 

 

7. Determinación del final de la lectura del archivo.

        1. Fefo se utiliza incorrectamente

Recuerde: durante el proceso de lectura del archivo, el valor de retorno de la función feof no se puede utilizar para determinar directamente si el archivo finaliza;

La función de feof es: cuando finaliza la lectura del archivo, determinar si el motivo del final de la lectura es: encontrar el final del archivo.

1. Si se completa la lectura del archivo de texto, determine si el valor de retorno es EOF (fgetc) o NULL (fgets)

Por ejemplo:

fgetc determina si es EOF 

fgets determina si el valor de retorno es NULL

2. Determine el final de la lectura del archivo binario y determine si el valor de retorno es menor que el número real a leer;

Por ejemplo:

fread determina si el valor de retorno es menor que el número real que se va a leer.

8. Búfer de archivos

El estándar ANSIC utiliza un "sistema de archivos de búfer" para procesar archivos de datos. El llamado sistema de archivos de búfer significa que el sistema crea automáticamente un "búfer de archivos" en la memoria para cada archivo que se utiliza en el programa;

La salida de datos de la memoria al disco se enviará primero al búfer en la memoria y luego se enviará al disco juntos una vez que el búfer esté lleno;

Si los datos se leen desde el disco a la computadora, los datos se leen desde el archivo del disco y se ingresan en el búfer de memoria (el búfer se llena), y luego los datos se envían desde el búfer al área de datos del programa (variables del programa, etc.) uno por uno;

El tamaño del búfer lo determina el sistema de compilación C.

Por ejemplo:

include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
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;
}

 

Aquí podemos sacar una conclusión: debido a la existencia del búfer, cuando el lenguaje C opera un archivo, necesita actualizar el búfer o cerrar el archivo al final de la operación del archivo;

Si no se hace, puede causar problemas al leer y escribir archivos.

​​​

Si hay alguna deficiencia, ¡no dude en complementarla y comunicarla!

fin. . .


Supongo que te gusta

Origin blog.csdn.net/m0_71676870/article/details/132231177
Recomendado
Clasificación