Copier un fichier avec un chemin trop long vers un autre répertoire en Python

j'essaie de copier des fichiers sur Windows avec Python 2.7, mais parfois cela échoue.

shutil.copyfile(copy_file, dest_file)

j'ai le IOError:

[Errno 2] No such file or directory

mais le fichier existe! Le problème est que le chemin du fichier est trop long. (> 255 caractères)

comment copier ces fichiers? Il n'est pas un problème pour les ouvrir dans d'autres applications.

pour créer un fichier avec un chemin trop long, créez un fichier avec un nom de fichier aussi long que possible et déplacez le contenant un dossier plus profond dans une structure d'arbre.

j'ai essayé certaines de ces méthodes sans succès: http://timgolden.me.uk/python/win32_how_do_i/copy-a-file.html

12
demandé sur Gfy 2012-12-29 00:35:59

3 réponses

Je n'étais pas sûr de la limite de 255 char alors je suis tombé sur ce post. Là, j'ai trouvé une réponse de travail: Ajouter \\?\ avant le chemin d'accès.

shutil.copyfile("\\?\" + copy_file, dest_file)

modifier: J'ai découvert que travailler avec long paths provoque des problèmes sur Windows. Un autre truc que j'utilise est de raccourcir les chemins:

import win32api
path = win32api.GetShortPathName(path)
18
répondu Gfy 2017-05-23 11:47:20

Merci pour la réponse Gfy. J'ai l'obligation d'utiliser des chemins relatifs. \?\ ne peut pas être ajouté avec succès à un chemin relatif, il est donc nécessaire de passer à un chemin absolu en premier (exécuter depuis le bureau):

import os

def clean_path(path):
    path = path.replace('/',os.sep).replace('\',os.sep)
    if os.sep == '\' and '\\?\' not in path:
        # fix for Windows 260 char limit
        relative_levels = len([directory for directory in path.split(os.sep) if directory == '..'])
        cwd = [directory for directory in os.getcwd().split(os.sep)] if ':' not in path else []
        path = '\\?\' + os.sep.join(cwd[:len(cwd)-relative_levels]\
                         + [directory for directory in path.split(os.sep) if directory!=''][relative_levels:])
    return path

clean_path('samples')
\?\C:\Users\Username\Desktop\samples
clean_path('\samples')
\?\C:\Users\Username\Desktop\samples
clean_path('..\samples')
\?\C:\Users\Username\samples
clean_path('..\..\samples')
\?\C:\Users\samples
clean_path('C:\Users\Username\Dropbox')
\?\C:\Users\Username\Dropbox
4
répondu Hywel Thomas 2017-05-23 12:03:03

Peut-être faire quelque chose comme ceci:

path = "some/really/really/long/path/more/than/255/chars.txt"

def copyFile(path, dest, relative=0):
    if len(path) > 255:
        if not os.sep in path:
            raise SomeException()
        moveTo, path = path.split(os.sep, 1)
        os.chdir(moveTo)
        copyFile(path, dest, relative + 1)
    else:
        path_base = ['..'] * relative
        path_rel = path_base + [dest]
        shutil.copyfile(path, os.path.join(*path_rel))

C'est testé et fonctionne... toutefois, si la destination est plus de 255 caractères, vous seriez de retour dans le même bateau. Dans ce cas, vous pourriez avoir à déplacer le fichier plusieurs fois.

0
répondu sberry 2012-12-28 20:52:22