【问题标题】:Copy a file into a directory with its original leading directories appended将文件复制到附加其原始前导目录的目录中
【发布时间】:2023-06-19 01:48:02
【问题描述】:

我想知道 python 是否提供了一种规范的方法来将文件复制到附加了原始前导目录的目录中,就像 cp --parents 那样。来自cp 手册页:

`--parents'
[...]
     cp --parents a/b/c existing_dir

 copies the file `a/b/c' to `existing_dir/a/b/c', creating any
 missing intermediate directories.

我在shutil 文档中没有看到任何与此相关的内容。当然,我可以在将任何文件复制到 existing_dir 目录之前创建整个目录结构,但这样做可能会产生开销。

【问题讨论】:

  • 我认为这是您自己编写程序的那种东西,可以找到具有此功能的库。这取决于相对路径,而 shutil 上的东西不应该
  • 查看 'os' 的文档 -- 听起来您想为路径模拟 'mkdir -p',然后将文件复制到其中?
  • @JonathanVanasco:是的,就是这样。

标签: python python-3.x copy shutil


【解决方案1】:

我终于想出了下面的代码。它的作用几乎与cp --parents 完全相同。

import os, shutil

def cp_parents(target_dir, files):
    dirs = []
    for file in files:
        dirs.append(os.path.dirname(file))
    dirs.sort(reverse=True)
    for i in range(len(dirs)):
        if not dirs[i] in dirs[i-1]:
            need_dir = os.path.normpath(target_dir + dirs[i])
            print("Creating", need_dir )
            os.makedirs(need_dir)
    for file in files:
        dest = os.path.normpath(target_dir + file)
        print("Copying %s to %s" % (file, dest))
        shutil.copy(file, dest)

这样称呼它:

target_dir = '/tmp/dummy'
files = [ '/tmp/dir/file1', '/tmp/dir/subdir/file2', '/tmp/file3' ]

cp_parents(target_dir, files)

输出是:

Creating /tmp/dummy/tmp/dir/subdir
Copying /tmp/dir/file1 to /tmp/dummy/tmp/dir/file1
Copying /tmp/dir/subdir/file2 to /tmp/dummy/tmp/dir/subdir/file2
Copying /tmp/file3 to /tmp/dummy/tmp/file3

可能有更好的方法来处理这个问题,但它确实有效。

【讨论】:

    【解决方案2】:

    不确定您的具体要求,但听起来shutil.copytree 很适合您。你可以看到完整的文档here,但基本上你需要在你的例子中调用类似

    shutil.copytree( 'a/b/c', 'existing_dir/a/b/c' )
    

    【讨论】:

    • 其实shutil.copytree复制了整个源码树,而我想要的只是复制其中的一些文件。
    • 哦,确定它只是从您指定的目录和更深入的目录中复制文件编辑:重新阅读,在我的回答中将 c 误解为目录,没有意识到您的意思是它是一个文件
    【解决方案3】:
    import os
    import shutil
    
    files = [ '/usr/bin/ls','/etc/passwd' , '/var/log/daily.out' , '/var/log/system.log' , '/var/log/asl/StoreData' ]
    
    def copy_structure(dst_dir,source_files):
        if not os.path.exists(dst_dir) and os.path.isdir(dst_dir):
            os.mkdir(dst_dir)
        for file in source_files:
            dir_name = os.path.dirname(file)
            final_dir_path = os.path.normpath(dst_dir+dir_name)
            if not os.path.exists(final_dir_path):
                os.makedirs(final_dir_path)            
            if os.path.exists(file): 
                shutil.copy(file,final_dir_path)
    
    copy_structure('/tmp/backup',files)  
    

    【讨论】:

      【解决方案4】:

      只有 3.6 或更高版本(它使用 f 函数)

      这是我对 cp --parents 的实现

      首先获取src目录和文件名的偏移量,还有目录偏移量(有时我想省略src文件的第一个文件夹)

      然后它提取文件夹和文件名(检查 src_dirs 是因为我注意到当 src 文件没有嵌套在任何文件夹中时它崩溃了)

      最后它在目标文件夹中创建目录树并将文件复制到其中

      def __copy_parents(src, dest_folder, dir_offset=0):
          ''' Copies src tree into dest, offset (optional) omits n folders of the src path'''
          prev_offset = 0 if dir_offset == 0 else src.replace('/', '%', dir_offset - 1).find('/') + 1
          post_offset = src.rfind('/')
      
          src_dirs = '' if post_offset == -1 else src[prev_offset:post_offset]
          src_filename = src[post_offset + 1:]
      
          os.makedirs(f'{dest_folder}/{src_dirs}', exist_ok=True)
          shutil.copy(src, f'{dest_folder}/{src_dirs}/{src_filename}')
      

      【讨论】: