Sie sind auf Seite 1von 30
Lenguaje d Programación Estructurada Integrantes: - Bazán Soto, José - Huraca Berrospi, Angelo - Urbina Quispe,
Lenguaje d Programación Estructurada Integrantes: - Bazán Soto, José - Huraca Berrospi, Angelo - Urbina Quispe,
Lenguaje d Programación Estructurada Integrantes: - Bazán Soto, José - Huraca Berrospi, Angelo - Urbina Quispe,

Lenguaje d Programación Estructurada

Lenguaje d Programación Estructurada Integrantes: - Bazán Soto, José - Huraca Berrospi, Angelo - Urbina Quispe,

Integrantes:

  • - Bazán Soto, José

  • - Huraca Berrospi, Angelo

  • - Urbina Quispe, Jaime

20120153C

20122022C

20120319I

Profesor: Córdova Neri Teodoro

2013

INDICE

I.

Introducción

II.

Importancia del software Fundamento teórico

  • 2.1 Historia del Lenguaje c

  • 2.2 Historia del Lenguaje C++

  • 2.3 Programación estructurada

    • 2.3.1 Estructuras de Control

    • 2.3.2 Estructuras Repetitivas

    • 2.3.3 Arreglos:

*Arreglos *Cadena de Caracteres *Matrices 2.3.4. Archivos

III. Base de Datos

I.

Introducción

El avance en el campo de la Tecnología de la información mejora realmente la vida de las personas. Las habilidades y el trabajo de Los profesionales de TI realmente han traído grandes cambios y las empresas están disfrutando de los privilegios, que llegan a servir en el trabajo, realizado por los profesionales de TI. Usted verá que el software de innumerables se vende en el mercado, que han hecho la vida de los hombres de Negocios, más fácil que nunca. Entre todos los otros tipos de software, Software médico es uno de los más prominentes y eficiente. Este software ha ayudado a mejorar la eficiencia en el trabajo y la funcionalidad de las instituciones médicas, incluyendo clínicas y los hospitales. De software médico pueden introducir cambios importantes y destacados en el trabajo constante de los médicos y el personal, que trabajan en Hospitales y Clínicas. Las ventajas de este software puede ser igualmente proporcionada a los pacientes. Que puede traer la paz en la vida de los médicos y pacientes y no habrá posibilidades de bastante menos de cualquier tipo de problema, en el funcionamiento de hospitales y clínicas. Los médicos llevan una vida ocupada y agitada. No tienen mucho tiempo para mantener el registro de sus pacientes y para registrar la historia de los pacientes es un trabajo de mucho tiempo. Si va a contratar a un empleado para mantener el registro de los pacientes, incluso en ese caso sería una pérdida de tiempo y trabajo caro. En lugar de pagar a un empleado, sólo para este trabajo, el que tiene que entender la importancia de la instalación de software médico. No sólo va a ayudar en el mantenimiento de los datos de los pacientes, sino que también ayudará en el mantenimiento de la facturación de su hospital o clínica.

II. Fundamento teórico 2.1 Historia del lenguaje c

El lenguaje de programación C fue creado por Brian Kernighan y Dennis Ritchie a mediados de los años 70. La primera implementación del mismo la realizó Dennis Ritchie sobre un computador DEC PDP-11 con sistema operativo UNIX. C es el resultado de un proceso de desarrollo que comenzó con un lenguaje anterior, el BCPL, el cual influyó en el desarrollo por parte de Ken Thompson de un lenguaje llamado B, el cual es el antecedente directo del lenguaje C. El lenguaje C es un lenguaje para programadores en el sentido de que proporciona una gran flexibilidad de programación y una muy baja comprobación de incorrecciones, de forma que el lenguaje deja bajo la responsabilidad del programador acciones que otros lenguajes realizan por sí mismos. Así, por ejemplo, C no comprueba que el índice de referencia de un vector (llamado array en la literatura informática) no sobrepase el tamaño del mismo; que no se escriba en zonas de memoria que no pertenecen al área de datos del programa, etc. El lenguaje C es un lenguaje estructurado, en el mismo sentido que lo son otros lenguajes de programación tales como el lenguaje Pascal, el Ada o el Modula-2, pero no es estructurado por bloques, o sea, no es posible declarar subrutinas (pequeños trozos de programa) dentro de otras subrutinas, a diferencia de como sucede con otros lenguajes estructurados tales como el Pascal. Además, el lenguaje C no es rígido en la comprobación de tipos de datos, permitiendo fácilmente la conversión entre diferentes tipos de datos y la asignación entre tipos de datos diferentes, por ejemplo la expresión siguiente es válida en C:

float a; /*Declaro una variable para números reales*/

int b; /*Declaro otra variable para número enteros*/

b=a; /*Asigno a la variable para entera el número real*/

Todo programa de C consta, básicamente, de un conjunto de funciones, y una función llamada main, la cual es la primera que se ejecuta al comenzar el programa, llamándose desde ella al resto de funciones que compongan nuestro programa. Desde su creación, surgieron distintas versiones de C, que incluían unas u otras características, palabras reservadas, etc. Este hecho provoco la necesidad de unificar el lenguaje C, y es por ello que surgió un estándar de C, llamado ANSI-C, que declara una serie de características, etc., que debe cumplir todo lenguaje C. Por ello, y dado que todo programa que se desarrolle siguiendo el estándar ANSI de C será fácilmente portable de un modelo de ordenador a otro modelo de ordenador, y de igual forma de un modelo de compilador a otro, en estos apuntes explicaremos un C basado en el estándar ANSI-C.

El lenguaje C posee un número reducido de palabras reservadas (tan solo 32) que define el estándar ANSI-C. Estas palabras reservadas pueden verse en la tabla siguiente:

El lenguaje C posee un número reducido de palabras reservadas (tan solo 32) que define el
  • 2.2 Historia del lenguaje c++

El comité para el estándar ANSI C fue formado en 1983 con el objetivo de crear un lenguaje uniforme a partir del C original, desarrollado por Kernighan y Ritchie en 1972, en la ATT. Hasta entonces el estándar lo marcaba el libro escrito en 1978 por estos dos autores1. El lenguaje C++ se comenzó a desarrollar en 1980. Su autor fue B. Stroustrup, también de la ATT. Al comienzo era una extensión del lenguaje C que fue denominada C with classes. Este nuevo lenguaje comenzó a ser utilizado fuera de la ATT en 1983. El nombre C++ es también de ese año, y hace referencia al carácter del operador incremento de C (++). Ante la gran difusión y éxito que iba obteniendo en el mundo de los programadores, la ATT comenzó a estandarizarlo internamente en 1987. En 1989 se formó un comité ANSI (seguido algún tiempo después por un comité ISO) para estandarizarlo a nivel americano e internacional. En la actualidad, el C++ es un lenguaje versátil, potente y general. Su éxito entre los programadores profesionales le ha llevado a ocupar el primer puesto como herramienta de desarrollo de aplicaciones. El C++ mantiene las ventajas del C en cuanto a riqueza de operadores y expresiones, flexibilidad, concisión y eficiencia. Además, ha eliminado algunas de las dificultades y limitaciones del C original. La evolución de C++ ha continuado con la aparición de Java, un lenguaje creado simplificando algunas cosas de C++ y añadiendo otras, que se utiliza para realizar aplicaciones en Internet. Hay que señalar que el C++ ha influido en algunos puntos muy importantes del ANSI C, como por ejemplo en la forma de declarar las funciones, en los punteros a void, etc. En efecto, aunque el C++ es posterior al C, sus primeras versiones son anteriores al ANSI C, y algunas de las mejoras de éste fueron tomadas del C++. El C++ es a la vez un lenguaje procedural (orientado a algoritmos) y orientado a objetos. Como lenguaje procedural se asemeja al C y es compatible con él, aunque ya se ha dicho que presenta ciertas ventajas (las modificaciones menores, que se verán a continuación). Como lenguaje orientado a objetos se basa en una filosofía completamente diferente, que exige del programador un completo cambio de mentalidad. Las características propias de la Programación Orientada a Objetos (Object Oriented Programming, u OOP) de C++ son modificaciones mayores que sí que cambian radicalmente su naturaleza.

2.3 Programación estructurada

Orígenes de la programación estructurada

A finales de los años 1970 surgió una nueva forma de programar que no solamente daba lugar a programas fiables y eficientes, sino que además estaban escritos de manera que facilitaba su mejor comprensión, no sólo proveyendo ventajas durante la fase de desarrollo, sino también posibilitando una más sencilla modificación posterior.

El teorema del programa estructurado, propuesto por Böhm-Jacopini, demuestra que todo programa puede escribirse utilizando únicamente las tres instrucciones de control siguientes:

Secuencia

Instrucción condicional.

Iteración (bucle de instrucciones) con condición al principio.

Solamente con estas tres estructuras se pueden escribir todos los programas y aplicaciones posibles. Si bien los lenguajes de programación tienen un mayor repertorio de estructuras de control, éstas pueden ser construidas mediante las tres básicas citadas.

Historia

Fundamentación teórica

El teorema del programa estructurado proporciona la base teórica de la programación estructurada. Señala que tres maneras de combinar programas son suficientes para expresar cualquier función computable: secuencia, selección e iteración. Esta observación no se originó con el movimiento de la programación estructurada. Estas estructuras son suficientes para describir el ciclo de instrucción de una unidad central de procesamiento, así como el funcionamiento de una máquina de Turing. Por lo tanto un procesador siempre está ejecutando un "programa estructurado" en este sentido, incluso si las instrucciones que lee de la memoria no son parte de un programa estructurado. Sin embargo, los autores usualmente acreditan el resultado a un documento escrito en 1966 por Böhm y Jacopini, posiblemente porque Dijkstra había citado este escrito. El teorema del programa estructurado no responde a cómo escribir y analizar un programa estructurado de manera útil. Estos temas fueron abordados durante la década de 1960 y principio de los años 1970, con importantes contribuciones de Dijkstra, Robert W. Floyd, Tony Hoarey y David Gries.

2.3.1. Estructuras de control

Bloques if La sintaxis general de un bloque if es:

if( expresion ) { statement ; ... } La expresion debe ir entre paréntesis y dar un valor numérico. Si el valor es no cero, las expresiones que van entre llaves son ejecutadas. También se puede utilizar un bloque if-else:

if( expresion ) { contenidos bloque 1 ; } else { contenidos bloque 2 ; } Bucles

En C++ hay tres clases de bucles:

Bucle while while( expresion ) { statement ; // cuerpo del bucle ... } El bucle while ejecuta el cuerpo del bucle repetidamente mientras la expresion sea distinta de cero (sea verdadera). El test se hace antes de ejecutar el cuerpo del bucle, lo que significa que se este se ejecuta cero o más veces. Se debe utilizar un bucle while cuando es posible que el cuerpo del bucle no sea ejecutado. Por ejemplo, para leer y procesar el contenido de un fichero de tamaño desconocido. Bucle do-while do { statement ; // cuerpo del bucle do-while ... } while ( expresion ); El cuerpo del bucle se ejecuta repetidamente mientras la expresion es distinta de cero (verdadera). El test se hace después de ejecutar el cuerpo del bucle, por lo que este se ejecuta al menos una vez. Debe utilizarse este tipo de bucles cuando el cuerpo debe ser ejecutado al menos una vez. En particular, en aquellos casos en que el bucle calcula un valor que es necesario para la condición de terminación. Por ejemplo, los cálculos iterativos que terminan cuando se da una condición de convergencia, cuando una expresion calculada dentro del bucle es menor que un determinado valor. Bucle for for ( init-statement; expresion de continuación; expresion de incremento ) { statement ; // cuerpo del bucle for ... }

break y continue break termina la ejecución del bucle en que se encuentra. continue hace que el bucle pase directamente a la siguiente iteración. Ambos comandos deben utilizarse lo menos posible

2.3.2 Estructuras repetitivas

Introducción

Un

ciclo

es

una

estructura

que

nos

permite

representar

un

conjunto

de

instrucciones que debe repetirse una cantidad limitada de veces, normalmente

dependiente de una condición o de una cantidad determinada de repeticiones o iteraciones. Los ciclos permiten iterar todo un proceso tantas veces como el

programador

(o

el

usuario)

lo

determine.

Es común, que en la solución de muchos problemas algorítmicos, se requiera realizar la repetición de cierto bloque de instrucciones, con el fin de obtener el objetivo buscado por el algoritmo. Para implementar repetición de bloques de instrucciones se utilizan las estructuras de control llamadas ciclos o estructuras repetitivas.

Concepto General

Un ciclo puede definirse como una estructura que nos permite repetir o iterar un conjunto de instrucciones y que tiene las siguientes características:

El conjunto de instrucciones a repetir dentro del ciclo debe ser finito La cantidad de veces que se repita dicho conjunto de instrucciones también debe ser finita. En algunos casos esta cantidad de veces va a depender de una condición explícita y en otros casos va a depender de una condición implícita. Una condición es explícita cuando depende solamente de la misma ejecución del programa sin que sea importante la participación del usuario. Asimismo una condición es implícita cuando depende solamente de la voluntad del usuario y por lo tanto la cantidad de iteraciones o repeticiones del ciclo podría llegar a ser diferente cada vez pues sería posible que cambiara con cada usuario. Deben estar claramente demarcados el inicio y el fin del ciclo. En los casos en los cuales solo exista una instrucción a iterar, no serán necesarias dichas marcas. Dentro de un ciclo podrá ir cualquiera de las otras estructuras, incluyendo otros ciclos.

Tipos de Ciclos

A continuación se describe la estructura de construcción de cada uno de los ciclos tal como son concebidos por la mayoría de lenguajes de programación y

posteriormente se utilizaran para representar el mismo algoritmo con cada una de las estructuras.

Ciclo while (Mientras)

El ciclo while representa el esquema general de trabajo para todos los ciclos, esto quiere decir que si se entiende claramente la lógica de funcionamiento de este ciclo se facilita entender no solo los otros ciclos. Es útil saber que este ciclo también es llamado en algunos libros el Ciclo Mientras Que.

Su forma de ejecución es muy sencilla: Mientras se cumpla que la condición sea Verdadera entonces se ejecutará el Cuerpo del Ciclo. De igual forma también se podría decir que el Cuerpo del Ciclo se repetirá tantas veces como lo permita la condición o mientras dicha condición sea Verdadera. En condiciones normales la cantidad de veces que se repita el cuerpo del ciclo será siempre una cantidad finita y deberá existir, dentro del mismo cuerpo del ciclo, una o más instrucciones que hagan que en algún momento la condición sea Falsa.

El ciclo while se puede describir de la siguiente forma: cuando el computador encuentra la estructura while verifica la condición del ciclo, si la condición es verdadera se ejecutan las instrucciones al interior del ciclo, luego de ejecutar la última condición del ciclo se vuelve a evaluar la condición, sí continúa siendo cierta se vuelve a ejecutar el bloque de instrucciones del ciclo. Cuando la condición se hace falsa el computador se salta el bloque de instrucciones del ciclo y continúa con la ejecución del resto de instrucciones del programa.

posteriormente se utilizaran para representar el mismo algoritmo con cada una de las estructuras. Ciclo while

2.3.3 Arreglos

Arreglos y Matrices 1. Arreglos

Un arreglo es una estructura de datos, o más técnicamente, un espacio de memoria que permite almacenar una colección de elementos, todos del mismo tipo. Conviene imaginar un arreglo como una secuencia contigua de celdas (espacios de memoria), o casillas, en cada una de las cuales se puede guardar un elemento de la colección. Además, es usual dibujarlo como lo ilustra la figura siguiente:

|

0 |

1 |

2 |

3 |

4 |

5

|

6 |

Esta figura representa un arreglo de siete casillas cada una de las cuales se puede utilizar para guardar un dato. La dimensión o tamaño de un arreglo es el número de casillas que lo conforman. Debe ser claro, entonces, que la figura anterior corresponde a un arreglo de dimensión 7.

Cada una de las casillas de un arreglo tiene asociado un número que la identifica de manera única. A este número se le llama índice o dirección. En la figura anterior, debajo de cada casilla, aparece su índice. En lenguajes como C, C++ y java, la primera casilla del arreglo tiene índice 0, la segunda tiene índice 1, la tercera índice 2, y así sucesivamente. Es muy importante tener presente que si el arreglo es de dimensión N, la última casilla tiene índice N-1. Los lenguajes de programación, permiten que el programador declare arreglos de cualquier tipo y prácticamente de cualquier tamaño. En el seudolenguaje, un arreglo se declara usando el siguiente formato o plantilla:

<NOMBRE>: arreglo [<N>] de <TIPO>

En este formato aparecen en mayúsculas y entre los caracteres < y > los componentes que el programador debe determinar. Así por ejemplo, si se quiere declarar un arreglo con nombre letras, de dimensión 15 y que pueda almacenar datos de tipo caracter, se debe escribir la siguiente línea. letras : arreglo [15] de caracter

Volviendo al formato anterior, el programador debe bautizar el arreglo (ponerle un nombre significativo), debe decir cuál es su dimensión, y también debe decir de qué tipo son los elementos que almacenará ese arreglo. Enseguida se dan algunos ejemplos de declaraciones de arreglos. Si se necesita guardar las ventas diarias de una tienda durante la última semana, se puede declarar el siguiente arreglo:

ventas : arreglo [7] de real Si se quiere guardar las notas que ha sacado un estudiante en los cinco talleres y en los cinco laboratorios del curso de Programación de Computadores se pueden declarar los siguientes arreglos:

talleres : arreglo [5] de real

laboratorios : arreglo [5] de real Si se quiere guardar el valor de las últimas 12 facturas telefónicas de una casa, se puede declarar el siguiente arreglo:

facturasTel : arreglo [12] de real

Los índices se crearon para permitir que el programador se pueda referir, de forma específica, a una cualquiera de las casillas del arreglo, tanto para guardar un dato en esa casilla, como para obtener el dato guardado. Para referirse a una casilla particular de un arreglo se debe seguir el siguiente formato:

<NOMBRE>[<INDICE>]

es decir, se debe escribir el nombre del arreglo seguido por el índice de la casilla entre paréntesis cuadrados. Para los siguientes ejemplos, suponga que se declara el arreglo cifras, de la siguiente manera:

cifras : arreglo [10] de entero

La siguiente instrucción asigna o guarda el número 100 en la primera casilla de este arreglo:

cifras[0]:= 100 La siguiente instrucción iterativa guarda 550 en cada una de las últimas 5 casillas de este arreglo:

i:=5

MIENTRAS (i<10) HACER cifras[i]:= 550

i:=i+1

FIN-MIENTRAS

  • 2. Cadenas de caracteres

Los elementos del tipo caracter (tipo char en lenguaje C) se pueden agrupar para formar secuencias que se denominan cadenas de caracteres, o simplemente cadenas. En este texto, y también en el texto de un programa en C, las cadenas se delimitan por dobles comillas. Por ejemplo, “CH?*$A7!y soy cadena” son dos cadenas, la primera formada por 8 caracteres y la segunda por 10. En la memoria del computador una cadena se guarda en un arreglo de tipo caracter, de tal manera que cada símbolo de la cadena ocupa una casilla del arreglo. Sin embargo, se utiliza una casilla adicional del arreglo para guardar un carácter especial que se llama terminador de cadena. En C y en el seudolenguaje este carácter especial es ´\0´. Como lo indica su nombre, la función de este carácter especial es indicar que la cadena termina. La longitud de una cadena se define como el número de símbolos que la componen, sin contar el terminador de cadena. Es muy importante tener en cuenta que aunque el terminador de cadena no hace parte de la cadena, sí ocupa una casilla de memoria en el arreglo. Dado que la representación de cadenas es mediante arreglos de tipo caracter, aplican todos los conceptos que ya explicaron para esta estructura de datos. Por otra parte, por el hecho de que las cadenas son de uso muy frecuente y generalizado en programación, en muchos lenguajes se dispone de muchas operaciones (funciones) sobre estas. La siguiente es una lista corta de estas operaciones para el seudolenguaje, en la cual debe suponerse que cad, cad1 y cad2 son nombres de arreglos de tipo caracter.

Para determinar si una cadena es menor que otra se usa el orden lexicográfico, es decir, el mismo que usan los diccionarios. Así por ejemplo, “casa” es menor “casita”, y esta a su vez es menor que “caza”. De otra parte, la operación leerCadena pone automáticamente el terminador de cadena, lo mismo que las operaciones

copiarCadena y concatenarCadena.

  • 3. Matrices

Una matriz es una estructura de datos, o más técnicamente, un espacio de memoria que permite almacenar una colección de elementos, todos del mismo tipo. La

diferencia con los arreglos está en que, en las matrices, los elementos no están organizados linealmente sino que su organización es bidimensional, es decir, en filas y columnas. Conviene imaginar una matriz como una organización de celdas de memoria, o casillas, en cada una de las cuales se puede guardar un elemento de la colección. Además, es usual dibujarla como lo ilustra la figura siguiente:

diferencia con los arreglos está en que, en las matrices, los elementos no están organizados linealmente

Esta figura representa un matriz de cuatro filas (numeradas verticalmente de 0 a 3) y seis columnas (numeradas horizontalmente de 0 a 5). En cada una de las 24 celdas o casillas se puede guardar un dato. La dimensión o tamaño de una matriz es el número filas por el número de columnas. Debe ser claro entonces que la figura anterior es la gráfica de una matriz de dimensión 4x6. La numeración de las filas y las columnas determina que cada una de las casillas de una matriz tiene asociados dos números que la identifican de manera única. A estos números se les llama índice de fila e índice de columna, respectivamente. En el seudolenguaje, y también en C y C++, las filas y las columnas se numeran desde 0. Los lenguajes como C y C++, permiten que el programador declare matrices de cualquier tipo y prácticamente de cualquier tamaño. En el seudolenguaje, un matriz se declara usando el siguiente formato:

<NOMBRE> : matriz [<N>][<M>] de <TIPO>

En este formato aparecen en mayúsculas y entre los caracteres < y > los componentes que el programador puede determinar. Así por ejemplo, si se quiere declarar una matriz con nombre mat, de dimensión 15x4 y que pueda almacenar datos de tipo caracter, se debe escribir la siguiente línea. mat : matriz [15][4] de caracter

Según el formato anterior, el programador debe bautizar la matriz (ponerle un nombre significativo), debe decir cuál es su dimensión, y también debe decir de qué tipo son los elementos que almacenará. Enseguida se dan algunos ejemplos de declaraciones de matrices.

Si se necesita guardar la información relacionada con el tablero de un juego de tic tac toe (el tradicional triqui), se puede declarar la siguiente matriz: tablero:

matriz [3][3] de caracter Si se requiere guardar las notas que han sacado 35 estudiantes en los 5 talleres y en los 5 laboratorios del curso de Programación de Computadores se pueden declarar las siguientes matrices.

talleres : matriz [35][5] de real laboratorios : matriz [35][5] de real

Note que, en ambas matrices, cada fila guarda las notas de un estudiante del curso. Si se quiere guardar las letras que conforman una sopa de letras, como aquellas que vienen en los pasatiempos, se puede declarar la siguiente matriz.

sopa : matriz [10][15] de caracter

Note que la sopa de letras más grande que se puede guardar es de 10 filas por 15 columnas. Los índices se crearon para permitir que el programador se pueda referir, de forma específica y directa, a una cualquiera de las casillas de la matriz, tanto para guardar un dato en esa casilla, como para obtener el dato almacenado en ella. En el seudolenguaje, para referirse a una casilla particular de una matriz se debe seguir el siguiente formato:

<NOMBRE> [<INDICE-DE-FILA>][<INDICE-DE-COLUMNA>]

es decir, se debe escribir el nombre de la matriz seguido por el índice de fila y por

el índice de columna, ambos entre paréntesis cuadrados, de la casilla que se quiere consultar. Para los siguientes ejemplos, suponga que se declara la matriz montos, de la siguiente manera:

montos : matriz [6][10] de real

La siguiente instrucción asigna o guarda el número 10,4 en la casilla de la esquina superior izquierda de esta matriz:

montos[0][0]:= 10,4

La siguiente instrucción iterativa guarda 5,5 en cada una de las casillas de la última fila de esta matriz:

k:=0

MIENTRAS (k<10) HACER montos[5][k]:= 5,5

k:=k+1

FIN-MIENTRAS

2.3.4. Archivos

Muy a menudo necesitamos almacenar cierta cantidad de datos de forma más o menos permanente. La memoria del ordenador es volátil, y lo que es peor, escaso y caro. De modo que cuando tenemos que guardar nuestros datos durante cierto tiempo tenemos que recurrir a sistemas de almacenamiento más económicos, aunque sea a costa de que sean más lentos. Durante la historia de los ordenadores se han usado varios métodos distintos para el almacenamiento de datos. Al principio se recurrió a cintas de papel perforadas, después a tarjetas perforadas. A continuación se pasó al soporte magnético, empezando por grandes rollos de cintas magnéticas abiertas. Hasta aquí, todos los sistemas de almacenamiento externo eran secuenciales, es decir, no permitían acceder al punto exacto donde se guardaba la información sin antes haber partido desde el principio y sin haber leído toda la información, hasta el punto donde se encontraba la que estábamos buscando. Con las cintas magnéticas empezó lo que con el tiempo sería el acceso aleatorio a los datos. Se podía reservar parte de la cinta para guardar cierta información sobre la situación de los datos, y añadir ciertas marcas que hicieran más sencillo localizarla. Pero no fue hasta la aparición de los discos magnéticos cuando ésta técnica llegó a su sentido más amplio. En los discos es más sencillo acceder a cualquier punto de la superficie en poco tiempo, ya que se accede al punto de lectura y escritura usando dos coordenadas físicas. Por una parte la cabeza de lectura/escritura se puede mover en el sentido del radio del disco, y por otra el disco gira permanentemente, con lo que cualquier punto del disco pasa por la cabeza en un tiempo relativamente corto. Esto no pasa con las cintas, donde sólo hay una coordenada física. Con la invención y proliferación de los discos se desarrollaron los ficheros de acceso aleatorio, que permiten acceder a cualquier dato almacenado en un fichero en relativamente poco tiempo. Actualmente, los discos duros tienen una enorme capacidad y son muy rápidos, aunque aún siguen siendo lentos, en comparación con las memorias RAM. El caso de los CD es algo intermedio. En realidad son secuenciales en cuanto al modo de guardar los datos, cada disco sólo tiene una pista de datos grabada en espiral. Sin embargo, este sistema, combinado con algo de memoria RAM, proporciona un acceso muy próximo al de los discos duros. En cuanto al tipo de acceso, en C y C++ podemos clasificar los archivos según varias categorías:

  • 1. Dependiendo de la dirección del flujo de datos:

De entrada: los datos se leen por el programa desde el archivo. De salida: los datos se escriben por el programa hacia el archivo. De entrada/salida: los datos pueden se escritos o leídos.

  • 2. Dependiendo del tipo de valores permitidos a cada byte:

De texto: sólo están permitidos ciertos rangos de valores para cada byte.

Algunos bytes tienen un significado especial, por ejemplo, el valor hexadecimal 0x1A marca el fin de fichero. Si abrimos un archivo en modo texto, no será posible leer más allá de un byte con ese valor, aunque el fichero sea más largo. Binarios: están permitidos todos los valores para cada byte. En estos archivos el final del fichero se detecta de otro modo, dependiendo del soporte y del sistema operativo. La mayoría de las veces se hace guardando la longitud del fichero. Cuando queramos almacenar valores enteros, o en coma flotante, o imágenes, etc., deberemos usar este tipo de archivos.

  • 3. Según el tipo de acceso:

Archivos secuenciales: imitan el modo de acceso de los antiguos ficheros secuenciales almacenados en cintas magnéticas y Archivos de acceso aleatorio: permiten acceder a cualquier punto de ellos para realizar lecturas y/o escrituras.

  • 4. Según la longitud de registro:

Longitud variable: en realidad, en este tipo de archivos no tiene sentido hablar de longitud de registro, podemos considerar cada byte como un registro. También puede suceder que nuestra aplicación conozca el tipo y longitud de cada dato almacenado en el archivo, y lea o escriba los bytes necesarios en cada ocasión. Otro caso es cuando se usa una marca para el final de registro, por ejemplo, en ficheros de texto se usa el carácter de retorno de línea para eso. En estos casos cada registro es de longitud diferente. Longitud constante: en estos archivos los datos se almacenan en forma de registro de tamaño contante. En C usaremos estructuras para definir los registros. C dispone de funciones de librería adecuadas para manejar este tipo de ficheros. Mixtos: en ocasiones pueden crearse archivos que combinen los dos tipos de registros, por ejemplo, dBASE usa registros de longitud constante, pero añade un registro especial de cabecera al principio para definir, entre otras cosas, el tamaño y el tipo de los registros. Es posible crear archivos combinando cada una de estas categorías, por ejemplo:

archivos secuenciales de texto de longitud de registro variable, que son los típicos archivos de texto. Archivos de acceso aleatorio binarios de longitud de registro constante, normalmente usados en bases de datos. Y también cualquier combinación menos corriente, como archivos secuenciales binarios de longitud de registro constante, etc. En cuanto a cómo se definen estas propiedades, hay dos casos. Si son binarios o de texto o de entrada, salida o entrada/salida, se define al abrir el fichero, mediante la función fopen en C o mediante el método open de fstream en C++. La función open usa dos parámetros. El primero es el nombre del fichero que contiene el archivo. El segundo es en modo que es una cadena que indica el modo en que se abrirá el archivo: lectura o escritura, y el tipo de datos que contiene: de texto o binarios.

En C, los ficheros admiten seis modos en cuanto a la dirección del flujo de datos:

l r: sólo lectura. El fichero debe existir.

l

w: se abre para escritura, se crea un fichero nuevo o se sobrescribe si ya existe.

  • l a: añadir, se abre para escritura, el cursor se sitúa al final del fichero. Si el fichero no existe, se crea.

  • l r+: lectura y escritura. El fichero debe existir.

  • l w+: lectura y escritura, se crea un fichero nuevo o se sobrescribe si ya existe.

  • l a+: añadir, lectura y escritura, el cursor se sitúa al final del fichero. Si el fichero no existe, se crea.

En cuanto a los valores permitidos para los bytes, se puede añadir otro carácter a la cadena de modo:

  • l t: modo texto. Normalmente es el modo por defecto. Se suele omitir.

  • l b: modo binario.

En ciertos sistemas operativos no existe esta distinción, y todos los ficheros son binarios. En C++ es algo diferente, el constructor de las clases ifstream, ofstream y fstream

admite los parámetros para abrir el fichero directamente, y también disponemos del método open, para poder crear el stream sin asociarlo con un fichero concreto y hacer esa asociación más tarde.

Tipos, funciones y clases usados frecuentemente con ficheros

Funciones y tipos C estándar:

Tipo FILE:

  • C define la estructura de datos FILE en el fichero de cabecesa "stdio.h" para el manejo de ficheros. Nosotros siempre usaremos punteros a estas estructuras. La definición de ésta estructura depende del compilador, pero en general mantienen un campo con la posición actual de lectura/escritura, un buffer para mejorar las prestaciones de acceso al fichero y algunos campos para uso interno.

Función fopen:

Sintaxis:

FILE *fopen(char *nombre, char *modo);

ésta función sirve para abrir y crear ficheros en disco. El valor de retorno es un puntero a una estructura FILE. Los parámetros de entrada son:

  • 1. nombre: una cadena que contiene un nombre de fichero válido, esto depende del

sistema operativo que estemos usando. El nombre puede incluir el camino

completo.

  • 2. modo: especifica en tipo de fichero que se abrirá o se creará y el tipo de datos

que puede contener, de texto

o binarios:

r: sólo lectura. El fichero debe existir. w: se abre para escritura, se crea un fichero nuevo o se sobrescribe si ya existe. a: añadir, se abre para escritura, el cursor se sitúa al final del fichero. Si el fichero no existe, se crea. r+: lectura y escritura. El fichero debe existir. w+: lectura y escritura, se crea un fichero nuevo o se sobrescribe si ya existe. a+: añadir, lectura y escritura, el cursor se sitúa al final del fichero. Si el fichero no existe, se crea. t: tipo texto, si no se especifica "t" ni "b", se asume por defecto que es "t" b: tipo binario.

Función fclose:

Sintaxis:

int fclose(FILE *fichero);

Es importante cerrar los ficheros abiertos antes de abandonar la aplicación. Esta función sirve para eso. Cerrar un fichero almacena los datos que aún están en el buffer de memoria, y actualiza algunos datos de la cabecera del fichero que mantiene el sistema operativo. Además permite que otros programas puedan abrir el fichero para su uso. Muy a menudo, los ficheros no pueden ser compartidos por varios programas. Un valor de retorno cero indica que el fichero ha sido correctamente cerrado, si ha habido algún error, el valor de retorno es la constante EOF. El parámetro es un puntero a la estructura FILE del fichero que queremos cerrar.

Función fgetc:

Sintaxis:

int fgetc(FILE *fichero);

Esta función lee un carácter desde un fichero. El valor de retorno es el carácter leído como un unsigned char convertido a int. Si no hay ningún carácter disponible, el valor de retorno es EOF. El parámetro es un puntero a una estructura FILE del fichero del que se hará la lectura.

Función fputc:

Sintaxis:

int fputc(int caracter, FILE *fichero);

Esta función escribe un carácter a un fichero. El valor de retorno es el carácter escrito, si la operación fue completada con éxito, en caso contrario será EOF. Los parámetros de entrada son el carácter a escribir, convertido a int y un puntero a una estructura FILE del fichero en el que se hará la escritura.

Función feof:

Sintaxis:

int feof(FILE *fichero);

Esta función sirve para comprobar si se ha alcanzado el final del fichero. Muy frecuentemente deberemos trabajar con todos los valores almacenados en un archivo de forma secuencial, la forma que suelen tener los bucles para leer todos los datos de un archivo es permanecer leyendo mientras no se detecte el fin de fichero. Esta función suele usarse como prueba para verificar si se ha alcanzado o no ese punto. El valor de retorno es distinto de cero sólo si no se ha alcanzado el fin de fichero. El parámetro es un puntero a la estructura FILE del fichero que queremos verificar.

Función rewind:

Sintaxis:

void rewind(FILE *fichero)

Es una función heredada de los tiempos de las cintas magnéticas. Literalmente significa "rebobinar", y hace referencia a que para volver al principio de un archivo almacenado en cinta, había que rebobinarla. Eso es lo que hace ésta función, sitúa el cursor de lectura/escritura al principio del archivo. El parámetro es un puntero a la estructura FILE del fichero que queremos rebobinar. Ejemplos:

// ejemplo1.c: Muestra un fichero dos veces. #include <stdio.h> int main() { FILE *fichero; fichero = fopen("ejemplo1.c", "r"); while(!feof(fichero)) fputc(fgetc(fichero), stdout); rewind(fichero); while(!feof(fichero)) fputc(fgetc(fichero), stdout); fclose(fichero); getchar(); return 0; }

Función fgets:

Sintaxis:

char *fgets(char *cadena, int n, FILE *fichero);

Esta función está diseñada para leer cadenas de caracteres. Leerá hasta n-1 caracteres o hasta que lea un retorno de línea. En este último caso, el carácter de retorno de línea también es leído. El parámetro n nos permite limitar la lectura para evitar desbordar el espacio disponible en la cadena.

El valor de retorno es un puntero a la cadena leída, si se leyó con éxito, y es NULL si se detecta el final del fichero o si hay un error. Los parámetros son: la cadena a leer, el número de caracteres máximo a leer y un puntero a una estructura FILE del fichero del que se leerá.

Función fputs:

Sintaxis:

int fputs(const char *cadena, FILE *stream);

La función fputs escribe una cadena en un fichero. No se añade el carácter de retorno de línea ni el carácter nulo final. El valor de retorno es un número no negativo o EOF en caso de error. Los parámetros de entrada son la cadena a escribir y un puntero a la estructura FILE del fichero donde se realizará la escritura.

Función fread:

Sintaxis:

size_t fread(void *puntero, size_t tamaño, size_t nregistros, FILE *fichero);

Esta función está pensada para trabajar con registros de longitud constante. Es capaz de leer desde un fichero uno o varios registros de la misma longitud y a partir de una dirección de memoria determinada. El usuario es responsable de asegurarse de que hay espacio suficiente para contener la información leída. El valor de retorno es el número de registros leídos, no el número de bytes. Los parámetros son: un puntero a la zona de memoria donde se almacenarán los datos leídos, el tamaño de cada registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la lectura.

Función fwrite:

Sintaxis:

size_t

fwrite(void

*puntero,

size_t

tamaño,

size_t

nregistros, FILE

 

*fichero);

Esta función también está pensada para trabajar con registros de longitud constante y forma pareja con fread. Es capaz de escribir hacia un fichero uno o varios registros de la misma longitud almacenados a partir de una dirección de memoria determinada. El valor de retorno es el número de registros escritos, no el número de bytes. Los parámetros son: un puntero a la zona de memoria donde se almacenarán los datos leídos, el tamaño de cada registro, el número de registros a leer y un puntero a la estructura FILE del fichero del que se hará la lectura.

Ejemplo:

// copia.c: Copia de ficheros // Uso: copia <fichero_origen> <fichero_destino> #include <stdio.h> int main(int argc, char **argv) { FILE *fe, *fs; unsigned char buffer[2048]; // Buffer de 2 Kbytes int bytesLeidos; if(argc != 3) { printf("Usar: copia <fichero_origen> <fichero_destino>\n"); return 1; } // Abrir el fichero de entrada en lectura y binario fe = fopen(argv[1], "rb"); if(!fe) { printf("El fichero %s no existe o no puede ser abierto.\n",

argv[1]);

return 1; } // Crear o sobrescribir el fichero de salida en binario fs = fopen(argv[2], "wb"); if(!fs) { printf("El fichero %s no puede ser creado.\n", argv[2]); fclose(fe); return 1; } // Bucle de copia:

while((bytesLeidos = fread(buffer, 1, 2048, fe))) fwrite(buffer, 1, bytesLeidos, fs); // Cerrar ficheros:

fclose(fe);

fclose(fs);

return 0;

}

Función fprintf:

Sintaxis:

int fprintf(FILE *fichero, const char *formato,

...

);

La función fprintf funciona igual que printf en cuanto a parámetros, pero la salida se dirige a un fichero en lugar de a la pantalla.

Función fscanf:

Sintaxis:

int fscanf(FILE *fichero, const char *formato,

...

);

La función fscanf funciona igual que scanf en cuanto a parámetros, pero la entrada se toma de un fichero en lugar del teclado.

Función fflush:

Sintaxis:

int fflush(FILE *fichero);

Esta función fuerza la salida de los datos acumulados en el buffer de salida del fichero. Para mejorar las prestaciones del manejo de ficheros se utilizan buffers, almacenes temporales de datos en memoria, las operaciones de salida se hacen a través del buffer, y sólo cuando el buffer se llena se realiza la escritura en el disco y se vacía el buffer. En ocasiones nos hace falta vaciar ese buffer de un modo manual, para eso sirve ésta función. El valor de retorno es cero si la función se ejecutó con éxito, y EOF si hubo algún error. El parámetro de entrada es un puntero a la estructura FILE del fichero del que se quiere vaciar el buffer. Si es NULL se hará el vaciado de todos los ficheros abiertos.

Funciones C específicas para ficheros de acceso aleatorio

Función fseek:

Sintaxis:

int fseek(FILE origen);

*fichero, long

int

desplazamiento, int

Esta función sirve para situar el cursor del fichero para leer o escribir en el lugar deseado. El valor de retorno es cero si la función tuvo éxito, y un valor distinto de cero si hubo algún error. Los parámetros de entrada son: un puntero a una estructura FILE del fichero en el que queremos cambiar el cursor de lectura/escritura, el valor del desplazamiento y el punto de origen desde el que se calculará el desplazamiento. El parámetro origen puede tener tres posibles valores:

  • 1. SEEK_SET el desplazamiento se cuenta desde el principio del fichero. El primer

byte del fichero tiene un desplazamiento cero.

  • 2. SEEK_CUR el desplazamiento se cuenta desde la posición actual del cursor.

Función ftell:

Sintaxis:

long int ftell(FILE *fichero);

La función ftell sirve para averiguar la posición actual del cursor de lectura/escritura de un fichero. El valor de retorno será esa posición, o -1 si hay algún error. El parámetro de entrada es un puntero a una estructura FILE del fichero del que queremos leer la posición del cursor de lectura/escritura.

Clases para manejar ficheros en C++

Existen tres clases para manejar ficheros: ifstream, ofstream y fstream. La primera está orientada a ficheros de entrada, la segunda a ficheros de salida, y la tercera puede manejar cualquiera de los dos tipos o ficheros de entrada y salida.

Clase ifstream:

El constructor está sobrecargado para poder crear streams de varias maneras:

ifstream(); ifstream(const char *name, int mode = ios::in, int = filebuf::openprot);

El primero sólo crea un stream de entrada pero no lo asocia a ningún fichero. El segundo lo crea, lo asocia al fichero con el nombre "name" y lo abre Los parámetros son: el nombre del fichero, el modo, que para ifstream es ios::in por defecto. El tercer parámetro se refiere al buffer, y no nos preocupa de momento.

Clase ofstream:

Lo mismo pasa con ofstream, salvo que los valores por defecto de los parámetros son diferentes:

ofstream(); ofstream(const char *name, int mode = ios::out, int = filebuf::openprot);

Clase fstream:

fstream(); fstream(const char *name, int mode = ios::in, int = filebuf::openprot);

Método open:

Todas estas clases disponen además del método "open", para abrir el fichero a lo largo de la ejecución del programa.

void open(const char *name, int mode, int prot=filebuf::openprot);

"name" es el nombre del fichero, mode es el modo en que se abrirá, puede ser uno o una combinación del tipo enumerado open_mode, de la clase "ios":

enum open_mode { in, out, ate, app, trunc, nocreate, noreplace, binary };

Cada uno de los valores se pueden combinar usando el operador de bits OR (|), y significan lo siguiente:

  • l in: modo de entrada.

  • l out: modo de salida.

  • l ate: abre el fichero y sitúa el cursor al final.

  • l app: modo append, parecido al anterior, pero las operaciones de escritura siempre se hacen al final del fichero.

  • l trunc: si se aplica a ficheros previamente, o se truncará con un

de

salida,

tamaño de 0 bytes, si existe.

se

creará

el

fichero

si

no

existe

  • l nocreate: impide crear un fichero si no existe, en ese caso, la función falla.

  • l noreplace: lo ignoro.

  • l binary: abre el fichero en modo binario.

Los tres últimos modos probablemente no son estándar, y es posible que no

existan en muchos compiladores.

Método close:

void close();

Sencillamente, cierra el fichero asociado a un stream.

Operador >>:

Igual que sucede con el stream estándar cout, el operador de flujo de salida >> se puede usar con streams de salida cuando trabajemos con texto.

Operador <<:

Del mismo modo, al igual que sucede con el stream estándar cin, el operador de flujo de entrada << se puede usar con streams de entrada cuando trabajemos con texto.

Método de salida put:

iostream& put(char ch); Sirve para cualquier stream de salida, e inserta un carácter en el stream.

Método de entrada get:

int get(); istream& get(char*, int len, char = '\n'); istream& get(char&); istream& get(streambuf&, char = '\n');

La primera forma no se recomienda y se considera obsoleta, lee un carácter desde el stream de entrada. La segunda lee caracteres y los almacena en el buffer indicado en el primer parámetro hasta que se leen "leen" caracteres o hasta que se encuentra el carácter indicado en el tercer parámetro, que por defecto es el retorno de línea.

La tercera forma extrae un único carácter en la referencia a char proporcionada. La cuarta no nos interesa de momento.

Método de entrada getline:

iostream& getline(char*, int, char = '\n');

Extrae caracteres hasta que se encuentra el delimitador y los coloca en el buffer, elimina el delimitador del stream de entrada y no lo añade al buffer. Método eof: int eof(); Verifica si se ha alcanzado el final del fichero, devuelve un valor nulo si no es así.

Método clear:

void clear(iostate state=0);

Cada vez que se produzca una condición de error en un stream es necesario eliminarla, ya que en caso contrario ninguna operación que se realice sobre él tendrá éxito. Por ejemplo, si llegamos hasta el final de fichero, el stream quedará en estado "eof" hasta que se elimine explícitamente ese estado. Eso se hace mediante el método "clear", sin parámetros dejará el estado en 0, es decir, sin errores.

Los estados posibles se definen en un enumerado:

enum io_state { goodbit, eofbit, failbit, badbit };

  • l goodbit: indica que el estado es correcto.

  • l eofbit: indica que se ha detectado fin de fichero.

  • l failbit: indica que una operación sobre el stream ha fallado.

  • l badbit: se activa si falla una operación de escritura de buffers.

Método bad:

int bad();

Devuelve el estado del bit "badbit".

Método fail:

int fail();

Devuelve el estado del bit "failbit".

Método good:

int good();

Devuelve el estado del bit "goodbit". Ejemplo:

Veamos el ejemplo anterior de mostrar dos veces un fichero, pero esta vez escrito para C++ usando streams:

// ejemplo1.cpp: Muestra un fichero dos veces. #include <iostream> #include <fstream> using namespace std; int main() { ifstream fichero("ejemplo1.cpp"); char c; while(fichero.get(c)) cout.put(c); fichero.clear(); // (1)

fichero.seekg(0);

while(fichero.get(c)) cout.put(c); fichero.close(); cin.get(); return 0; }

Como vemos en (1), es necesario eliminar el bit de eof, que se ha activado al leer hasta el final del fichero, cuando el último intento de llamar a "get" ha fallado, porque se ha terminado el fichero.

Método is_open:

int is_open();

Devuelve un valor no nulo si el fichero está abierto.

Método flush:

iostream& flush();

Realiza las operaciones de escritura pendientes que aún se han realizado sólo en el buffer.

Métodos relacionados con acceso aleatorio.

Disponemos de otro tipo enumerado en ios para indicar movimientos relativos dentro de un stream de acceso aleatorio:

enum seek_dir { beg, cur, end};

  • l beg: relativo al principio del fichero.

  • l cur: relativo a la posición actual del cursor dentro del fichero.

  • l end: relativo al final del fichero.

Método seekg:

Cambia la posición del cursor en streams de entrada.

iostream& seekg(streampos pos); istream& seekg(streamoff offset, seek_dir dir);

La primera forma es para cambiar la posición de modo absoluto. La segunda para cambios relativos, en la que se indica el salto en el primer parámetro y el punto de partida en el segundo, que puede ser cualquiera de los indicados anteriormente:

ios::beg, ios::cur o ios::end.

Método seekp:

Cambia la posición del cursor en streams de salida.

iostream& seekp(streampos pos); iostream& seekp(streamoff offset, seek_dir);

Lo mismo que seekg, pero aplicado a stream de salida.

Método tellg:

streampos tellg();

Devuelve la posición actual del cursor dentro de un stream de entrada.

Método tellp:

streampos tellp();

Devuelve la posición actual del cursor dentro de un stream de salida.

Método read:

istream& read(char*, int);

Lee el número de caracteres indicado en el segundo parámetro dentro del buffer suministrado por el primero.

Método gcount:

int gcount();

Devuelve el número de caracteres sin formato de la última lectura. Las lecturas sin formato son las realizadas mediante las funciones get, getline y read.

Método write:

iostream& write(const char*, int);

Escribe el número de caracteres indicado en el segundo parámetro desde el buffer suministrado por el primero. Ejemplo:

De nuevo haremos el ejemplo de copiar ficheros, pero esta vez usando streams.

// copia.cpp: Copia de ficheros // Uso: copia <fichero_origen> <fichero_destino> #include <iostream> #include <fstream> using namespace std; int main(int argc, char **argv) { ifstream entrada; ofstream salida; char buffer[2048]; // Buffer de 2 Kbytes int bytesLeidos; if(argc != 3) { printf("Usar: copia <fichero_origen> <fichero_destino>\n"); return 1; } // Abrir el fichero de entrada en lectura y binario

entrada.open(argv[1]);

if(!entrada.good()) { printf("El fichero %s no existe o no puede ser abierto.\n",

argv[1]);

return 1; } // Crear o sobrescribir el fichero de salida en binario

salida.open(argv[2]);

if(!salida.good()) { printf("El fichero %s no puede ser creado.\n", argv[2]); entrada.close(); return 1; }

// Bucle de copia:

do { entrada.read(buffer, 2048); bytesLeidos = entrada.gcount(); salida.write(buffer, bytesLeidos); } while(bytesLeidos > 0); // Cerrar ficheros:

entrada.close(); salida.close(); return 0; }

3 Archivos secuenciales

En estos archivos, la información sólo puede leerse y escribirse empezando desde el principio del archivo. Los archivos secuenciales tienen algunas características que hay que tener en cuenta:

  • 1. La escritura de nuevos datos siempre se hace al final del archivo.

  • 2. Para leer una zona concreta del archivo hay que avanzar siempre, si la zona está

antes de la zona actual de lectura, será necesario "rebobinar" el archivo.

  • 3. Los ficheros sólo se pueden abrir para lectura o para escritura, nunca de los dos

modos a la vez. Esto es en teoría, por supuesto, en realidad C no distingue si los archivos que usamos son secuenciales o no, es el tratamiento que hagamos de ellos lo que los clasifica como de uno u otro tipo. Pero hay archivos que se comportan siempre como secuenciales, por ejemplo los ficheros de entrada y salida estándar: stdin, stdout, stderr y stdaux. Tomemos el caso de stdin, que suele ser el teclado. Nuestro programa sólo podrá abrir ese fichero como de lectura, y sólo podrá leer los caracteres a medida que estén disponibles, y en el mismo orden en que fueron tecleados. Lo mismo se aplica para stdout y stderr, que es la pantalla, en estos casos sólo se pueden usar para escritura, y el orden en que se muestra la información es el mismo en que se envía. Un caso especial es stdaux, que suele ser el puerto serie. También es un archivo secuencial, con respecto al modo en que se leen y escriben los datos. Sin embargo se un fichero de entrada y salida. Trabajar con archivos secuenciales tiene algunos inconvenientes. Por ejemplo, imagina que tienes un archivo de este tipo en una cinta magnética. Por las características físicas de este soporte, es evidente que sólo podemos tener un fichero abierto en cada unidad de cinta. Cada fichero puede ser leído, y también sobrescrito, pero en general, los archivos que haya a continuación del que escribimos se perderán, o bien serán sobrescritos al crecer el archivo, o quedará un espacio vacío entre el final del archivo y el principio del siguiente. Lo normal cuando se quería actualizar el contenido de un archivo de cinta añadiendo o modificando datos, era abrir el archivo en modo lectura en una unidad de cinta, y crear un nuevo fichero de escritura en una unidad de cinta distinta. Los datos leídos de una cinta se editan o modifican, y se copian en la otra secuencialmente.

Cuando trabajemos con archivos secuenciales en disco haremos lo mismo, pero en ese caso no necesitamos dos unidades de disco, ya que en los discos es posible abrir varios archivos simultáneamente. En cuanto a las ventajas, los archivos secuenciales son más sencillos de manejar, ya que requieren menos funciones, además son más rápidos, ya que no permiten moverse a lo largo del archivo, el punto de lectura y escritura está siempre determinado. En ocasiones pueden ser útiles, por ejemplo, cuando sólo se quiere almacenar cierta información a medida que se recibe, y no interesa analizarla en el momento. Posteriormente, otro programa puede leer esa información desde el principio y analizarla. Este es el caso de archivos "log" o "diarios" por ejemplo, los servidores de las páginas WEB pueden generar una línea de texto cada vez que alguien accede a una de las páginas y las guardan en un fichero secuencial.

III. Base de Datos.

Uno de los objetivos fundamentales de un sistema de información es contar no sólo con recursos de información, sino también con los mecanismos necesarios para poder encontrar y recuperar estos recursos. De esta forma, las bases de datos se han convertido en un elemento indispensable no sólo para el funcionamiento de los grandes motores de búsqueda y la recuperación de información a lo largo y ancho de la Web, sino también para la creación de sedes web, Intranets y otros sistemas de información en los que se precisa manejar grandes o pequeños volúmenes de información. La creación de una base de datos a la que puedan acudir los usuarios para hacer consultas y acceder a la información que les interese es, pues, una herramienta imprescindible de cualquier sistema informativo sea en red o fuera de ella.

3.1. Definición de Bases de Datos

Es una colección de datos referentes a una organización estructurada según un modelo de datos de forma que refleja las relaciones y restricciones existentes entre los objetos del mundo real, y consigue independencia, integridad y seguridad de los datos.

Lo que debemos tener claro es la diferencia entre Base de Datos y Sistema Gestor de Bases de Datos (SGBD). La base de datos es el almacenamiento donde residen los datos. El SGBD es el encargado de manipular la información contenida en ese almacenamiento mediante operaciones de lectura/escritura sobre la misma. Además las bases de datos no sólo contendrán las tablas (ficheros) de datos, sino que también almacenará formularios (interfaces para edición de datos), consultas sobre los datos, e informes. El SGBD se encargará de manipular esos datos,

controlar la integridad y seguridad de los datos, reconstruir y reestructurar la base de datos cuando sea necesario.

  • 3.2. Definición de Modelo de Datos.

Un modelo de datos es un conjunto de conceptos y reglas que nos llevarán a poder reflejar la estructura de datos y operaciones aplicables sobre ellos de un sistema informático.

Modelo Relacional.

Existen multitud de modelos de datos aplicables para el diseño de bases de datos, pero el modelo relacional es el más usado y extendido; actualmente los SGBD más implantados utilizan este modelo de datos.

La representación gráfica de este modelo es la tabla. Una tabla se compone de filas y columnas. Las filas se corresponden con los registros y las columnas se corresponden con los campos. Un campo será la unidad mínima de información. A partir de éste se formarán los registros.

Para entender estos conceptos partamos de un típico fichero de alumnos. Cada una de las fichas incluidas en él sería un registro y cada apartado de información (DNI, nombre, apellidos, dirección, teléfono,…) que se rellena referente al alumno sería un campo.

Como norma general, una tabla siempre dispondrá de un campo o conjunto de ellos denominado clave primaria, que permitirá identificar de forma única cada registro de una tabla. Se podrán aplicar índices sobre las tablas, lo que permitirá acceder a la información más rápidamente. Las tablas las podremos relacionar de forma que se evitará redundancia de información y la información será más correcta. Estas relaciones se establecerán entre uno o varios campos de una tabla (clave ajena) “contra” la clave primaria de otra tabla, por lo que una vez establecida la relación, los valores que se introduzcan deberán existir en la tabla relacionada.

  • 3.3. Ventajas de las Bases de Datos:

    • Control sobre la redundancia de datos:

Los sistemas de ficheros almacenan varias copias de los mismos datos en ficheros distintos. Esto hace que se desperdicie espacio de almacenamiento, además de provocar la falta de consistencia de datos.

  • Consistencia de datos:

Si un dato está almacenado una sola vez, cualquier actualización se debe hacer

una sola vez, y está disponible para todos los usuarios inmediatamente. Si algún

dato esta duplicado y el sistema reconoce esta redundancia, el mismo sistema se encarga de garantizar que todas las copias se mantengan consistentes.

  • Compartición de datos:

Los ficheros pertenecen a las personas o a los departamentos que los utilizan. Pero en los sistemas de bases de datos, la base de datos pertenece a la empresa y puede ser compartida por todos los usuarios que estén autorizados.

  • Mantenimiento de Estándares:

Gracias a la integración, es más fácil respetar los estándares necesario, tanto los establecidos a nivel de empresa como los nacionales e internacionales. Estos estándares pueden establecerse sobre el formato de los datos para facilitar su intercambio, pueden ser estándares de documentación, procedimientos de actualización y también reglas de acceso.

  • Mejora la integridad de datos:

La integridad de las bases de datos se refiere a la validez y la consistencia de los datos almacenados. Normalmente, la integridad se expresa mediante restricciones

o reglas que no se pueden violar. Estas restricciones se pueden aplicar tanto a los datos, como a sus relaciones, y es Sistema de Gestión de Bases de Datos quien se debe de encargar de mantenerse.

  • Mejora los servicios de copias de seguridad:

Muchos sistemas de ficheros dejan que sea el usuario quien proporcione las medidas necesarias para proteger los datos ante fallos en el sistema o en las aplicaciones. Los usuarios tienen que hacer copias de seguridad cada día, y si

ocurre algún fallo, utilizar las copias para restaurarlos.

3.4. Desventajas de las Bases de Datos

  • Complejidad:

Los Sistemas de Gestión de Bases de Datos son conjuntos de programas que

pueden llegar a ser complejos con una gran funcionalidad. Es preciso comprender muy bien esta funcionalidad para poder realizar un buen uso de ellos.

  • Vulnerable a Fallos:

El hecho de que todo este centralizado en el Sistema de Gestión de Bases de Datos hace que el sistema sea más vulnerable ante los fallos que pueden

producirse. Es por ello que deben tenerse copias de seguridad (Backup).