【问题标题】:Ignore missing file while downloading with Python ftplib使用 Python ftplib 下载时忽略丢失的文件
【发布时间】:2015-02-07 19:00:03
【问题描述】:

我正在尝试从 FTP 服务器下载某个文件(名为 010010-99999-year.gz)。这个相同的文件,但不同年份驻留在不同的 FTP 目录中。例如:

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 等等。图片说明了其中一个目录:

该文件并非位于所有目录中(即所有年份)。在这种情况下,我希望脚本忽略丢失的文件,打印“不可用”,然后继续下一个目录(即明年)。 我可以使用 NLST 列表来执行此操作,方法是首先在当前 FTP 目录中生成文件列表,然后检查我的文件是否在该列表中,但这很慢,并且 NOAA(拥有服务器的组织)不喜欢文件列表(source)。因此我想出了这个代码:

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()

这会正确下载现有文件(1973-2014 年),但也会生成 1901-1972 年的空文件。该文件不在 1901-1972 的 FTP 中。 我在使用 try 和 except 时做错了什么,还是其他问题?

【问题讨论】:

标签: python ftp ftplib try-except


【解决方案1】:

我拿了你的代码并稍作修改:

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()

注意事项

  • 一个人可以做的最危险的操作是拥有一个没有特定异常类的except 子句。这种类型的构造将忽略所有错误,从而难以排除故障。为了解决这个问题,我添加了特定的异常error_perm
  • 一旦发生异常,我绝对确定本地文件已关闭,因为with 语句保证
  • 如果发生error_perm 异常,我删除了本地文件,表明该文件在服务器上不可用
  • 我删除了更改目录的代码:每年,您 cwd 两次,这会减慢进程
  • range(1901, 2015) 将不包括 2015。如果需要,必须指定 range(1901, 2016)
  • 我改进了打印语句以包含文件名,从而更容易跟踪哪些可用,哪些不可用

更新

此更新回答了您关于不创建空本地文件(然后必须删除它们)的问题。有几种不同的方法:

  1. 下载前查询远程文件是否存在。仅当远程存在时才创建本地文件。这种方法的问题是查询远程文件比创建/删除本地文件需要更长的时间。
  2. 创建一个字符串缓冲区 (StringIO),下载到该缓冲区。仅当该字符串缓冲区不为空时才创建本地文件。这种方法的问题是您将相同的数据写入两次:一次写入字符串缓冲区,一次从字符串缓冲区写入文件。

【讨论】:

  • 太棒了!很棒的笔记!你认为有可能根本不在本地生成空文件吗?
【解决方案2】:

我认为问题出在您的 try: except 块中,您在检查文件是否存在之前为新文件保持打开文件处理程序:

try:              
    file=open(fullStationId,"wb")
    ftp.retrbinary('RETR %s' % fullStationId, file.write)
    print("File is available")
    file.close()
except: 
    print("File not available")

相反,在 except 块中添加一个附加语句来关闭文件处理程序,并在文件为空时再添加一条语句来删除文件。

另一种可能性是仅当文件存在并且使用ftp.size在服务器上具有非零大小时才打开文件以进行本地写入

【讨论】:

  • +1 因为它有效。最好根本不生成空文件。喜欢:尝试: ftp.retrbinary('RETR %s' % fullStationId,open(fullStationId,"wb").write.close()) 但这也不起作用。
猜你喜欢
  • 1970-01-01
  • 2014-04-08
  • 1970-01-01
  • 1970-01-01
  • 2012-07-19
  • 2018-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多