ejemplo - python ftp server
Ignorar el archivo que falta durante la descarga con Python ftplib (2)
Tomé tu código y lo modifiqué un poco:
from ftplib import FTP, error_perm
import os
def FtpDownloader2(url="ftp.ncdc.noaa.gov"):
ftp = FTP(url)
ftp.login()
for year in range(1901, 2015):
remote_file = ''/pub/data/noaa/isd-lite/{0}/010010-99999-{0}.gz''.format(year)
local_file = os.path.basename(remote_file)
try:
with open(local_file, "wb") as file_handle:
ftp.retrbinary(''RETR %s'' % remote_file, file_handle.write)
print(''OK'', local_file)
except error_perm:
print(''ERR'', local_file)
os.unlink(local_file)
ftp.close()
Notas
- La operación más peligrosa que una persona puede hacer es tener una cláusula
except
sin una clase de excepción específica. Este tipo de construcción ignorará todos los errores, lo que dificultará la resolución de problemas. Para solucionar esto, agregué la excepción específicaerror_perm
- Una vez que se produjo la excepción, estoy absolutamente seguro de que el archivo local está cerrado porque el enunciado
with
garantiza que -
error_perm
archivo local si seerror_perm
excepciónerror_perm
, una señal de que el archivo no está disponible en el servidor - Eliminé el código para cambiar directorios: para cada año,
cwd
dos veces el código, lo que ralentiza el proceso -
range(1901, 2015)
no incluirá 2015. Si lo desea, debe especificar elrange(1901, 2016)
- Mejoré las declaraciones de impresión para incluir los nombres de los archivos, lo que facilita el seguimiento de cuáles están disponibles y cuáles no.
Actualizar
Esta actualización responde a su pregunta sobre no crear un archivo local vacío (luego tener que eliminarlos). Hay un par de maneras diferentes:
- Consulte la existencia del archivo remoto antes de descargar. Solo crea el archivo local cuando exista el control remoto. El problema con este enfoque es que consultar un archivo remoto lleva más tiempo que crear / eliminar un archivo local.
- Cree un búfer de cadena (StringIO), descárguelo a ese búfer. Solo cree un archivo local cuando ese buffer no esté vacío. El problema con este enfoque es que está escribiendo los mismos datos dos veces: una vez en el búfer de cadena y una vez desde el búfer de cadena hasta el archivo.
Estoy intentando descargar un determinado archivo (llamado 010010-99999-year.gz) desde un servidor FTP. Este mismo archivo, pero para diferentes años reside en diferentes directorios FTP. Por ejemplo:
ftp://ftp.ncdc.noaa.gov/pub/data/noaa/isd-lite/2000/010010-99999-1973.gz ftp://ftp.ncdc.noaa.gov/pub/data/noaa/isd -lite / 2001 / 010010-99999-1974.gz y así sucesivamente. La imagen ilustra uno de los directorios:
El archivo no se encuentra en todos los directorios (es decir, todos los años). En tal caso, quiero que la secuencia de comandos ignore los archivos que faltan, imprima "no disponible" y continúe con el siguiente directorio (es decir, el próximo año). Podría hacer esto usando la lista NLST generando primero una lista de archivos en el directorio FTP actual y luego comprobando si mi archivo está en esa lista, pero eso es lento, y NOAA (la organización propietaria del servidor) no le gusta la lista de archivos ( fuente ) Por lo tanto, se me ocurrió este código:
def FtpDownloader2(url="ftp.ncdc.noaa.gov"):
ftp=FTP(url)
ftp.login()
for year in range(1901,2015):
ftp.cwd("/pub/data/noaa/isd-lite")
ftp.cwd(str(year))
fullStationId="010010-99999-%s.gz" % year
try:
file=open(fullStationId,"wb")
ftp.retrbinary(''RETR %s'' % fullStationId, file.write)
print("File is available")
file.close()
except:
print("File not available")
ftp.close()
Esto descarga los archivos existentes (año 1973-2014) correctamente, pero también está generando archivos vacíos para los años 1901-1972. El archivo no está en el FTP para 1901-1972. ¿Estoy haciendo algo mal en el uso de try y except, o es algún otro problema?
Creo que el problema está en tu intento: excepto bloquear, donde mantienes abierto un manejador de archivos para un nuevo archivo antes de verificar si el archivo existe o no:
try:
file=open(fullStationId,"wb")
ftp.retrbinary(''RETR %s'' % fullStationId, file.write)
print("File is available")
file.close()
except:
print("File not available")
En su lugar, agregue una instrucción adicional en el bloque except para cerrar el manejador de archivos, y otra declaración para eliminar el archivo si está vacío.
Otra posibilidad es abrir el archivo para escribir localmente solo si el archivo existe y tiene un tamaño distinto de cero en el servidor usando ftp.size