2010-10-07 11 views
5

std::istream tiene el prototipo istream& read (char* s, streamsize n) la real número de bytes de lectura debe ser obtenido llamando istream::gcount(), también la validez de la istream puede ser conocido a partir ios::good.Comprender el diseño de std :: :: istream leer

Estaba discutiendo la implementación de otra clase de flujo que estaba tratando de escribir con un colega mío, donde estaba diciendo que podría seguir este diseño; pero dijo que en lugar de hacer que el usuario llame a gcount cada vez, uno podría tener un prototipo de lectura como este istream& read (char* s, streamsize n, size_t &bytes_read) para que termine en una sola llamada y el primero sea más torpe. No pude defender la elección de diseño de std. ¿Cuál es la verdadera razón detrás de istream::read?

+0

¿Quisces decir 'size_t & bytes_written'? Y, probablemente debería ser 'streamsize & bytes_written' (o quizás' chars_read'). –

+0

@James: ¡Sí, gracias! Los bytes y los caracteres son sinónimos aquí, ya que 'sizeof' es el mismo :) – legends2k

Respuesta

4

Supongo que es porque C++ no suele forzar una interfaz que puede no ser necesaria para todos. Si necesita read para aceptar un parámetro que a algunas personas no les importa, entonces causa un trabajo de codificación adicional (declarando un int extra para pasar como parámetro). También guarda siempre los bytes leídos independientemente de si le importa al cliente o no (algunos clientes pueden preocuparse de que la lectura falle, como lo indican los bits eof/fail).

Con un método separado, desacopla la interfaz para diferentes partes de información que pueden o no ser necesarias.

0

std::istream tiene el prototipo istream& read (char* s, streamsize n) la real número de bytes leídos debe ser obtenido llamando istream::gcount(), también la validez de la istream puede ser conocido a partir ios::good.

istream::read(char* s, streamsize n) lee un bloque sin formato de los datos (sin NULL terminación) de tamaño n en la matriz en s. Aunque s es un puntero a char, puede usar istream::read para leer datos binarios. Por ejemplo, usted podría tener un istream que contiene los valores de una matriz de dobles (suponiendo que el orden de bits es correcta):

unsigned int count; 
input.read(reinterpret_cast<char*>(&count), sizeof(count)); 
double* data = new double[count]; 

for (unsigned int i = 0; i < count; ++i) 
    input.read(reinterpret_cast<char*>(data[i]), sizeof(double)); 

istream::gcount() devuelve el número de bytes leídos en el último istream::read llamada. En este caso, vemos que el tamaño de count es probablemente diferente del tamaño de double, por lo tanto, no podríamos usar istream::gcount() para especificar el tamaño del primer elemento en la matriz data.

+0

@CashCow Tiene la solución correcta a las limitaciones de' istream :: read'. No puedo votar porque no tengo al menos 15 puntos de reputación (todavía soy un Stack Overflow n00b). –

+0

Mi verdadera pregunta era, ¿por qué tenemos que llamar 'gcount'; en cambio, ¿por qué no tener como que la persona que llama puede pasar una variable de referencia, que se establecerá por 'lectura 'a la cantidad de bytes realmente leídos (que pueden ser menores o iguales a' tamaño de secuencia n'), en lugar de la llamada llamante gcount cada vez. – legends2k

+0

Parece preferible devolver el número de bytes leídos como @CashCow explicado con 'istream :: readsome'. Como explicó @Mark B, evita tener que declarar un int extra para pasar por referencia. Otra opción es pasar un puntero a la variable que está predeterminada como 'NULL', que puede usarse para ignorar el número real de bytes leídos:' istream & read (char * s, streamsize n, streamsize * bytesRead = NULL) '. Sin embargo, no sé si ofrecerá una ventaja significativa sobre 'istream :: readsome'. –

2

Pruebe el comando readsome lugar,

streamsize readsome (char* buf, streamsize num); 

buf es su búfer y num es el número de bytes que desea leer, como máximo el número de bytes disponibles en su memoria intermedia, por supuesto.

El valor de retorno es el número de bytes realmente leídos.

para leer un archivo al final puede recorrer:

char buf[BUF_SIZE] 
streamsize bytesRead; 
do 
{ 
    bytesRead = instr.readsome(buf, BUF_SIZE); 
    // do stuff with the bytes you read, if any 
} while (bytesRead == BUF_SIZE); 
0

En respuesta a la pregunta original, teniendo llamadas de verificación de error fue un estilo de programación popular cuando C era joven, pero pasó de moda pronto después. Lo que sucede son pequeñas cosas que no están muy mal, pero que, sin embargo, son casi siempre un poco inferiores por un tiempo hasta que la comunidad las llama y las tilda de malas. Este código tiene la mala fortuna de haber sido escrito antes de que ese pequeño antipatrón fuera ampliamente discutido.

En respuesta a la solución de Cash Cow, creo que hay un error. Si está esperando IO y tiene suficientes caracteres para llenar parcialmente el búfer, la función volverá y el bucle while finalizará antes de que el archivo se lea completamente. Por lo tanto, su solución probablemente se ejecutaría correctamente si se escribiera sobre IO crudo directo, pero no funcionaría con IO amortiguado.

La solución correcta, por supuesto, sería finalizar el ciclo while cuando se establece el indicador EOF. No estoy seguro en este momento cuál es la mejor respuesta cuando se establece badbit, pero probablemente también debería manejar ese caso.

Estoy de acuerdo en que readsome es una buena alternativa de lectura.

Edit: Algunas veces readsome no está disponible (algunas versiones de VC++). En este caso, leer no es inutilizable.

Cuestiones relacionadas