C'è un trucco speciale per il download di un file zip e la scrittura su disco con Python?

StackOverflow https://stackoverflow.com/questions/576238

  •  05-09-2019
  •  | 
  •  

Domanda

Sto FTPing un file zip da un sito FTP remoto utilizzando ftplib di Python. Ho quindi tentare di scrivere su disco. I lavori di scrittura file, tuttavia la maggior parte i tentativi di aprire la zip con WinZip o WinRar falliscono; entrambe le applicazioni sostengono il file è danneggiato. Stranamente però, quando fai clic destro e il tentativo di estrarre il file utilizzando WinRar, il file estratto.

Quindi, per essere chiari, il file di scrittura funziona, ma non sarà Apri all'interno delle applicazioni zip popolari, ma decomprimere usando quelle stesse applicazioni. Si noti che il modulo zipfile Python non non riesce a estrarre le cerniere.

Ecco il codice che sto usando per ottenere il file zip dal sito FTP (si prega di ignorare il cattivo tabulazione, non è questo il problema).

filedata = None
def appender(chunk):
    global filedata
    filedata += chunk


def getfile(filename):
  try:
      ftp = None

      try:
          ftp = FTP(address)
          ftp.login('user', 'password')

      except Exception, e:
          print e

      command = 'RETR ' + filename

      idx = filename.rfind('/')
      path = filename[0:idx]
      ftp.cwd(path)
      fileonly = filename[idx+1:len(filename)]

      ftp.retrbinary('RETR ' + filename, appender)

      global filedata
      data = filedata

      ftp.close()

      filedata = ''
      return data

  except Exception, e:
      print e

data = getfile('/archives/myfile.zip')    
file = open(pathtoNTFileShare, 'wb')
file.write(data)
file.close()
È stato utile?

Soluzione

scivolare file.write direttamente all'interno della funzione retrbinary invece di passare appender. Ciò funzionerà e sarà, inoltre, non utilizzare più di tanto RAM quando si sta scaricando un file di grandi dimensioni.

Se vuoi i dati memorizzati all'interno di una variabile, però, si può anche avere una variabile denominata:

blocks = []

Poi passare ad retrbinary invece di appender:

blocks.append

La vostra funzione appender corrente è sbagliata. + = Non funziona correttamente quando ci sono dati binari, perché cercherà di fare un append corda e fermarsi al primo NULL che vede.

Come già detto da @Lee B è anche possibile utilizzare urllib2 o Curl. Ma il vostro codice attuale è quasi corretto se si fanno le piccole modifiche che ho citato sopra.

Altri suggerimenti

Non ho mai usato quella libreria, ma urllib2 funziona bene, ed è più semplice. Curl è ancora meglio.

Guardando il codice, posso vedere un paio di cose sbagliate. Il tuo eccezione cattura solo stampare l'eccezione, quindi continua. Per gli errori fatali come non ottenere una connessione FTP, hanno bisogno di stampare il messaggio e quindi uscire. Inoltre, il filedata inizia come None, allora il tuo appender utilizza + = da aggiungere a quella, così si sta cercando di aggiungere una stringa + Nessuno, che dà un TypeError quando provo qui. Sono sorpreso che sta funzionando per niente; Avrei immaginato che l'appender sarebbe un'eccezione, e quindi la copia FTP sarebbe interrompere.

Mentre ri-lettura, ho appena notato un'altra risposta circa l'uso di + = su dati binari. Questo potrebbe anche essere esso; python cerca di essere intelligente a volte, e potrebbe essere "aiutare" quando si uniscono le stringhe con spazi bianchi o NULs in loro, o qualcosa del genere. La cosa migliore che c'è quello di avere il file aperto (chiamiamolo outfile), e utilizzare il tuo appender ad appena outfile.write (blocco).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top