Enchantres
Enchantres

Reputation: 1055

When uploading recursively all files to FTP using ftplib, only the first directory is successfully transferred

I am trying to copy all directories with files and subdirectories from an FTP server to a local directory. The goal is to create a copy of all of them at the first execution of the program and update the changed ones at the other executions or add the newly added.

My FTP directory structure is:

├── _directory1
│   ├──_subdirectory1
│       ├── file1.py
│       ├── file2.py
│   ├──_subdirectory2
│       ├── file3.py
│       ├── file4.py│   
|   ├──_subdirectory3
│       ├── file3.py
│       ├── file4.py
│   └── packages.py
│   └── somefile.py
│   └── somepdf.pdf
├── _directory2
│   ├──_subdirectory2.1
│       ├── file2.1.py

Here is my code:

import os
import os.path
from ftplib import FTP, error_perm
from io import BytesIO

host = 'localhost'
username = 'user'
password = 'password'
port = 21
ftp = FTP()
ftp.connect(host, port)
ftp.login(username, password)
filenameCV = "C:/Users/User/Desktop/test"
# ftp.set_debuglevel(2)


def copy_all_files(ftp_server, path):
    for filename in ftp_server.nlst():
        print(filename)
        try:
            ftp_server.size(filename)
            if os.path.exists(os.path.join(path, filename)):
                with open(os.path.join(path, filename), "rb") as file:
                    r = BytesIO()
                    try:
                        ftp_server.retrbinary('RETR ' + filename, r.write)
                        if BytesIO(file.read()).getvalue() != r.getvalue():
                            print(filename+"has changed")
                            ftp_server.retrbinary('RETR ' + filename,
                                                  open(os.path.join(path, filename),
                                                       'wb').write)
                    except Exception as ee:
                        print(ee)
            else:
                ftp_server.retrbinary('RETR ' + filename, open(os.path.join(path, filename), 'wb').write)
        except:
            try:
                if not os.path.exists(os.path.join(path, filename)):
                    os.mkdir(os.path.join(path, filename))
                ftp_server.cwd(filename)
                copy_all_files(ftp_server, os.path.join(path, filename))
            except:
                pass


copy_all_files(ftp, filenameCV)
ftp.quit()

The problem is that my code creates directory 1 and directory 2 from the FTP, but copies and changes only subdirectory1 and files inside it, the rest of the directories are empty, the files from directory1 level are missing, subdirectories 2,3 and directory 2 are empty and also the pdf from the directory level is copied as a dir. Do I need to change ftp.cwd or what is the reason for not being copied the other dirs?

Upvotes: 1

Views: 240

Answers (1)

Martin Prikryl
Martin Prikryl

Reputation: 202168

You enter the remote folders here:

ftp_server.cwd(filename)

But you never leave them.


Either:

  • Leave the folder, once you download its contents:

    ftp_server.cwd(filename)
    copy_all_files(ftp_server, os.path.join(path, filename))
    ftp_server.cwd("..")
    
  • Or use absolute paths when entering the folders. That way the cwd will work, no matter there you are at that particular moment. Like here:
    Downloading a directory tree with ftplib

    In a broad sense, your question is actually a duplicate of the above one – Why are you trying to implement something, for which there's already a working solution?

Upvotes: 1

Related Questions