Los rincones del API Win32: WinInet y FTP - Obtener información de archivos y carpetas

10 - Obtener información de archivos y carpetas

[editar]
Tutorial creado por Juan Manuel. Extraido de: http://www.lawebdejm.com
30 de Noviembre de 1999
Otro tipo de operaciones que podemos realizar con el protocolo FTP es la obtención de información de archivos y carpetas remotos.

La única información que podemos obtener de un archivo es su tamaño, a través de la función FtpGetFileSize.

Pero antes de llamar a esta función, es necesario obtener un descriptor de un archivo remoto, a través de la función FtpOpenFile:

HINTERNET FtpOpenFile( HINTERNET hConexión, LPCTSTR lpszArchivo, DWORD dwTipoAcceso, DWORD dwOpciones, DWORD_PTR dwContexto );

  • hConexión: un descriptor de conexión obtenido a través de InternetConnect.
  • lpszArchivo: un puntero a una cadena en la que se pasa la ruta (absoluta o relativa) del archivo que queremos abrir.
  • dwTipoAcceso: el tipo de acceso que se va utilizar con fichero. Se puede utilizar el valor GENERIC_READ o GENERIC_WRITE.
  • dwOpciones: las opciones de acceso al fichero, desde el punto de vista de el tipo de transmisión:
    • FTP_TRANSFER_TYPE_ASCII: utiliza el tipo de transferencia ASCII propia de los servidores FTP.
    • FTP_TRANSFER_TYPE_BINARY: utiliza el tipo de transferencia binaria propia de los servidores FTP.
    • FTP_TRANSFER_TYPE_UNKNOWN: igual que FTP_TRANSFER_TYPE_ASCII.
    • INTERNET_FLAG_TRANSFER_ASCII: utiliza codificación ASCII estándar.
    • INTERNET_FLAG_TRANSFER_BINARY: utiliza codificación binaria estándar.
      Y desde el punto de vista del caché interno se puede configurar los siguientes aspectos:
    • INTERNET_FLAG_HYPERLINK: fuerza a cargar si no hay datos sobre la caducidad o la última modificación.
    • INTERNET_FLAG_NEED_FILE: guarda el contenido en un archivo temporal si no ha podido guardarse en el caché interno.
    • INTERNET_FLAG_RELOAD: vuelve a descargar el archivo, aunque esté en el caché.
  • dwContexto: el valor de contexto que queramos pasar al llamar a la función de callback.

La función retorna el descriptor del archivo si todo ha ido correctamente, o NULL si ha ocurrido algún tipo de error. Se puede llamar a GetLastError para averiguar las causas del error.

Cuando ya no necesitemos más el descriptor de archivo, debemos llamar a InternetCloseHandle para cerrarlo.

Entre la llamada a FtpOpenFile e InternetCloseHandle, no podemos llamar a ninguna otra función de WinInet, utilizando el mismo descriptor de conexión, ya que el canal de control permanece ocupado. Si hacemos una llamada a otra función (por ejemplo FtpCreateDirectory o cualquier otra) con la misma conexión, obtendremos el error ERROR_FTP_TRANSFER_IN_PROGRESS.
Una consecuencia de esto es que sólo podemos mantener abierto un archivo por cada conexión FTP.

Ahora que ya sabemos cómo obtener un descriptor de archivo con FtpOpenFile, podemos explicar el modo de utilizar la función FtpGetFileSize:

DWORD FtpGetFileSize( HINTERNET hArchivo, LPDWORD lpdwTamañoHigh );

  • hArchivo: un descriptor de archivo obtenido a través de FtpOpenFile.
  • lpdwTamañoHigh: un puntero a un valor de 32 bits en el que se almacenarán los 32 bits más altos del tamaño total del archivo. En caso de que el tamaño del archivo pueda almacenarse en un espacio de 32 bits (menos de 2 GB.), en este valor no se copiará nada.

La función retornará los 32 bits más bajos del tamaño de archivo que pueden combinarse con el parámetro lpdwTamañoHigh para obtener un valor de 64 bits con el tamaño total del archivo.

Para aquellos que no hayáis trabajado nunca a nivel de bits, vamos a hacer una pequeña pausa para explicar el modo de combinar ambos valores, a través de los operadores de desplazamiento de bits. En nuestro caso, desplazaremos 32 bits a la izquierda el valor high y haciendo un or lógico con el valor low, más o menos del siguiente modo:

  1. Paso 0: valores con los que vamos a trabajar: High: Decimal: 3991676535 Binario: 11101101111011000010011001110111 Low: Decimal: 2863659011 Binario: 10101010101011111111100000000011 Total: Decimal: 17144120176899258371 Binario: 11101101111011000010011001110111101010101010111111111
    00000000011
  2. Paso 1: desplazar el valor high 32 bits a la izquierda (se crea un valor de 64 bits). Al desplazar un número de bits a la izquierda, se rellena los espacio sobrantes con ceros. 0000000000000000000000000000000011101101111011000010011001110111 desplazado 32 bits da: 1110110111101100001001100111011100000000000000000000000000000000
  3. Paso 2: combinar con el valor high con el valor low, a través de un operación or lógica. Como sabéis, la operación or lógica nos retornará 1 cuando alguno de los operandos sea 1. High: 11101101111011000010011001110111
    00000000000000000000000000000000 or Low: 0000000000000000000000000000000010101010101011111111100000000011
    Total: 1110110111101100001001100111011110101010101011111111100000000011 Decimal: 17144120176899258371

Como veis, a partir de dos valores de 32 bits, se ha creado otro de 64 bits que contiene ambos, en la parte alta y baja.

Fácil ¿verdad? De todas formas, esta misma operación que hemos realizado a nivel de bits, se puede realizar aritméticamente más fácilmente, aplicando la siguiente ecuación:

total = (high * 4294967296) + low;

El valor 4294967296 se obtiene de sumar 1 al valor máximo para un rango de 32 bits.

Estas dos opciones, en nuestros lenguajes de programación se puede implementar muy fácilmente:

{ DWORD SizeHigh; DWORD SizeLow; DWORDLONG total; /* ¡¡ un numérico de 64 bits!! */ total = (SizeHigh << 32) | SizeLow; /* a nivel de bits */ total = (SizeHigh * (0xFFFFFFFF + 1)) + SizeLow; /* aritmeticamente */ }

Bueno, después de esta pequeña interrupción (que espero que os haya servido para entender algo más las operaciones a nivel de bits) vamos a retomar el tema que nos ocupa.

Nos quedamos en la obtención de información de los archivos y carpetas del servidor. Ya sabemos que la única información que se puede obtener de un archivo es su tamaño, con la función FtpGetFileSize. Para utilizar esta función debemos obtener un descriptor de archivo a través de FtpOpenFile, y a su vez, para llamar a esta debemos conocer el nombre del archivo al que queremos acceder. ¿Y cómo sabemos el nombre de los archivos que tiene el servidor? Pues aquí es donde enlazamos con lo siguiente: obtener información de las carpetas.

Basicamente, la información que podemos obtener de una carpeta es un listado de los archivos y otras carpetas que contiene. Para ello debemos hacer uso de dos funciones: FtpFindFirstFile para iniciar la búsqueda e InternetFindNextFile para recorrer la lista de resultados.
Vamos allá:

HINTERNET FtpFindFirstFile( HINTERNET hConexión, LPCTSTR lpszArchivo, LPWIN32_FIND_DATA lpDatos, DWORD dwOpciones, DWORD_PTR dwContexto );

  • hConexión: un descriptor de conexión obtenido a través de InternetConnect.
  • lpszArchivo: un puntero a una cadena en la que se pasa el nombre de archivo a encontrar. En este parámetro se puede pasar el valor NULL, para obtener un listado de todos el contenido del directorio activo, o bien utilizar los comodines que todos conocemos: “*” y “?”. Si se pasa un nombre de archivo, o una máscara con comodines, se puede pasar tanto la ruta absoluta como relativa.
  • lpDatos: un puntero a una estructura de tipo WIN32_FIND_DATA en la que se almacena los datos del archivo encontrado. La estructura tiene los siguientes campos.
typedef struct _WIN32_FIND_DATA { DWORD dwFileAttributes; FILETIME ftCreationTime; FILETIME ftLastAccessTime; FILETIME ftLastWriteTime; DWORD nFileSizeHigh; DWORD nFileSizeLow; DWORD dwReserved0; DWORD dwReserved1; TCHAR cFileName[260]; TCHAR cAlternateFileName[14]; } WIN32_FIND_DATA, *PWIN32_FIND_DATA; Estos campos tienen los siguientes significados:
    • dwFileAttributes: indica los atributos que tiene asignados el archivo encontrado. Este valor es una máscara de bits en la que pueden aparecen los siguientes valores:
      • FILE_ATTRIBUTE_ARCHIVE: indica que se debe marcar como “archivado”.
      • FILE_ATTRIBUTE_COMPRESSED: indica que los datos están comprimidos (sólo validos para sistemas de archivos NTFS).
      • FILE_ATTRIBUTE_HIDDEN: el archivo está oculto.
      • FILE_ATTRIBUTE_NORMAL: no tiene otros atributos asignados.
      • FILE_ATTRIBUTE_READONLY: el archivo está marcado como “sólo lectura”.
      • FILE_ATTRIBUTE_SYSTEM: el archivo es de sistema.
      • FILE_ATTRIBUTE_TEMPORARY: el archivo se ha marcado como temporal.
    • ftCreationTime: fecha en que se creó el archivo.
    • ftLastAccessTime: fecha de último acceso al archivo.
    • ftLastWriteTime: fecha de la última modificación de archivo.
    • nFileSizeHigh: 32 bits más altos del tamaño del archivo.
    • nFileSizeLow: 32 bits más bajos del tamaño del archivo.
    • dwReserved0 y dwReserved1: no se usan.
    • cFileName: el nombre completo del archivo.
    • cAlternameFileName: el nombre corto del archivo, con un máximo de 8 caracteres para el nombre y 3 para la extensión.
  • dwOpciones: configura el comportamiento de la función. Pueden utilizarse cualquier combinación de los siguientes valores.
    • INTERNET_FLAG_HYPERLINK: fuerza a cargar si no hay datos sobre la caducidad o la última modificación.
    • INTERNET_FLAG_NEED_FILE: guarda el resultado de la búsqueda en un archivo temporal si no ha podido guardarse en el caché interno.
    • INTERNET_FLAG_RELOAD: vuelve a descargar el resultado de la búsqueda, aunque esté en el caché.
    • INTERNET_FLAG_NO_CACHE_WRITE: no almacena el resultado de la búsqueda en el caché local.
  • dwContexto: el valor de contexto que queramos pasar al llamar a la función de callback.

La función retorna un descriptor de búsqueda, que nos servirá para las siguientes llamadas a InternetFindNextFile. En caso de error, la función retorna NULL y en este caso, podemos llamar a GetLastError para averiguar la causa del error. Os recuerdo, como ya sabéis todos, que si GetLastError retorna ERROR_INTERNET_EXTENDED_ERROR, debemos llamar a InternetGetLastResponseInfo para conseguir más datos sobre el error.

Una vez conseguido el descriptor de la búsqueda (el valor retornado por FtpFindFirstFile), la estructura WIN32_FIN_DATA tendrá los valores del primer archivo que cumpliese el criterio de búsqueda. Si queremos buscar el siguiente archivo, debemos hacer uso de la función InternetFindNextFile.

Os habréis fijado que esta función no empieza por “Ftp”sino por “Internet”. Hace ya unos cuantos meses, en el “”, dijimos que las funciones comenzaban por el nombre del protocolo con el que trabajaban (Http, Ftp o Gopher) excepto las que comenzaban por “Internet”, que eran para uso general o servían para varios protocolos. Este es el caso de InternetFindNextFile, que sirve tanto para una conexión FTP como Gopher. Como no explicaremos el procolo Gopher, sólo explicaré el uso de esta función aplicada al protocolo FTP.
La sintaxis es la siguiente:

BOOL InternetFindNextFile( HINTERNET hBúsqueda, LPWIN32_FIND_DATA lpDatos );

  • hBúsqueda: un descriptor de búsqueda conexión obtenido a través de FtpFindFirstFile.
  • lpDatos: un puntero a una estructura de tipo WIN32_FIND_DATA en la que se almacena los datos del archivo encontrado. En realidad este valor es un puntero genérico, pero para conexiones FTP debe pasarse un puntero a esta estructura.

La función retorna TRUE o FALSE dependiendo del éxito o error. Cuando retorne FALSE, debe comprobarse el valor de GetLastError, y si retorna el valor ERROR_NO_MORE_FILES significará que no se han encontrado más archivos que cumpliesen la condición de búsqueda.

Sabiendo esto, el uso más típico de estas funciones es el que aparece a continuación:

{ WIN32_FIND_DATA datos; HINTERNET busqueda; BOOL ok; busqueda = ::FtpFindFirstFile(hConexion, NULL, &datos, 0, 0); try { ok = (busqueda != NULL); while (ok) { /* aquí se procesa el archivo encontrado */ ok = ::InternetFindNextFile(busqueda, &datos); } if (GetLastError() != ERROR_NO_MORE_FILES) MessageBox(GetActiveWindow(), "Error buscando archivos en FTP.", "Error", MB_ICONERROR); } finally { if (busqueda) InternetCloseHandle(busqueda); } }
[editar]

12 opiniones

OTATO

MUY BUENA EXPLICACION.....
ME PARECIO EXCELENTE
AHORA SOLO KISIERA SABER COMO PONER MI CONEXION FTP DE MODO PASIVO.....SI NO ES MUCHO PEDIR
GRACIAS
Y MUY BUEN TRABAJO EH
OTATO

MUY BUENO EH
ME PARECE K ES EXCELENTE LA EXPLICACION DE ESTOS 2 PROTOCOLOS
ESTO ES BUENO CONOCER PARA TODOS
OTATO

PUES ESTA CHIDO LA EXPLICACION... PERO NO YO KISIERA SABER K PUERTO PUEDO ABRIR (K NO SEA EL 21) PARA MI SERVIDOR FTP
ESPERO ME AYUDEN CON ESO
DE ANTE MANO MUCHAS GRACIAS
Excelente aporte.

Es un tutorial muy bueno, y facil de entender.
Corrección.

En el punto 3. Del "modo pasivo" hay un error: 3. Para ciertas operaciones, es necesario realizar el envío de un fichero, por lo que se crea el canal de datos. Para ello el cliente crea una conexión física desde uno de sus puerto (puerto y) hasta un número de puerto del *cliente*. Este número de puerto fue el que indicó el servidor como respuesta del comando pasv (puerto z). De este modo, el cliente establece el canal de datos por el que se transmite la información. Donde dice *cliente* debería decir *servidor*.
1 2 3 | siguiente >

Tutoriales relacionados con 'Los rincones del API Win32: WinInet y FTP'

El protocolo FTP desde el API WinInet. Con este curso aprenderás a hacer un pequeño... Más »
Comienzo con un nuevo tema dentro dentro de la serie Los rincones del API Win32.... Más »
Entramos en temas interesantes: el acceso a recursos remotos a través del protocolo de aplicación... Más »
En el anterior curso dejamos muchos temas en el tintero, así que voy a terminar... Más »
Damos una visión detallada de una de las características más interesantes de esta tecnología de... Más »

Autor y licencia de 'Los rincones del API Win32: WinInet y FTP'


Tutorial de Juan Manuel. Extraido de: http://www.lawebdejm.com CopyLeft
Este contenido ha sido recopilado por el equipo de Wikilearning. Todo el contenido recopilado se ha obtenido respetando y comunicando en nuestro site la licencia de cada fuente.
Wikilearning tiene permiso expreso por escrito de los autores para publicar los contenidos que ha extraído de otras webs, incluyendo su uso comercial.