Inicio > C++, Cómo hacer, WIN-32 > Cómo leer datos de un archivo

Cómo leer datos de un archivo


En la entrada sobre manipulación de archivos, expliqué cómo le podemos hacer para abrir, crear, copiar y eliminar archivos. Pero no hablé sobre cómo escribir a estos archivos, o bien leer desde los mismos. Esta entrada trata sobre cómo leer datos (la de escritura la dejaré para otra entrada). Por consiguiente, no voy a detallar aquí cómo abrir y cerrar los archivos: lee la entrada anterior si tienes dudas.

Bueno. En esencia, el API de Windows nos provee la función ReadFile para leer datos, y tiene el siguiente prototipo:

BOOL WINAPI ReadFile(
  HANDLE hFile,
  LPVOID lpBuffer,
  DWORD nNumberOfBytesToRead,
  LPDWORD lpNumberOfBytesRead,
  LPOVERLAPPED lpOverlapped
);

de donde los parámetros son:

  • hFile. El handle del archivo del cuál se leerá. Dicho handle se obtiene al abrir (o crear) un archivo con CreateFile, y por supuesto, debe abrirse con permisos de lectura.
  • lpBuffer. Es la estructura binaria que contendrá los bytes a leer del archivo.
  • nNumberOfBytesToRead. Indica el número de bytes que se pretenden leer. Usualmente, si se emplea un tipo de dato, será el tamaño de este (i.e. si leeremos en un int, entonces el valor de este parámetro sería sizeof(int)); si escribimos en un búfer de caracteres, entonces sería el tamaño total de dicho búfer (i.e. si nuestro búfer es un char de 10 caracteres, entonces el valor del parámetro sería sizeof(char)*10).
  • lpNumberOfBytesRead. Un puntero a un DWORD que nos regresará el número de caracteres leídos (usualmente, será igual a nNumberOfBytesToRead a menos que se llegue al final del archivo, o que haya habido algún error, i.e. no había suficiente memoria o el búfer es muy chico). Si este dato no se necesita, puede ser NULL.
  • lpOverlapped. Un puntero a la estructura OVERLAPPED. Si nuestro archivo se abrió (o creó) con la bandera FILE_FLAG_OVERLAPPED, este parámetro nos regresa la información relacionada. Al ser opcional, puede ser un NULL. Eso del "overlapped" se emplea cuando escribimos un archivo de forma asíncrona (digamos, a un dispositivo USB, donde nos interesa que nuestra aplicación no espere a que se termine de pasar la información).

Si todo sale bien, nos regresará un valor distinto de cero. Si algo sale mal, nos regresará cero. En este caso, podemos consultar a GetLastError para obtener información del error. En particular, nos interesará revisar si ésta función nos regresa ERROR_INSUFFICIENT_BUFFER, en cuyo caso quiere decir que nos vimos avaros en la asignación de memoria del búfer.

El siguiente ejemplo muestra cómo leer enteros desde un archivo.

int main()
{
   HANDLE hFile;
   int val1, val2, val3;

   val1 = val2 = val3 = 0;

   hFile = CreateFile(_T("C:\\archivo.txt"), GENERIC_READ, FILE_SHARE_READ,
               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   if (hFile == INVALID_HANDLE_VALUE)
   {
      cout << "Error al abrir el archivo. " << endl;
   }
   else
   {
      ReadFile(hFile, &val1, sizeof(int), NULL, NULL);
      ReadFile(hFile, &val2, sizeof(int), NULL, NULL);
      ReadFile(hFile, &val3, sizeof(int), NULL, NULL);

      cout << "Valor 1: " << val1 << endl;
      cout << "Valor 2: " << val2 << endl;
      cout << "Valor 3: " << val3 << endl;

      CloseHandle(hFile);
   }

   return EXIT_SUCCESS;
}

Nota que en CreateFile, tenemos que especificar que vamos a hacer operaciones de lectura.

Si en nuestro archivo de ejemplo tuviéramos los siguientes valores (vistos desde, digamos, notepad):

A[NULL]B[NULL]C[NULL] 

de donde [NULL] especifica que hay un byte con valor 0, la salida del programa anterior sería:

Valor 1: 64
Valor 2: 65
Valor 3: 66

Recordemos que aquí leemos bytes, y los bytes son valores numéricos. La interpretación que le demos a los mismos es lo que determina la forma en la que tenemos que recibir los datos. Es decir, en este ejemplo los recibimos en un entero, pero bien pudimos haberlos recibido en caracteres y hacer una interpretación completamente diferente:

int main()
{
   HANDLE hFile;
   char val1, val2, val3;
   char aux;

   val1 = val2 = val3 = 0;
   aux = 0;

   hFile = CreateFile(_T("C:\\archivo.txt"), GENERIC_READ, FILE_SHARE_READ,
               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   if (hFile == INVALID_HANDLE_VALUE)
   {
      cout << "Error al abrir el archivo. " << endl;
   }
   else
   {
      ReadFile(hFile, &val1, sizeof(char), NULL, NULL);
      ReadFile(hFile, &aux, sizeof(char), NULL, NULL);
      ReadFile(hFile, &val2, sizeof(char), NULL, NULL);
      ReadFile(hFile, &aux, sizeof(char), NULL, NULL);
      ReadFile(hFile, &val3, sizeof(char), NULL, NULL);

      cout << "Valor 1: " << val1 << endl;
      cout << "Valor 2: " << val2 << endl;
      cout << "Valor 3: " << val3 << endl;

      CloseHandle(hFile);
   }

   return EXIT_SUCCESS;
}

En cuyo caso, la salida del programa anterior sería:

Valor 1: A
Valor 2: B
Valor 3: C

El mismo principio aplica si queremos leer desde cualquier tipo de dato, digamos, una estructura:

struct Estructura
{
   int val1;
   long val2;
   double val3;
   char val4[20];
};

int main()
{
   HANDLE hFile;
   Estructura estructura;

   hFile = CreateFile(_T("C:\\archivo.txt"), GENERIC_READ, FILE_SHARE_READ,
               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   if (hFile == INVALID_HANDLE_VALUE)
   {
      cout << "Error al abrir el archivo. " << endl;
   }
   else
   {
      ReadFile(hFile, &estructura, sizeof(Estructura), NULL, NULL);

      cout << "Valor 1: " << estructura.val1 << endl;
      cout << "Valor 2: " << estructura.val2 << endl;
      cout << "Valor 3: " << estructura.val3 << endl;
      cout << "Valor 4: " << estructura.val4 << endl;

      CloseHandle(hFile);
   }

   return EXIT_SUCCESS;
}

Y así sucesivamente. Supongamos ahora que el archivo tiene simplemente texto, y lo queremos leer y mostrar en pantalla. Ejemplirijillo:

int main()
{
   HANDLE hFile;
   TCHAR str[51];

   hFile = CreateFile(_T("C:\\archivo.txt"), GENERIC_READ, FILE_SHARE_READ,
               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   if (hFile == INVALID_HANDLE_VALUE)
   {
      cout << "Error al abrir el archivo. " << endl;
   }
   else
   {
      while (ReadFile(hFile, str, sizeof(TCHAR) * 50, NULL, NULL))
      {
         cout << sz;
      }

      CloseHandle(hFile);
   }

   return EXIT_SUCCESS;
}

Así, todo lo que tenga nuestro archivo se mostrará en la pantalla, tal cual.

Anuncios
Categorías:C++, Cómo hacer, WIN-32 Etiquetas: ,
  1. Aún no hay comentarios.
  1. septiembre 28, 2010 en 9:00 am

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s