Hp05 Manejo de Archivos

Anuncio
CAPÍTULO 5
MANEJO DE ARCHIVOS
Actualmente existen dos formas para manejar los archivos en lenguaje C, uno llamado de primer nivel
(también llamado secuencial) y otro llamado de segundo nivel (también llamado tipo registro o de alto nivel).
En el estándar UNIX tradicional, se diseño un sistema de archivos con buffer para operar sobre archivos
textos y un sistema de archivos sin buffer para operar sobre archivos binarios. Finalmente el comité ANSI decidió
que no había razón para que existiesen dos sistemas separados para el manejo de archivos por lo que el sistema de
archivos sin buffer no forma parte del estándar propuesto. En la actualidad un gran número de compiladores
soporta la operaciones de bajo nivel.
En el nivel más bajo se considera el archivo como un conjunto de bytes continuos, esto sin tener en cuenta
como se han grabado, un usuario puede leer la cantidad de bytes que desee no importando la posición en la cual se
encuentren éstos.
En el modo de más alto nivel se puede acceder a uno o varios registros, es decir, lo que se lee cada vez es
una agrupación lógica. Las operaciones de primer nivel, como se las llama a las de nivel más bajo, son las más
potentes. Se dice que estas operaciones son las primitivas del sistema: son las operaciones básicas. Las de segundo
nivel se construyen a partir de éstas.
5.1. INSTRUCCIONES A BAJO NIVEL
La siguiente tabla muestra las instrucciones de primer nivel para manejo de archivos. Todas estas
funciones se encuentran definidas en el archivo io.h.
Función
read()
write()
open()
close()
lseek()
unlink()
Descripción
Lee un buffer de datos
Escribe un buffer de datos
Abre un archivo en disco
Cierra un archivo
Busca un byte especificado
Elimina un archivo del directorio
Tabla 5.1. Funciones para manejo de archivo en bajo nivel.
Apertura de archivo
int open(char *nomfich,int modo)
/* devuelve un numero de archivo */
Si la operación ha resultado sin fallas, open devuelve el número que ha adjudicado al archivo que acaba
de abrir. Devuelve un -1 en el caso de que se produzca un error. Para esta función el modo puede tener los
siguientes valores:
44
Preparado por Juan Ignacio Huircán
Modo
0x01
0x02
0x04
Efecto
Sólo Lectura
Sólo Escritura
Lectura/Escritura
O_RDONLY
O_WRONLY
O_RDWR
Tabla 5.2. Modos de acceso de archivo.
Sin embargo, si el archivo no existe, se producirá un error. Para especificar el modo se debe recurrir
entonces a otras configuraciones de bits. Definidas en fcntl.h, los principales son los siguientes:
Modo
O_APPEND
O_CREAT
O_TRUNC
O_TEXT
O_BINARY
Descripción
(0x0800)
(0x0100)
(0x0200)
(0x4000)
(0x8000)
Escritura al final del archivo
Creación si el fichero no existe
Vacía un archivo que ya existe
Considera loa archivo como texto.
Considera los archivos como binarios, no existen caracteres especiales.
Tabla 5.3. Modos de apertura de archivo.
Cuando se vaya a crear un archivo debe especificarse un tercer argumento. Este tercer argumento indica el
modo de protección, los cuales están definidos en sys\stat.h
Modo de protección
Descripción
S_IWRITE
S_IREAD
S_IREAD | S_IWRITE
Sin protección contra escritura.
Sin protección contra lectura.
Lectura y escritura autorizada.
Tabla 5.4. Modos de protección.
Ej 5.1. Abriendo un archivo
#include <stdio.h>
#include <io.h>
void main()
{
int f, modo=0x01;
if( (f= open("Nombre1", modo))==-1)
{
printf("NO se puede abrir ! ");
}
}
Para este ejemplo el archivo NOMBRE1 debe existir. Si NO existe la función open devuelve -1.
Apuntes de Herramientas de Programación
45
Ej 5.2. Abriendo un archivo que no existe.
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
void main()
{
int f, modo=0x04; /* Se puede usar O_RDWR en vez de modo */
if( (f= open("Nombre1", modo|O_CREAT))==-1)
{
printf("NO se puede abrir ! ");
} else printf(" Archivo Abierto !");
}
Para este ejemplo si el archivo NO existe lo crea. El acceso será de lectura-escritura. Todo lo que escriba
en el archivo borrará la información existente. Si el modo es O_RDONLY , sólo se podrá leer.
Para proteger los archivos, se pueden utilizar los modos de protección indicados, estos deben pasarse a la
función open como un tercer argumento.
Lectura de archivos
int read(int fn, char *buf,int
nbytes);
Lee el número de caracteres especificados por nbytes, contados a partir de la posición actual en el
archivo identificado por el número que contiene fn. Los bytes leídos se almacenan en la zona de memoria
apuntada por buf.
La función devuelve el número de caracteres que realmente se hayan leído. Si se produce un error
devuelve -1.
Si el número de caracteres leídos es inferior al número de caracteres pedidos significa que se ha llegado al
final del archivo. Cada vez que se efectúa la operación read, se incrementa en nbytes el puntero de posición
actual en el archivo.
Escritura de archivos
int write(int fn,char *buf,int nbytes);
Escribe el número de caracteres especificados por nbytes, los que se deben encontrar en la zona
apuntada por buf, a partir del puntero de la posición actual del archivo.
Esta función devuelve el número de caracteres realmente escritos. En el caso de que se produzca un error
devuelve un -1.
Posicionamiento de un archivo
long lseek(int fn, long desp1,int modo);
46
Preparado por Juan Ignacio Huircán
Devuelve el nuevo valor del puntero de posición actual en un archivo, o sea el desplazamiento en número
de bytes (en formato long) relativo al principio del archivo. Si ocurre un error retorna -1L (-1 en formato
long).
Cambia el valor del puntero de posicionamiento en el archivo. El desplazamiento es siempre relativo a
una posición que depende del modo.
Modo
0
1
2
Descripción
Principio del archivo
Posición actual en el archivo
Al final del archivo
Tabla 5.4. Modos de posicionamiento
Se recalca que el desplazamiento es un valor long, es decir:
lseek(5, 180L, 0);
Se está accesando el archivo 5, a 180 caracteres respecto del principio. La definición de esta función se
encuentra el prototipo io.h.
Cierre de archivos
int close(int fn);
Siempre deben cerrarse aunque el sistema los cierra al final de la ejecución del programa.
Ej 5.3. Ejemplos de apertura de archivos
Un archivo se puede crear con las ordenes open, creat o creatnew . Cuando se trabaja en DOS para la
creación de un archivo se debe especificar un tercer argumento.
open("NOMBRE", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,S_IREAD|S_IWRITE);
Crea un archivo con nombre "NOMBRE", en modo binario. Si el archivo ya existiera, será borrado el
antiguo. No tiene ninguna protección (se podrá borrar sin ningún problema).
open("NOMBRE", O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,S_IWRITE);
Igual al caso anterior, pero en este caso el archivo está protegido contra escritura.
open("NOMBRE", O_WRONLY|O_APPEND|O_TEXT,S_IREAD,S_IWRITE);
Se abrirá un archivo "NOMBRE" tipo texto, y el puntero se posicionará al final del archivo, escribirá a
continuación.
open("NOMBRE", O_CREAT|O_RDONLY|O_TEXT);
Apuntes de Herramientas de Programación
47
Se abre el archivo "NOMBRE" tipo texto si no existe lo crea, en caso contrario lo abre pero no se
modifica el escribir sobre él.
5.2. INSTRUCCIONES DE SEGUNDO NIVEL (ALTO NIVEL)
En las instrucciones de segundo nivel los archivos ya no se designan por un número, sino, por un puntero
a una estructura compleja llamada FILE cuya descripción se haya en el archivo stdio.h.
Apertura de archivo
FILE *fopen(char *nombrefich, char *modo);
fopen devuelve un puntero a una estructura FILE. En el caso de existir un error devuelve NULL. El
modo se especifica mediante una cadena de caracteres.
Modo
"r"
"w"
"a"
"r+"
Descripción
Para lectura solamente.
Para escritura solamente (si el archivo ya existiera lo borra).
Añadir al final de un archivo que ya existe.
Actualizar uno que ya existe.
Tabla 5.5. Modos de apertura en alto nivel.
Ej 5.4. Para abrir un archivo binario o texto
#include <stdio.h>
void main()
{
FILE * fp;
fp=fopen("NOMBRE", "wb");
...
}
#include <stdio.h>
void main()
{
FILE * fp;
fp=fopen("NOMBRE", "wt");
...
}
Lectura de archivo
int fread(char *p,int s,int n, FILE *fp);
Lee n registros de tamaño s del archivo indicado por fp y los almacena en la zona de memoria indicada
por p. fread devuelve el número de registros leidos, si este número es menor que el pedido, se ha llegado al final
del archivo. Para mayor precisión se usa el feof.
48
Preparado por Juan Ignacio Huircán
Escritura de archivo
fwrite(char *p,int s,int n, FILE *fp);
Escribe n registros de tamaño s del archivo indicado por fp. Los registros se encuentran almacenados en
la zona de memoria indicada por p. La función devuelve el número de registros realmente escritos.
Cerrar archivo
int fclose(FILE *fp);
Posicionamiento en un archivo
fseek(FILE *fp, long pos, int modo);
/* Análoga a lseek */
Condición de fin de archivo
int feof(FILE *fp);
Posicionamiento al comienzo de un archivo
rewind(FILE *fp);
Ej 5.5. Creación de un archivo de registros.
#include <stdio.h>
#include <string.h>
void main()
{
FILE *fp;
struct {char nombre[10]; int edad;}persona;
char buf[65];
fp=fopen("PERSONAS", "wb");
printf("\nNOMBRE :?");
gets(&buf[0])
wihile(buf[0])
{
strcpy(persona.nombre,&buf[0]);
printf("\nEDAD :?");
gets(&buf[0]);
sscanf(&buf[0],"%d",&persona.edad);
fwrite((char *)&persona,12,1,fp);
printf("\nNOMBRE :?");
gets(&buf[0])
}
fclose(fp);
}
Apuntes de Herramientas de Programación
49
Ej 5.6. Creación de un archivo ASCII.
#include <stdio.h>
#include <string.h>
void main()
{
FILE *fp;
struct {char nombre[10]; int edad;}persona;
char buf[65];
fp=fopen("PERSONAS", "wt");
printf("\nNOMBRE :?");
gets(&buf[0])
wihile(buf[0])
{
strcpy(persona.nombre,&buf[0]);
printf("\nEDAD :?");
gets(&buf[0]);
sscanf(&buf[0],"%d",&persona.edad);
fprintf(fp,"%12s %d\n",persona.nombre,persona.edad);
printf("\nNOMBRE :?");
gets(&buf[0])
}
fclose(fp);
}
5.3. FORMAS ADICIONALES DE ENTRADA/SALIDA
Una de la forma muy común de ingreso de datos es la que se realiza por teclado, a continuación se dan
algunos ejemplos, ya que indirectamente ha sido referenciadas.
Funciones para lectura de caracteres desde teclado y funciones a la salida estándar
Estas funciones se encuentran definidas en conio.h y stdio.h.
Funciones
int getch();
int getche();
cputs(char *str);
char *cgets(char *str);
Descripción
Lee caracter desde teclado
Lee caracter desde teclado e imprime en pantalla
Imprime una cadena de caractéres en pantalla
Lee un string. str[0] especifica el largo, str[1] el tamaño del string
leido y apartir de str[2] se encuentra la cadena leida. Retorna &str[2].
Tabla 5.6. Funciones para lectura de caracteres.
50
Preparado por Juan Ignacio Huircán
Ej 5.7. Utilizando funciones para imprimir caracteres en pantalla.
#include <conio.h>
#include <string.h>
void main()
{
char s[30]={"XXX"};
int i;
clrscr();
puts(&s[0])
getch();
}
A continuación se indican algunas funciones definidas en stdio.h
Funciones
Descripción
char *gets(char *s);
fgets(char *s,int n, FILE * fp);
fputs(char *s,int n,FILE *fp);
Lee un string desde el stdin hasta que se ingresa un caracter nueva
línea (\n) retorna un puntero a s.
Realiza la misma operación pero desde un archivo. si fue bien
realizada restorna un puntero a s, sino un NULL.
Escribe una cadena en un archivo.
Tabla 5.7. Funciones defindas en stdio.h.
Funciones de E/S con formato
int printf(const char *format...);
int scanf(const char *format...);
/* Imprime en pantalla con formato */
/* Lee de teclado con formato */
int fprintf(FILE *fpconst char *format...);
int fscanf(FILE *fp,const char *format...);
/* Imprime en un archivo */
/* Lee desde un archivo */
Para las funciones cada format se especifica con % seguido de un caracter que indica el tipo de
conversión (type), todo entre comillas ("). También se pueden intercalar entre ambos otros especificadores.
% [flag][width][.prec][F|N|h|l] type
Apuntes de Herramientas de Programación
type
d
i
o
u
x
f
e
c
s
51
Formato de salida
Entero decimal con signo
Entero decimal con signo
entreo octal sin signo
decimal sin signo
Hexadecimal sin signo
Punto flotante[-]dddd.ddd
Punto flotante [-]d.ddde [+/-] ddd
Caracter
Cadena de caracteres
Tabla 5.8. Especificación de tipo para el formato.
[flag]
Descripción
[width]
nada
-
Justificación a la derecha
Justificación a la izquierda
n
0n
Descripción
Relleno con n Caracteres en blanco
Relleno con 0
Tabla 5.9. Descripción de [flag] y [width].
[.prec]
nada
.0
.n
Descripción
Precisión por defecto
Precisión por defecto para d,i,o,u,x,e, E,f
n decimales
Tabla 5.10. Precisión.
Ej 5.8. Imprimiendo datos en pantalla con formato
#include <stdio.h>
#include <conio.h>
void main()
{
int entero =123;
char caracter=37;
float real=3.14159;
char cadena[20]={"HOLA FLACO"};
clrscr();
printf("%d\n",caracter);
printf("%c\n",caracter);
printf("%d\n",entero);
52
Preparado por Juan Ignacio Huircán
printf("%8d\n",entero);
printf("%x\n",entero);
printf("%f\n",real);
printf("%4.3f\n",real);
printf("%-8.4f\n",real);
printf("%e\n",real);
printf("%s\n",cadena);
getch();
}
Ej 5.9. Leyendo datos con formato desde teclado
#include <stdio.h>
#include <conio.h>
void main()
{
int entero =123;
float real=3.14159;
clrscr();
printf("ENTERO : ?");
scanf("%d",&entero);
printf("REAL: ?");
scanf("%f",&real);
printf("%d %f\n",entero,real);
printf("Pueden ser ingresados separdos por un espacio\n");
scanf("%d %f",&entero, &real);
printf("%d %f\n",entero, real);
getch();
}
Ej 5.10. Escritura y lectura desde un archivo
#include <stdio.h>
#include <conio.h>
void main()
{
int entero=34;
float real=0.5;
FILE *fp;
fp=fopen("TEXTO.TXT","wt");
if(fp!=NULL)
{
fprintf(fp,"%d %f\n",45,34.56);
fprintf(fp,"%d %f\n",40,3304.56);
fprintf(fp,"%d %f\n",entero,real);
fclose(fp);
} printf("NO SE PUEDE ABRIR!\n");
getch();
}
#include <stdio.h>
#include <conio.h>
void main()
{
int entero;
float real;
FILE *fp;
fp=fopen("TEXTO.TXT","rt");
if(fp!=NULL)
{
fscanf(fp,"%d %f\n",&entero,&real);
printf("%d %f\n",entero,real);
fscanf(fp,"%d %f\n",&entero,&real);
printf(fp,"%d %f\n",entero,real);
fscanf(fp,"%d %f\n",&entero,&real);
printf(fp,"%d %f\n",entero,real);
fclose(fp);
}printf("NO SE PUEDE ABRIR!\n");
getch();
}
Apuntes de Herramientas de Programación
53
Descargar