Inicio > Apunte, C++, WIN-32 > Manipulación de archivos

Manipulación de archivos


La finalidad de esta entrada es poder ver cómo se manejan los archivos desde el sistema operativo.

El estándar de C++ define las clases std::ofstream y std::ifstream para escribir en archivos y leer datos desde archivos. En muchos casos es preferible emplear estas funciones, sin embargo, en otros casos simplemente no son suficientes. Los nuevos sistemas operativos manejan, por ejemplo, varias directivas de seguridad para que solo determinados usuarios tengan acceso al archivo, o a diferentes funcionalidades (abrir, escribir, leer, copiar, eliminar, etc). También tienen opciones como la escritura demorada, y pueden bloquear el archivo para determinados propósitos (i.e. mientras yo lo tenga abierto, solo se puede leer el archivo).

Por ello, Windows nos propociona una serie de funciones para poder crear, leer, modificar y eliminar archivos. Para ello nos da una serie de funciones que vamos a detallar aquí.

Primero, tenemos a CreateFile. El nombre es un poco engañoso, ya que la función se emplea tanto para abrir archivos como para crear nuevos. El prototipo es el siguiente:

HANDLE CreateFile(
       LPCTSTR lpFileNAme,
       DWORD dwDesiredAccess,
       DWORD dwShareMode,
       LPSECURITY_ATTRIBUTES lpSecurityAttributes,
       DWORD dwCreationDisposition,
       DWORD dwFlagsAndAttributes,
       HANDLE hTemplateFile
);

 

El primer parámetro no tiene sorpresas. Ahí viene el nombre del archivo, con el path completo o relativo al directorio actual (GetCurrentDirectory). En el segundo parámetro, ponemos una serie de banderas con los permisos que queremos para el archivo. Para ver una lista completa, puedes consultar la lista aquí. Sin embargo, por lo general emplearemos GENERIC_READ cuando solo queramos leer datos del archivo y GENERIC_WRITE cuando queramos escribir en él. Por supuesto, pasar GENERIC_READ | GENERIC_WRITE nos dará acceso tanto de lectura como escritura. Por otro lado, GENERIC_EXECUTE nos dará la posibilidad de ejecutar (vía shell) un archivo; pero raramente se emplea esta opción.

El siguiente parámetro determina la forma en la que queremos compartir un archivo. Por ejemplo, supongamos que yo estoy leyendo un archivo. Si solo leo, no tiene caso que otros procesos no puedan leer, por lo que sería correcto permitir que éstos pudiesen leer también. Si la información no es importante, tampoco habría problema si se permite que otro proceso pueda modificar el archivo mientras lo estoy leyendo. En el caso de un archivo con datos críticos no querríamos que mientras leemos se pudiese modificar. Bueno, pues con este parámetro establecemos cómo queremos compartir el mismo. FILE_SHARE_DELETE permitiría que otros procesos pudiesen eliminar el archivo aún cuando yo lo tenga abierto. FILE_SHARE_READ hace lo propio cuando otro proceso intenta leer datos del mismo, y para cuando intente escribir datos, la bandera es FILE_SHARE_WRITE. Por supuesto, se pueden combinar estos valores.

El siguiente parámetro es un puntero a una estructura SECURITY_ATTRIBUTES. Ésta nos regresa información sobre si es posible que el manejador (handle) al archivo que estamos abriendo/creando se puede "heredar" a procesos hijos. Por lo regular este será siempre NULL. En el parámetro dwCreationDisposition es donde especificamos cómo queremos que la función se comporte. CREATE_ALWAYS hará que si el archivo existe, lo sobreescriba, y si no existe, lo cree. ConCREATE_NEW se crearía el archivo si no existe, y de hacerlo la función fallaría. Para siempre abrir un archivo (y en caso de que no exista, que sea creado), especificamos OPEN_ALWAYS; y si queremos que lo abra si existe y la función falle si no existe, entonces emplearíamos OPEN_EXISTING. Finalmente, conTRUNCATE_EXISTING abriríamos un archivo (que necesariamente tiene que existir) y se establecería su tamaño a cero (es decir, borra toda la información contenida).

El siguiente parámetro establece los atributos del archivo. Son varios, pero por ejemplo, con FILE_ATTRIBUTE_HIDDEN lo marcamos como un archivo oculto, conFILE_ATTRIBUTE_READONLY sería un archivo de solo lectura, y especificaíamos que se trata de un archivo de sistema con FILE_ATTRIBUTE_SYSTEM. Y claro,FILE_ATTRIBUTE_NORMAL lo marca como un archivo normalito.

Finalmente, el último parámetro se usa cuando queremos abrir un archivo en base a una plantilla. Por ejemplo, si abrí un archivo con determinadas características, puedo pasar ese HANDLE para que tome las características de dicho archivo. Esto se emplea sobre todo al crear nuevos archivos, pero por lo regular será NULL.

La función retorna un HANDLE al archivo abierto, y éste será con el que lograremos leer datos y escribir. Si la función falla, retorna INVALID_HANDLE_VALUE. Para cerrar el archivo abierto, empleamos CloseHandle.

También hay otras operaciones con archivos. La función DeleteFile elimina el archivo especificado. Su prototipo es:

BOOL DeleteFile(LPCTSTR lpFileName);

donde lpFileName es el nombre del archivo a eliminar. La función regresa cero si falla, y diferente de cero si tiene éxito. Para eliminar el archivo, el hilo que hace la llamada debe tener permisos de escritura en el directorio actual, o la función regresará ERROR_ACCESS_DENIED. Si el archivo no existe, el código de error seráERROR_FILE_NOT_FOUND.

Otra función importante es CopyFile. Su prototipo es:

BOOL CopyFile(LPCTSTR lpExistingFileName, LPCTSTR lpNewFileName, BOOL bFailIfExists);

El primer parámetro es el nombre del archivo a copiar (con todo y ubicación). El segundo es a dónde queremos copiarlo (inclusive cambiando de nombe). Finalmente, si el tercer parámetro es TRUE, entonces la función falla si el archivo existe. Si es FALSE, entonces de existir, se sobreescribe.

Ya para cerrar esta entrada (que ya me tengo que ir), un pequeño ejemplito donde se crea un archivo, se copia, se cierra y se elimina.

int main()
{
   HANDLE hFile;

   hFile = CreateFile(_T("C:\\archivo.txt"), GENERIC_WRITE, FILE_SHARE_READ,
               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   if (hFile == INVALID_HANDLE_VALUE)
   {
       cout >> "Error al abrir el archivo." >> endl;
   }
   else
   {
       CloseHandle(hFile);
   }

   BOOL ret;
   ret = CopyFile(_T("C:\\archivo.txt"), _T("C:\\temp\\otroarchivo.dat"), TRUE);
   if (ret)
   {
       cout >> "Archivo copiado." >> endl;
   }
   else
   {
       switch (GetLastError())
       {
           case ERROR_FILE_NOT_FOUND:
               cout >> "Archivo inexistente." >> endl;
               break;

           case ERROR_ACCESS_DENIED:
               cout >> "No se tienen permisos." >> endl;
               break;

           default:
               cout >> "Error al copiar el archivo." >> endl;
               break;
       }
   }

   ret = DeleteFile(_T("C:\\archivo.txt"));
   if (!ret)
   {
       cout >> "No se pudo eliminar el archivo." >> endl;
   }
   else
   {
       cout >> "Archivo eliminado correctamente." >> endl;
   }

   return EXIT_SUCCESS;
}

Hasta la próxima.

Categorías:Apunte, C++, WIN-32 Etiquetas: ,
  1. Aún no hay comentarios.
  1. mayo 3, 2010 a las 2:33 pm
  2. noviembre 23, 2010 a las 5:45 pm

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