Flujos en C++ (Streams) Entrada/Salida en C++ Programación Orientada a Objeto Ing. Civil en Telecomunicaciones Hasta aquí, hemos usado cin y cout para leer desde teclado y escribir a consola C++ no incluye comandos de entrada/salida en el lenguaje Definidos en bibliotecas de E/S Objetivo: tratar todas las fuentes de datos (teclado, archivos, redes) de la misma forma: como flujos de bytes de largo indefinido Clases de entrada/salida Biblioteca de entrada/salida de C++ define una jerarquía de clases Flujos y buffers Escribir a pantalla o a archivos es lento Sistema mantiene buffers en memoria para acoplar velocidades Datos se reciben del teclado a un buffer, donde quedan disponibles hasta que el programa los necesita Datos se escriben en un buffer en vez de escribir directamente en un archivo Buffer se escribe al archivo cuando está lleno Flujos y buffers Clase abstracta streambuf No todos los flujos utilizan buffers En algunos casos, se escriben los datos directamente al destino sin pasar por el buffer intermedio Ejemplo: cout y clog usan buffers, cerr no usa buffers La clase base abstracta streambuf maneja el buffer Sus funciones miembro permiten leer, escribir, sincronizar, vaciar y escribir a memoria los flujos Funciones no se invocan directamente Clases derivadas son stringbuf y filebuf 2015 Mario Medina C. 1
Clases de entrada/salida Estado de un flujo La clase ios es la clase base para los flujos de entrada y salida Define todas las funciones comunes a flujos de entrada y de salida Contiene un objeto streambuf Métodos manipuladores de formato Maneja los bits de estado del flujo eofbit, badbit, failbit, goodbit goodbit indica que todo está OK failbit es 1 si una operación no se procesó correctamente pero el flujo está OK badbit es 1 si el flujo está corrupto o si se han perdido datos eofbit es 1 si se detectó el fin de flujo Generalmente se activa con failbit Clase de entrada istream Clase de salida ostream Clase istream representa objetos usados para leer secuencias de caracteres Datos con formato son accedidos usando el operador istream::operator>> double a, b, c; cin >> a >> b >> c; Datos sin formato son accedidos a través de otras operaciones get(), getline(), read() Clase ostream representa objetos usados para escribir secuencias de caracteres Datos con formato son accedidos usando el operador istream::operator<< double a, b, c; cout << a << b << c; Datos sin formato son accedidos a través de otras operaciones put(), write() Clases generales de entrada/salida Clase de entrada/salida iostream Clases generales de entrada/salida <iostream>: entrada/salida estándar <fstream>: entrada/salida de archivos <sstream>: entrada/salida hacia/desde strings Clase para manipulación de flujos <iomanip>: manipulación de flujos Clase iostream deriva métodos de istream y de ostream Define 4 flujos estándar cin: entrada estándar de teclado cout: salida estándar a consola cerr: salida estándar de error clog: salida estándar de bitácora Estos flujos pueden ser manipulados por operadores >>, << o por otras funciones 2015 Mario Medina C. 2
Función istream::get() (I) int get() lee el siguiente caracter desde un flujo de entrada y lo retorna Retorna el siguiente caracter en el flujo, o retorna EOF char c = cin.get(); Función istream::get() (II) iostream& get(char& c) lee un caracter desde un flujo de entrada y lo almacena en el caracter c Retorna el flujo de entrada, por lo que puede ser usado en concatenaciones cin.get(a).get(b).get(c); cin.get(a) >> b >> c; Función istream::get() (II) iostream& get(char* p, int n, char delim) lee n - 1 caracteres desde un flujo de entrada y los almacena a partir del puntero p dado, retornando el flujo de entrada Función almacena caracter NULL en el último byte del área destino Lectura se detiene al llegar al delimitador Si se omite delimitador, asume \n Delimitador queda en flujo de entrada Función istream::getline() iostream& getline(char* p, int n, char delim) lee n - 1 caracteres desde un flujo de entrada y los almacena a partir del puntero p dado, retornando el flujo de entrada Función almacena caracter NULL en el último byte del área destino Lectura se detiene al llegar al delimitador Si se omite delimitador, asume \n Caracter delimitador es removido del flujo Función istream::read() Función istream& read(char *p, n) lee n bytes desde el flujo de entrada, y los almacena a partir del puntero p dado Retorna el flujo de entrada Termina anticipadamente al encontrar EOF En ese caso, se activa failbit y eofbit gcount() retorna número de caracteres leídos Función istream::readsome() streamsize readsome(char *p, n) lee n bytes desde el flujo de entrada, y los almacena a partir del puntero p dado Lee todos los bytes disponibles en el buffer Retorna el número de caracteres leídos No termina anticipadamente con EOF gcount() retorna número de caracteres leídos 2015 Mario Medina C. 3
Función istream::ignore() iostream& ignore(int n, char delim) lee n caracteres desde un flujo de entrada y los ignora Lectura se detiene si encuentra delim Delimitador es removido del flujo de entrada Si éste se omite, el delimitador por omisión es EOF Retorna el flujo de entrada istream::ignore() ignora un caracter Función istream::gcount() Función gcount() retorna el número de caracteres extraídos del flujo por la operación de lectura anterior Aplicable a funciones : get(), getline(), ignore(), peek(), read(), readsome(), putback() y unget() En los casos de unget() y putback(), gcount() siempre retorna 0 Función istream::peek() int peek() lee el siguiente caracter desde el flujo de entrada, y luego lo retorna al flujo int a = cin.peek(); En caso de error, retorna EOF Siguiente caracter queda entonces disponible en el flujo para la siguiente lectura Función istream::unget() istream& unget() devuelve el último caracter leído al flujo de entrada, y decrementa el puntero de lectura get pointer en 1 Función retorna el flujo de entrada Llamada posterior a gcount() retorna 0 Función istream::putback() istream& putback(char c) retorna caracter c al flujo, y decrementa el puntero de lectura en el flujo get pointer en 1 cin.putback(c); La función retorna el flujo de entrada Similar a unget(), pero es posible definir el caracter a retornar al flujo Si c no fue el último carácter extraído, se activa badbit Función istream::sync() Fuerza el vaciado de los buffers del flujo de entrada, sincronizando su contenido Aplicable a flujos istream Caracteres aún no leídos en el flujo de entrada son descartados 2015 Mario Medina C. 4
Función ostream::put() Función ostream::write() La función ostream& put(char c) escribe el caracter c en el flujo de salida Aplicable a flujos de salida ostream Incrementa el put pointer en 1 Retorna el flujo de salida El estado del flujo indica si la operación fue exitosa Función ostream& write(char *p, n) escribe n bytes a partir del puntero p dado en el flujo de salida Retorna el flujo de salida El estado del flujo indica si la operación fue exitosa Función ostream::flush() Función ostream& flush() fuerza la escritura de los buffers del flujo, sincronizando su contenido Aplicable a flujos ostream Función retorna el flujo de salida Fin de línea endl también fuerza un flush de los buffers Funciones de estado Para determinar estado del flujo bad() es true si hubo falla en operación de lectura ó escritura fail() es true si hubo falla en lectura ó escritura, u error de otro tipo Ejemplo: conversión de formatos eof() es true si se llegó al fin del flujo good() es true si todas las funciones anteriores son false clear() limpia el estado del flujo Punteros a flujos Objetos de la biblioteca mantienen punteros a flujos para lectura y/o escritura Clase istream incluye el get pointer, que apunta a la próxima posición a leer Clase ostream incluye el put pointer, que apunta a la próxima posición donde escribir Clase iostream incluye ambos punteros Posiciones están dadas en caracteres Lectura de punteros a flujos Funciones tellg() y tellp() retornan un entero representando la posición absoluta de get pointer y put pointer, respectivamente Posición está dada en caracteres Falla es indicada por resultado -1 Función retorna el flujo asociado tellg() pertenece a clase istream tellp() pertenece a clase ostream 2015 Mario Medina C. 5
Movimiento de punteros Movimiento de punteros Funciones seekg() y seekp() definen nuevas posiciones del get pointer y put pointer istream& seekg(offset, pos) Posición pos está dada en caracteres No todos los flujos admiten funciones seekg() y seekp() No son válidas para flujos estándares cin, cout y cerr Posición puede ser relativa al comienzo del flujo o relativa a otra posición seekg(offset, pos), donde offset es ios::beg: comienzo del flujo ios::end: final del flujo ios::cur:posición actual del flujo Comportamiento ante accesos fuera del flujo no está definido Movimiento de punteros Manejo de archivos #include <fstream>... ifstream if( archivo.txt, istream::binary); if (is) { is.seekg(0, is.end); int largo = is.tellg(); // Calcula el largo is.seekg(0, is.beg); char *buffer = new char[largo]; is.read(buffer, largo); // Lee todo el archivo if (is) cout << Se leyeron << is.gcount() << bytes << endl; is.close() } Hay 3 clases para manipular archivos ifstream: usada para leer desde un archivo ofstream: usada para escribir a un archivo fstream: usada para leer y escribir a un archivo Archivos pueden ser abiertos en modo texto o modo binario Modo texto: interpreta caracteres especiales Modo binario: no hay caracteres especiales Manejo de archivos: open() y close() fstream f; f.open(nombre, modo) nombre es el nombre del archivo como un string de C modo indica el modo de operación con el archivo Flujo se cierra con f.close() Flujo también se cierra al destruir el objeto Modos de open() Modos de open() ios::in: abrir para entrada de datos ios::out: abrir para salida de datos ios::binary: abrir en modo binario ios::ate: abrir con posición inicial al final del archivo (at end) ios::app: abrir para agregar datos (append). Se usa en conjunto con ios::out ios::trunc: abrir con posición inicial el comienzo del archivo, y se borra su contenido 2015 Mario Medina C. 6
Modos por omisión Creación y apertura de archivos Modos se deducen del tipo de archivo ifstream arch1( entrada.txt ); Se agrega modo ios::in automáticamente ofstream arch2( salida.txt ); Se agrega ios::out automáticamente fstream arch3( datos.txt ); Se agregan modos ios::in y ios::out automáticamente Constructor por omisión de flujos de archivos también abren el flujo ofstream arch1; arch1.open( datos.txt", ios::out ios::app ios::binary); Equivale a ofstream arch1( datos.txt", ios::out ios::app ios::binary); Nótese cómo combinar modos usando Archivos binarios Manipuladores de entrada/salida No se reconocen caracteres especiales No se consideran delimitadores, espacios, ó saltos de línea Acceso mediante read() y write() char buffer[1000]; f.read(buffer, 1000); f.write(buffer, 1000); Objetos especiales para manipular flujos Usados con operadores << y >> Manipuladores de salida (clase ostream) endl: escribe \n y sincroniza buffer de salida ends: escribe \0 en el buffer de salida flush: escribe el buffer de salida a su destino Manipuladores de entrada (clase istream) ws: lee y descarta espacios en blanco Muchos flujos tienen esta opción activada por omisión Definidos en <iomanip> setbase: define la base de los números a desplegar. Puede ser 8, 10 ó 16 cout << setbase(16) << 100 << endl; oct, dec, hex: definen la base a usar cout << hex << 100 << endl; setw: Define el ancho del próximo campo cout << setw(7) << 100 << endl; setprecision: define la precisión decimal del siguiente número cout << setprecision(7) << 3.1415; setfill: define el caracter a usar como relleno en un número cout << setw(7) << setfill( a ) << 433; Tiene como salida aaaa433 2015 Mario Medina C. 7
Definidos en ios boolalpha/noboolalpha: Imprime true o false para valores booleanos. showpos/noshowpos: Controla impresión de signo + para los números positivos uppercase/nouppercase: Usa mayúsculas en números de punto flotante showpoint/noshowpoint: Siempre imprime el punto en números de punto flotante Definidos en ios showbase/noshowbase: Siempre imprime la base de un número skipws/noskipws: Ignora los espacios en blanco al leer del flujo unitbuf/nounitbuf: Siempre sincroniza el flujo después de cada operación inserción en éste fixed/scientific: tipo de notación a usar en el flujo Definidos en ios left: alinea número a la izquierda en el campo de largo dado por setw y rellena el campo con el caracter dado por setfill right: alinea número a la derecha en el campo de largo dado por setw y rellena el campo con el caracter dado por setfill internal: alinea número en el campo de acuerdo a un valor interno, y rellena el campo con el caracter dado por setfill Definidos en iomanip setiosflags: activa los flags de formato del flujo de acuerdo a una máscara resetiosflags: desactiva los flags de formato del flujo de acuerdo a una máscara cout << hex << setiosflags(ios_base::showbase ios_base::uppercase) << 100 << endl; Imprime 0X64 Funciones de formato Todo lo que se hace con manipuladores de flujo puede realizarse con funciones de manejo de formato Definidas en ios_base Ejemplo: cout << showbase; Equivale a cout.setf(ios::showbase); Funciones de formato flags(): retorna un entero indicando los flags de formato flags(newflags): asigna un nuevo valor a los flags de formato, y retorna un entero conteniendo los flags de formato antiguos setf(newflag): asigna un nuevo valor a los flags de formato, y retorna un entero conteniendo los flags de formato antiguos unsetf(newflag): limpia los flags de formato especificados 2015 Mario Medina C. 8