Programación 2: Guión Práctica 12

 

PRÁCTICA DE LABORATORIO 12
Archivos, Archivos de texto

Introducción
Un archivo es un grupo de registros relacionados almacenados en memoria secundaria. Por ejemplo, un archivo de nómina de una compañía contiene normalmente un registro por cada empleado. De esta manera, el archivo de nómina de una compañía pequeña podría contener sólo 20 registros y, en cambio un archivo de nómina de una compañía grande podría contener hasta 50.000 registros. La ventaja es que la información almacenada en un archivo es persistente en el tiempo, no es susceptible a fallas eléctricas y puede reproducirse y transportarse a bajo costo.

Archivos y flujos en C++
C++ ve a cada archivo simplemente como una secuencia de bytes que termina con un marcador especial de fin de archivo. Las bibliotecas estándar de C++ proporcionan un amplio conjunto de capacidades de entrada/salida. En general, la E/S en C++ se da en flujo de bytes. Un flujo es simplemente una secuencia de bytes. En las operaciones de entrada, los bytes fluyen desde un dispositivo (por ejemplo: teclado, unidad de disco, etc.) hacia la memoria principal. En operaciones de salida los bytes fluyen de la memoria principal hacia un dispositivo (por ejemplo: pantalla, impresora, unidad de disco, etc.). Ya se ha visto que existen cuatro objetos que se crean automáticamente cuando se utiliza la biblioteca iostream: cin, cout, cerr y clog. Estos objetos asocian canales de comunicación entre un programa y un archivo o dispositivo particular. Por ejemplo, el objeto cin (flujo de entrada estándar) permite que un programa reciba datos desde el teclado; el objeto cout (flujo de salida estándar) permite que un programa envíe datos a la pantalla, y los objetos cerr y clog (flujo de error estándar) permiten que un programa envíe mensajes de error a la pantalla.

Archivos de encabezado Para realizar el procesamiento de archivos en C++ se deben incluir los archivos de encabezado y . El archivo  incluye las definiciones para las clases ifstream (para entrada desde un archivo), ofstream (para salida hacia un archivo) y fstream (para entrada y salida de un archivo).
Jerarquía std::fstream en C++
Para crear un flujo para leer/escribir archivos a disco (archivos físicos), lo primero que debe hacer es definir un objeto (llamado también archivo lógico) para una de las clases de archivo convenientemente:

  • la clase ifstream, para definir los archivos que se usan exclusivamente para entrada de datos (leer).
  • la clase ofstream, para definir los archivos que se usan exclusivamente para la salida de datos (escribir).
  • la clase fstream, para definir archivos de entrada y/o salida de datos.

El siguiente programa muestra la forma de crear estos objetos de la clase fstream:

#include<fstream>;

int main(){
  std::ifstream lectura; // para leer un archivo
  std::ofstream escritura; // para escribir un archivo
  std::fstream lecturaEscritura; // para leer y escribir un archivo

  return(0);
}

Conexión de procesos con Archivos
El método open(), heredado por todas las clases del flujo de archivos, permite asociar el objeto del flujo de archivos (archivo lógico) a un archivo físico en disco y luego abrirlo para su acceso. La forma de llamar a este método es:

 <objeto de flujo de archivo>.open (<nombre del archivo físico>, <modo de apertura de archivo>);

El nombre del objeto es seguido por un punto y después por la función open() y luego sus argumentos. Los argumentos son: un nombre del archivo en disco y un designador del modo de apertura (opcional). El nombre del archivo en disco se debe ajustar a los requerimientos del sistema operativo. El nombre del archivo en el disco físico se puede especificar directamente dentro de dobles comillas (por ejemplo “ejemplo.txt”) o en forma indirecta como una variable tipo cadena. El argumento indicador del modo de apertura define que tipo de acceso se realizará dentro del archivo (detallado en la siguiente sección).

Nota: El (los) modo(s) de lectura/escritura siempre debe(n) especificarse cuando un objeto de flujo de archivos se define con la clase fstream, pues por definición, esta clase se usa para ambos accesos a archivos de entrada y salida (lectura/escritura). Los modos lectura/escritura no necesitan especificarse cuando se abren archivos definidos por las clases ifstream u ofstream, porque los archivos son predeterminados como entrada y salida respectivamente.

 

Compile y ejecute el siguiente programa y luego verifique los archivos creados en el directorio. ¿Por qué solo se crea el
archivo ejemplo2.txt?

#include <fstream>;

int main(){
  std::ifstream lectura; // para leer un archivo físico
  std::ofstream escritura; // para escribir un archivo físico
  std::fstream lecturaEscritura; // para leer y escribir un archivo
  
  // Archivo logico lectura que lea del archivo de disco ejemplo1.txt.
  lectura.open("ejemplo1.txt");

  // Archivo lógico escritura que escribe al archivo de disco ejemplo2.txt.
  escritura.open("ejemplo2.txt");

  // Archivo logico lescturaEscritura que lea y escriba el archivo ejemplo3.txt.
  lecturaEscritura.open("ejemplo3.txt", std::ios::in | std::ios::out);

  return(0);
}

Después de crear los objetos y abrirlos, se recomienda verificar si la operación tuvo éxito a través del operador sobrecargado ! de std::ios, retornando true si la operación falla. Algunos posibles errores son: intentar abrir un archivo que no existe en modo lectura, abrir un archivo de lectura sin permiso y abrir un archivo para escritura si no hay espacio en disco.
El siguiente código realiza esta verificación (compile y ejecute):

#include <iostream>
#include <fstream>

int main(){
  std::ifstream lectura; // para leer un archivo
  std::ofstream escritura; // para escribir un archivo
  std::fstream lecturaEscritura; // para leer y escribir un archivo

  lectura.open("ejemplo1.txt");
  escritura.open("ejemplo2.txt");
  lecturaEscritura.open("ejemplo3.txt",std:: ios::in | std::ios::out);

  if (!lectura) std::cout << "No se puede abrir el acrhivo lectura --> ejemplo1.txt" <<  std::endl;

  if (!escritura) std::cout << "No se puede abrir el acrhivo escritura --> ejemplo2.txt" << std::endl;

  if (!lecturaEscritura) std::cout << "No se puede abrir el acrhivo lecturaEscritura --> ejemplo3.txt" << std::endl;

  return (0);
}

Los constructores paramétricos de las clases fstream, ifstream y ofstream además de crear el objeto del archivo físico correspondiente, permiten abrir un archivo al igual que el método open(). El siguiente código lo muestra (compile y ejecute):


#include <iostream>
#include <fstream>


int main(){
  std::ifstream lectura("ejemplo1.txt");
  std::ofstream escritura("ejemplo2.txt");
  std::fstream lecturaEscritura("ejemplo3.txt", std::ios::in | std::ios::out);

   if (!lectura) std::cout << "No se puede abrir el archivo lectura --> ejemplo1.txt" << std::endl;

   if (!escritura) std::cout <<"No se puede abrir el archivo escritura --> ejemplo2.txt" <<  std::endl;

   if (!lecturaEscritura) std::cout << "No se puede abrir el archivo lecturaEscritura --> ejemplo3.txt" << std::endl;

  return (0);
}

Modos de apertura de archivo
Dependiendo del propósito del programa debe indicar el modo de acceso, por ejemplo es posible que sea necesario agregar datos a los ya existentes en el archivo, o quizá que las operaciones del programa no se lleven a cabo en caso de que el archivo especificado exista en el disco, etc., Dependiendo del caso podemos especificar el modo de apertura según la siguiente tabla:

Modo Descripción
ios::app Anexa toda la salida al final del archivo
ios::ate Abre en modo salida y se coloca el apuntador del archivo al final del mismo.Los datos pueden escribirse en cualquier parte del archivo.
ios::in Operaciones de lectura. Esta es la opción por defecto para objetos de la clase ifstream.
ios::out Operaciones de escritura. Esta es la opción por defecto para objetos de la clase ofstream.
ios::nocreate Si el archivo no existe se suspende la operación
ios::noreplace Crea un archivo, si existe uno con el mismo nombre la operación se suspende.
ios::trunc Crea un archivo, si existe uno con el mismo nombre lo borra.
ios::binary Operaciones sobre archivos No-Texto

Cerrar la conexión del proceso con un archivo
Después de terminar el procesamiento del archivo, deberá cerrar el archivo para garantizar su contenido y permitir su posterior uso. Esto se realiza con la método close(). Como resultado, los enunciados lecturaEscritura.close(), escritura.close() y lectura.close() deberán cerrar los archivos que se abrieron anteriormente.

Lectura y Escritura de un Archivo tipo texto
Se escribe un archivo en disco usando su objeto de flujo de archivo de salida y el operador de inserción <<, de la misma forma como se usó el objeto de flujo de archivo estándar cout y el operador <<. De esta manera, luego de abrir un objeto de archivo de salida las siguientes instrucciones permiten escribir:

  std::ofstream salida;
  salida.open(“ejemplo.txt”);
  salida << “Esto es un ejemplo” << std::endl;
  salida.close();

Verifique en su disco que aparece el archivo “ejemplo.txt” y que contiene el texto. Se pruebe escribir cualquier tipo de variable (string, arreglo de caracteres, entero, etc.) que tenga definido el operador <<. El siguiente programa genera un archivo de texto donde cada línea contiene un número de línea correspondiente al valor inicial del número de líneas solicitado al usuario (copie, compile, ejecute y verifique el archivo creado con su contenido):

#include <iostream>
#include <fstream>

int main(){
  int numl,i;
  std::ofstream salida; // flujo de salida
  // Apertura del archivo, crear y abrir un nuevo archivo
  salida.open("ejemplo-escribir.txt");
  
  // Verificando la operacion — si el archivo existe o no
  if (!salida)
  {
    std::cout << "No se puede abrir el archivo\n";
    exit(1);
  }
  else
  {
   std::cout << "Suministre el total de lineas del archivo: ";
   std::cin >> numl;
   for (i=0;i&lt;numl;i++)
   {
    //Escritura de un archivo de texto
    salida << i+1 <<"\n";
   }
  }
  
  salida.close(); //Cierre del archivo
  std::cout << "****** Archivo Procesado ******\n";

  return(0);
}

Se lee un archivo en disco con el objeto de flujo de archivo de entrada y el operador de extracción >>, tal como se usa el objeto de flujo de archivo estándar cin y el operador >>. De esta manera, luego de abrir un objeto de archivo de entrada las siguientes instrucciones permiten leer la primera secuencia de caracteres delimitada por el carácter espacio en blanco:

  std::string cadena;
  std::ifstream entrada;

  entrada.open(“ejemplo.txt”);
  entrada >> cadena;

  std::cout << cadena << std::endl; // muestra lo leído del archivo

  entrada.close();

Ejecute el código anterior y verifique lo que muestra por pantalla, note que no es toda la línea que contiene el archivo ejemplo.tx. Note que la cadena se definió como un string por tanto debe incluir la clase string de C++. Si desea obtener toda una
línea del archivo de entrada (independientemente del número de palabras) debe usarse la función getline, en lugar de “entrada >>cadena”, de la siguiente forma:

getline(entrada, cadena, ‘\n’);

Copie, compile y ejecute el siguiente código que muestra como leer el archivo ejemplo-escribir.txt línea a línea y mostrarlo por pantalla.

#include <iostream>
#include <fstream>
#include <string>

int main(){
  std::string i;
  std::ifstream entrada; // flujo de entrada

  // Apertura del archivo: abrir un nuevo existente)
  entrada.open("ejemplo-escribir.txt");
  // Verificando la operacion -- si el archivo existe o no
  
  if (!entrada) 
  {
    std::cout  << "No se puede abrir el archivo\n";
    exit(1);
  }
  else
  {
  /*
    do
      {
      //Lectura de un archivo de texto
      entrada >> i;
      std::cout << i << endl; // muestra lo pantalla
      } while (entrada);
    */
  }
  entrada.close();
  //Cierre del archivo
  std::cout << "****** Archivo Procesado ******\n";
  
  return(0);
}

Hay muchas formas de hacer un ciclo iterativo para leer un archivo de forma secuencial línea por línea hasta el final. Las siguientes son alternativas:

  while (entrada >> i) {
    std::cout << i << std::endl; // muestra lo pantalla
  }

  while (!entrada.eof()) {
    entrada >> i;
    std::cout << i << std::endl; // muestra lo pantalla
  }
  
  entrada >> i;
 while (!entrada.eof()) {
    std::cout << i << std::endl; // muestra lo pantalla
    entrada >> i;
 }

Sin embargo, la última alternativa deja de procesar la última línea. Esto se debe a que cuando se abre un archivo de lectura, un cursor que forma parte del archivo lógico se ubica en la primera línea del archivo físico, luego una vez leída la línea el cursor se ubica en la siguiente. Cuando se ejecuta eof(), este método determina si dicho cursor esta parado en el carácter de fin de archivo y se da el valor de verdad en caso positivo, entonces se sale del ciclo y no se procesa la última línea. Se debe tener cuidado con la forma en que realiza el ciclo iterativo.

Cuando se tienen archivos de textos estructurados, es decir con más de un valor por línea y de tamaño fijo el número de campos. Se puede escribir con el operador << y agregar el separador que se necesite. Para leer de debe usar el operador >> tantas veces como valores están separados por un espacio en blanco o fin de línea.

El siguiente código ilustra como crear y leer un archivo de 2 enteros por líneas:

#include <iostream>
#include <fstream>


int main(){
  int numl,i,j;
  std::ofstream salida; // flujo de salida
  salida.open("ejemplo-escribir2.txt",std::ios::out);
  
  if (!salida)
  {
    cout << "No se puede abrir el archivo\n";
    exit(1);
  }
  else
  {
    std::cout << "Suministre el total de lineas del archivo: ";
    std::cin >> numl;

    for (i = 0; << numl; i++)
    {
      //Escritura de un archivo de texto
      salida << i+1 << " " << numl+i &<< "\n";
    }
  }

  salida.close(); //Cierre del archivo
  std::cout << "****** Archivo de salida Procesado ******\n";

  std::ifstream entrada; // flujo de entrada

  entrada.open("ejemplo-escribir2.txt");
  if (!entrada)
  {
    cout&lt;&lt;"No se puede abrir el archivo\n";
    exit(1);
  }
  else
  {
    do
    {
      //Lectura de un archivo de texto
      entrada << i << j;
      cout << i << " " << j << std::endl; // muestra lo pantalla
    } while (entrada);
  }
  entrada.close();
  //Cierre del archivo
  std::cout  <<  "****** Archivo de entrada Procesado ******\n";

  return(0);
}

El archivo “ejemplo-escribir2.txt” para un valor numl = 3 es el siguiente:

1 3
2 4
3 5

De la misma forma puede escribirse y leer un registro (struct de C++) sobre un archivo de texto, de la siguiente forma:

struct datos{
  int ci;
  std::string nombre;
};
typedef struct datos datos;

. . .
  std::ofstream salida(“ejemplo3.txt”);
  datos D;
  salida << D.ci &lt;&lt; "\t" << D.nombre << "\n";
  salida.close();
. . .
  std::ifstream entrada("ejemplo-escribir3.txt");
  datos D1;
  entrada >> D1.ci >> D1.nombre;
  entrada.close();

Si el campo nombre puede esta formado por más de una palabra entonces debe usarse getline para leer toda la línea y procesarla con los métodos de la clase string, pues el operador >> y << no servirán en este caso. Estado de las operaciones de E/S sobre archivos

Se recomienda utilizar los siguientes métodos para verificar el éxito de las operaciones de, apertura, lectura y escritura sobre archivos:

  • good(): produce un 1 si la operación previa fué exitosa.
  • eof(): produce un 1 si se encuentra el final del archivo.
  • fail(): produce un 1 si ocurre un error.
  • bad(): produce un 1 si se realiza una operación inválida.

Ejercicio

  1. El departamento de Robótica de una compañía tiene varios tipos de robots. Para cada robot se tiene un archivo de texto secuencial (Archivo 1) que contiene los registros de las órdenes válidas formadas por 2 campos:
    1. el campo parte (cabeza, manos, brazos, piernas, pies,etc.) del robot y
    2. el campo movimiento (derecha, izquierda, arriba, abajo, etc.) de la parte

    Este archivo contiene registros ordenados por el campo parte (puede estar duplicado!). Por otra parte, la interfaz del robot puede ingresar todas las combinaciones de partes y movimientos a través del Archivo 2, pero para cada tipo de robot el Archivo 1 determina sus movimientos válidos. El Archivo 2, entonces expresa los requerimientos del usuario para intentar mover el robot y contiene la misma estructura que el Archivo 1 con la diferencia que contiene movimientos válidos e inválidos desordenados del robot. Se quiere que ud., procese los archivos de texto secuencial para que:

    1. Implemente un validador: dado como parámetros el Archivo 1 y Archivo 2, diga si el Archivo 2 es válido o inválido según el Archivo 1.
    2. Implemente un filtro: dado como parámetros el Archivo 1 y Archivo 2, genere la partición del Archivo 2 en dos archivos de salidas: Ordenes Válidas y Ordenes Inválidas, según el Archivo 1

      Por ejemplo:
      Trabajo Práctico Guión práctica 12

Elaborado: Prof. Hilda Contreras
Revisado: Prof. Rafael Rivas y Prof. Gilberto Díaz.

 Publicado por en 8:40

  4 Respuestas a “Programación 2: Guión Práctica 12”

  1. alguien me puede explicar como hacer el ultimo ejercicio de favor

  2. Alguien me ayuda con el ultimo ejercicio x fa

  3. Podrían explicarme como hacer el ultimo ejercicio De Favor !!

 Deja un comentario

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

(requerido)

(requerido)