archivo - Programación de computadores

Anuncio
09 ­ Archivos
Diego Andrés Alvarez Marín
Profesor Asociado
Universidad Nacional de Colombia
Sede Manizales
1
Temario
●
Definición
●
Archivos de texto y binarios
●
Fin de línea en archivos de texto
●
Modo de acceso a archivos
●
Puntero FILE*
●
●
Punteros a archivos estándar
●
●
●
●
fopen(), fclose(), fprintf(), fscanf(), putc(), getc(), fgets(), fputs(), rewind()
EOF, feof()
Acceso aleatorio a archivos: fseek(), ftell(), fgetpos(), fsetpos()
ungetc(), fflush(), fread(), fwrite(), ferror(), perror()
Buffer
2
Definición
Un archivo o fichero informático es un conjunto de bits que son almacenados en un dispositivo (disco/USB/dispositivo de estado sólido). Un archivo es identificado por un nombre y la descripción del subdirectorio que lo contiene. Los archivos se utilizan ya que el almacenamiento en memoria RAM es temporal y desaparece al terminar la ejecución de un programa.
3
Tipos y modo de acceso a los archivos
●
Clasificación de acuerdo al contenido:
–
●
Clasificación de acuerdo al modo de acceso:
–
●
Archivos de texto vs. Archivos binarios
Acceso en modo texto vs. Acceso en modo binario
Clasificación de acuerdo al acceso:
–
Acceso secuencial vs. Acceso aleatorio
4
Para generar el EOF desde el teclado se presiona:
Ctrl+Z en Windows
Ctrl+D en Linux
6
7
Archivos de texto: fin de línea
●
http://en.wikipedia.org/wiki/Text_file
●
http://en.wikipedia.org/wiki/Newline
●
LF (\n = \0x0A = 10) ­ Line feed
●
CR (\r = \0x0D = 13) – Carriage return
●
LF (\n): C, Linux, Windows (algunos programas)
●
CR (\r): Pre­OS X Macintosh
●
CR+LF (\r\n): MS­DOS, Windows Notepad
8
Archivos de texto: fin de línea
Linux
CR (\r = \0x0D = 13) – Carriage return
LF (\n = \0x0A = 10) ­ Line feed
Windows
9
Kate
Codeblocks
10
Modos de acceso a un archivo
●
●
Modo binario: aquí el computador puede acceder a todos y cada uno de los bytes del archivo.
Modo texto: se usa generalmente para representar texto. El archivo puede ser uno, pero C lo interpreta de una u otra forma dependiendo del sistema operativo. Por ejemplo, en un archivo creado con el “Bloc de Notas” de Windows: si en este hay un \r\n para indicar un fin de línea, el lenguaje C lo lee como \n. Igualmente, en Windows, un \n lo escribiría en disco como \r\n.
11
En Unix, ambas vistas serían iguales
Vista binaria y en modo texto de un archivo en MS Windows
12
Flujo de datos (file stream)
http://en.wikipedia.org/wiki/Stream_(computing)
Un flujo de datos (file stream) es una abstracción que se refiere a un flujo o corriente de datos (bytes) que fluyen entre un origen (o fuente) y un destino (o sumidero). Entre el origen y el destino debe existir una conexión o canal por la cual circula en los datos. El comando fopen() asocia un flujo con un archivo, es decir, establecer la conexión del programa con el dispositivo que contiene al archivo.
13
Puntero FILE*
FILE* es un puntero a una estructura (struct) que contiene información sobre el archivo (nombre, buffer, que tan lleno está el buffer, ubicación del archivo en disco, indicador de final del archivo, posición actual del flujo en el archivo, indicador de error, etc).
14
Punteros a los flujos (archivos) estándar
stdin: standard input (usualmente teclado)
● stdout: standard output (usualmente pantalla)
● stderr: standard error output. (usu. pantalla)
●
Estos son punteros FILE*
No abra o cierre estos archivos!!!
http://en.wikipedia.org/wiki/Standard_streams
15
1> redirección stdout
2> redirección stderr
16
El ch al cual devuelve el resultado getc() debe ser int
Siempre que compare contra un EOF en un ciclo, hágalo así
17
Buffer
Todo acceso a archivos en C se hace a través de buffers (en bloques de usualmente 512 bytes). Esto se hace con el objeto de mejorar la velocidad de acceso a disco. 18
fopen (stdio.h)
File stream = flujo de datos
Destroy contents = sobreescribir
Write to end = agregar al final del archivo
rb wb
ab
ab+ a+b
wb+
w+b
wx
wbx
w+x,
wb+x w+bx
Los modos x de C11 (modo de exclusividad) no permiten que otros programas o threads accedan al archivo hasta que el proceso actual cierre el archivo.
19
20
fopen (stdio.h)
Ver: http://en.cppreference.com/w/c/io/fopen
Si se abrió el archivo con éxito, fopen() retorna un puntero FILE* a la estructura del archivo. Si hubo un error, fopen() retorna NULL, demás, el POSIX requiere que errno se active. Los errores pueden ocurrir porque el disco está lleno, porque el acceso está restringido (modificador “x”), por un problema de hardware, porque el archivo no existe, porque el nombre es ilegal, etc.
21
NOTA
Cuando el programa se ejecuta, el programa espera que el archivo a abrir esté en el mismo subdirectorio que el archivo ejecutable. También las rutas se pueden especificar de forma absoluta o relativa:
–
http://en.wikipedia.org/wiki/Path_%28computing%29
–
http://www.linuxnix.com/2012/07/abslute­path­vs­relative­path­in­linuxunix.ht
ml
Forma absoluta:
WINDOWS: C:\\Archivos\\Semestre4\\trabajo.xlsx
LINUX:
/home/diego/Semestre4/trabajo.xlsx
Observe el doble \ en WINDOWS
Forma relativa:
WINDOWS: ..\\Semestre4\\trabajo.xlsx
LINUX:
Downloads/archivo.txt
../Trabajo/archi.txt
22
Número máximo de archivos abiertos
Existen límites en cuanto al número de archivos que se pueden tener abiertos simultáneamente. Estos dependen del sistema operativo.
Ver: http://www.ehow.com/how_6103386_increase­file­handles.html
23
int fprintf(FILE *restrict fp, const char *restrict format, ...);
int fscanf(FILE *restrict fp, const char *restrict format, ...);
Estas funciones retornan:
–
fprintf(): number of characters written if successful or negative value if an error occurred.
–
fscanf(): number of receiving arguments successfully assigned, or EOF if read failure occurs before the first receiving argument was assigned. Para ambas funciones el POSIX especifica que la constante errno se debe actualizar en caso que ocurra un error.
24
25
FILE *tmpfile();
●
●
●
Abre un archivo temporal como “wb+”. El sistema operativo le proporciona un nombre, que es único dentro del sistema de archivos del PC.
El archivo se cierra cuando el programa termina.
Retorna un puntero NULL si ha ocurrido un error. En este caso errno se activa para indicar el error.
26
27
int fgetc(FILE *f);
int getc(FILE *f);
Lee un char (byte) del flujo “f”. Son equivalentes. La única diferencia es que getc() puede ser un macro de fgetc() que se puede expandir varias veces (mucho cuidado!!!) Retorna el char si hubo éxito; si hubo falla retorna EOF.
La falla ocurre ya sea porque:
● se alcanzó el final del archivo: se verifica con feof()
● alguna otra razón: se verifica con ferror()
ch = getchar(); es lo mismo que ch = getc(stdin);
28
29
Por recomendación de:
http://c­faq.com/stdio/gets_flush2.html
En este caso solo se está vaciando una 30
línea del buffer del teclado.
int fputc(int ch, FILE *f);
int putc(int ch, FILE *f);
Escribe el carácter ch en el archivo “f”. Evite que ch sea una expresión que pueda retornar varios resultados, ya que putc(), puede estar implementado como un macro con múltiples repeticiones en la expansión. Internamente ch se convierte a un unsigned char antes de ser escrito.
En caso de éxito, retorna el carácter escrito, de lo contrario, si hubo falla retorna un EOF y activa el indicador de error errno.
putchar(ch); es lo mismo que putc(ch, stdout);
31
EOF (end of file)
http://en.wikipedia.org/wiki/End­of­file
●
●
Un programa que lee datos de un archivo necesita parar cuando alcanza el final del mismo.
EOF es una constante definida en stdio.h que es retornada por las funciones que leen o escriben en un archivo, en caso que se haya alcanzado el final del archivo, o en ocasiones en caso que se presente un error.
32
EOF (end of file)
●
●
●
En Windows el EOF se marca con Ctrl+Z (26 = \0x1A) http://en.wikipedia.org/wiki/Control­Z
En Unix, el sistema operativo tiene mecanismos para saber si se llegó al final del archivo. En ciertos programas de consola se marca con Ctrl+D (4 = \0x04).
EOF vale ­1 en gcc
33
int feof(FILE *f);
Verifica si se alcanzó el final del archivo “f”. Retorna un número diferente de cero si se alcanzó el final del archivo, de lo contrario retorna 0.
Esta función solo retorna el estado después de la última operación de lectura/escritura en el archivo “f”. Por ejemplo si la última operación de lectura/escritura fue un fget() que retorna un EOF, feof() retorna 0. El siguiente fgetc() falla y feof() ya no retornaría 0.
Se debe usar conjuntamente con ferror() para distinguir entre las posibles condiciones de error al acceder a un archivo.
34
int ferror(FILE *f);
●
●
Revisa si hay errores usando el flujo de datos “f”.
Returna un número diferente de cero si han ocurrido errores en “f”; de lo contrario retorna un cero.
35
ch es un int no un char
36
int fclose(FILE *f);
●
●
●
Vacía el buffer del flujo de datos “f” (en caso de requerirlo) y cierra el mismo.
fclose() puede fallar si el disco está lleno, o si por ejemplo la USB ha sido removida.
Retorna 0 si el cierre fue exitoso, de lo contrario retorna EOF.
37
38
char *fgets(char *restrict str, int n, FILE *restrict f);
Lee a los más n­1 chars de “f” y los guarda en str. Aquí n es la longitud de la cadena str. La cadena leída siempre termina con \0. Deja de funcionar si se encuentre el EOF o si se lee un \n. En este último caso, la cadena leída contendrá el \n.
● En caso de éxito, retornará str, de lo contrario retornará NULL.
● If the failure has been caused by end­of­file condition, additionally sets the eof indicator (see feof()) on “f”. If the failure has been caused by some other error, sets the error indicator (see ferror()) on the stream “f”. ●
39
Otro reemplazo de gets(): fgets()
strchr() busca desde la dirección buf hasta que encuentra la primera aparición de un \n. Se retorna dicha dirección de memoria
40
int fputs(const char *restrict str, FILE *restrict fp);
●
●
●
fputs() no agrega un \n como si lo hace puts()
Returns non­negative integer on success, EOF on failure. Because fgets() keeps the newline and fputs() doesn’t add one, they work well in tandem.
41
En Windows toca
poner \r\n
Observe que fputs() no agrega un \n como si lo hace puts()
42
Acceso aleatorio a archivos
El acceso aleatorio se utiliza generalmente con archivos binarios y permite tratar el archivo como un array, de modo que uno se puede mover, leer y escribir en cualquier posición del archivo.
43
Archivos binarios (b)
La ventaja de estos archivos sobre los archivos de texto es que en ellos los números ocupan menos espacio, ya que se guardan de igual forma a como se almacenan en la memoria RAM. Como desventaja, el humano ya no puede entender que se almacena dentro del archivo y se requiere un programa para leer dicho contenido.
44
Archivos binarios
The standard I/O functions you’ve used to this point are text oriented, dealing with characters and strings. What if you want to save numeric data in a file? True, you can use fprintf() and the %f format to save a floating­point value, but then you are saving it as a sequence of characters. For example, the code double num = 1./3.; fprintf(fp,"%f", num);saves num as a sequence of eight characters: 0.333333 . Using a %.2f specifier saves it as four characters: 0.33 . Using a %.12f specifier saves it as 14 characters: 0.333333333333 . Changing the specifier alters the amount of space needed to store the value; it can also result in different values being stored. After the value of num is stored as 0.33 , there is no way to get back the full precision when the file is read. In general, fprintf() converts numeric values to character data, possibly altering the value.
The most accurate and consistent way to store a number is to use the same pattern of bits that the computer does. Therefore, a double value should be stored in a size double unit. When data is stored in a file using the same representation that the program uses, we say that the data is stored in binary form. There is no conversion from numeric forms to character sequences. For standard I/O, the fread() and fwrite() functions provide this binary service.
45
46
Esta figura asume que un int ocupa 16 bits
Escribiendo en modo texto con
fprintf()
47
Escribiendo en modo binario con
fwrite()
48
size_t fwrite(const void *restrict buffer, size_t tam, size_t n, FILE *restrict fp);
fwrite() escribe n objetos (cada uno de tamaño tam) en el el flujo de datos “fp”. El puntero buffer apunta al primero de dichos elementos. fwrite() retorna el número de objetos escritos exitosamente.
Parámetros:
● buffer ­ puntero al primer elemento del array de objetos a ser escrito
● tam ­ tamaño de cada objeto a escribir
● n ­ número de objetos que se escribirán
● fp ­ puntero al flujo de datos asociado al archivo destino
49
50
size_t fread(void *restrict buffer, size_t tam, size_t n, FILE *restrict fp);
Reads up to n objects into the array buffer from the given input stream “fp”. The file position indicator for the stream “fp” is advanced by the number of characters read. If an error occurs, the resulting value of the file position indicator for the stream is indeterminate. If a partial element is read, its value is indeterminate
Parámetros:
● buffer ­ puntero al primer elemento del array donde se escribirán los objetos
● tam ­ tamaño de cada objeto a leer
● n ­ número de objetos que se leerán
● fp – puntero flujo de datos asociado al archivo que se leerá
La función retorna el número de objetos leídos correctamente, el cual puede ser menor que n en caso de un error o de una condición de EOF.51
52
int fseek(FILE *fp, long offset, int origin);
Trata el archivo como un array y se mueve directamente a cualquier byte en particular del flujo de datos asociado al archivo “fp”
●
http://en.cppreference.com/w/c/io/fseek
fseek(fp,
0L, SEEK_SET); // go to the beginning of the file
fseek(fp, 10L, SEEK_SET); // go 10 bytes into the file
fseek(fp,
2L, SEEK_CUR); // advance 2 bytes from current pos
fseek(fp,
0L, SEEK_END); // go to the end of the file
fseek(fp,-10L, SEEK_END); // go back 10 bytes from end of file
53
No todos los compiladores soportan SEEK_END en modo binario.
● If the stream is open in text mode, the only supported values for offset are zero (which works with any origin) and a value returned by an earlier call to ftell() on a stream associated with the same file (which only works with origin of SEEK_SET.
● In addition to changing the file position indicator, fseek() undoes the effects of ungetc() and clears the end­of­file status, if applicable.
● If a read or write error occurs, the error indicator for the stream (ferror()) is set and the file position is unaffected.
● Upon success, fseek() returns 0, and a nonzero value otherwise (esto sucede por ejemplo cuando se indica una posición fuera del archivo).
54
●
55
long ftell(FILE *stream);
Retorna la posición actual del archivo como un long. El inicio del archivo es el 0. (esta definición aplica si el archivo se abrió como binario). ● If the stream is open in binary mode, the value obtained by this function is the number of bytes from the beginning of the file.
● If the stream is open in text mode, the value returned by this function is unspecified and is only meaningful as the input to fseek().
● ftell() returns the file position indicator on success or EOF if failure occurs.
● On error, the errno variable is set to implementation­
defined positive value.
56
●
57
void rewind(FILE *fp);
●
●
“Rebobina” el programa al comienzo del archivo, es decir es equivalente a ejecutar fseek(fp, 0, SEEK_SET); la única diferencia es que se limpian los indicadores de EOF.
The function drops any effects from previous calls to ungetc(). 58
59
Modo binario vs modo texto
●
●
●
UNIX tiene únicamente un tipo de modo.
MS­DOS tiene ambos. MS­DOS marca el final del archivo con Ctrl+Z.
Los archivos en MS­DOS se “paddean” a 256 bytes.
60
●
●
Al abrir archivos de texto creados en MS­DOS en UNIX como modo binario, usted verá \r\n en vez de \n.
The ftell() function may work differently in the text mode than in the binary mode. Many systems have text file formats that are different enough from the Unix model that a byte count from the beginning of the file is not a meaningful quantity. ANSI C states that, for the text mode, ftell() returns a value that can be used as the second argument to fseek() . For MS­DOS, for example, ftell() can return a count that sees \r\n as a single byte.
61
fgetpos() y fsetpos()
●
Un problema potencial de fseek() y ftell() es que estos no trabajan con archivos de más de 2 Gb de tamaño. En este caso en vez de utilizar dichos comandos en ANSI C propone las funciones fgetpos() y fsetpos() y el tipo de dato especial fpos_t en caso que requiera dicho tamaño de archivos.
62
Como funciona la salida/entrada
●
●
●
●
Cuando se abre un archivo, posición en el archivo, buffer, indicadores de error, indicador EOF, número de caracteres copiados al buffer.
The buffer size is implementation dependent, but it typically is 512 bytes or some multiple thereof, such as 4,096 or 16,384. (As hard drives and computer memories get larger, the choice of buffer size tends to get larger, too.) In addition to filling the buffer, the initial function call sets values in the structure pointed to by fp. In particular, the current position in the stream and the number of bytes copied into the buffer are set. Usually the current position starts at byte 0.
Because all the input functions from the stdio.h family use the same buffer, a call to any one function resumes where the previous call to any of the functions stopped.
When an input function finds that it has read all the characters in the buffer, it requests that the next buffer­sized chunk of data be copied from the file into the buffer. In this manner, the input functions can read all the file contents up to the end of the file. After a function reads the last character of the final buffer’s worth of data, it sets the end­of­file indicator to true. The next call to an input function then returns EOF . In a similar manner, output functions write to a buffer. When the buffer is filled, the data is copied to the file.
63
int ungetc(int ch, FILE *fp);
●
●
●
This function puts ch back to the file “fp”. If you push a character onto the input stream “fp”, the next call to a standard input function reads that character.
The ANSI C standard guarantees only one pushback at a time.
On success ch is returned. On failure EOF is returned and the given stream remains unchanged. 64
ungetc()
65
66
int fflush(FILE *fp);
●
●
●
Calling the fflush() function causes any unwritten data in the output buffer to be sent to the output file identified by fp . This process is called flushing a buffer . If fp is the null pointer, all output buffers are flushed. The effect of using fflush() on an input (r) stream is undefined. Lo mismo pasa en un archivo que se abrió con update (a), en caso que la última operación no hubiera sido una de escritura.
If stream is NULL, all open streams are flushed.
Returns zero on success. Otherwise EOF is returned and the error indicator of the file stream fp is set.
67
La librería estándar errno.h
Esta cabecera estándar define macros que presentan un informe de error a través de códigos de error.
Algunos MACROS definidas para el compilador gcc:
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
#define
ENOMEM
EACCES
EFAULT
EEXIST
ENODEV
ENOTDIR
EISDIR
EINVAL
ENFILE
EMFILE
ENOTTY
ENOSPC
EROFS
EDOM
ERANGE
12
13
14
17
19
20
21
22
23
24
25
28
30
33
34
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
Not enough space */
El archivo no se puede abrir para lectura */
Bad address */
File exists */
No such device */
Not a directory */
Prada is a directory */
Invalid argument */
Too many open files in system */
Too many open files */
Inappropriate I/O control operation */
No space left on device */
Read-only file system */
Domain error (math functions) */
Result too large (possibly too small) */
http://www.virtsync.com/c-error-codes-include-errno
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
http://man7.org/linux/man-pages/man3/errno.3.html
68
En errno.h también se define la variable global errno (de error number), la cual se usa por la función perror() de stdio.h, para obtener los mensajes de error.
A value (the error number) is stored in errno by certain library functions when they detect errors. At program startup, the value stored is zero. Library functions store only values greater than zero. Any library function can alter the value stored before return, whether or not they detect errors. Most functions indicate that they detected an error by returning a special value, typically NULL for functions that return pointers, and −1 for functions that return integers. A few functions require the caller to preset errno to zero and test it afterwards to see if an error was detected.
The errno macro expands to int containing the last error code generated in any function using the errno facility.
Nota: ver adicionalmente la función strerror() de string.h
69
void perror(const char *s);
●
Imprime a stderr la cadena s (a menos que s sea NULL), seguido de ": ", y de un mensaje de error que describe la situación actual. El mensaje de error se almacena en la variable del sistema errno. La salida del sistema es idéntica a la salida de strerror(errno), seguida de'\n'.
70
71
●
http://en.cppreference.com/
●
Prata (2014). C primer plus, 6th edition.
72
Descargar