【问题标题】:Move from local linux folder to a windows share mounted with cifs从本地 linux 文件夹移动到使用 cifs 挂载的 Windows 共享
【发布时间】:2014-10-30 13:19:30
【问题描述】:

我需要将脚本中的文件从 ext4 硬盘上的本地文件夹移动到作为 Windows 共享安装的文件夹,例如:mount -t cifs -o username=username,password=password,rw,nounix,iocharset=utf8,file_mode=0777,dir_mode=0777 //192.168.1.120/storage /mnt/storage

我尝试使用os.rename(src,dst)shutil.move(src,dst) 甚至subprocess.call(['mv', src,dst], Shell=True)subprocess.call(['mv', src,dst])

获取每个文件的错误,以及由于 linux 文件所有权/权限,我可以告诉它的错误。

例如当mv /mnt/networkshare/file1.txt /tmp/file1.txt 很好,但是

mv /tmp/file1.txt /mnt/networkshare/file1.txt

结果

"mv: preserving times for /mnt/networkshare/file1.txt: Operation not permitted"
"mv preserving permissions for /mnt/networkshare/file1.txt: Operation not permitted"

我认为os.rename(src,dst)shutil.move(src,dst) 也会出现同样的问题,但他们并没有那么健谈。

shutil.move(src,dst) 告诉我:[Errno 1] Operation not allowed: '/mnt/networkshare/file1.txt'

os.rename(src,dst) 说:[Errno 18] 无效的跨设备链接

编辑:pcmanfm 能够从本地剪切和粘贴到远程就好了。

另外..让我感到困惑的是一些文件被移动了..

【问题讨论】:

    标签: python linux windows file-io share


    【解决方案1】:

    os.rename 不能跨文件系统移动文件,因为底层的rename syscall 不允许这样做:

    rename() 不能跨不同的挂载点工作,即使相同 文件系统安装在两者上。

    至于shutil.move为什么会失败,答案也在于its documentation

    如果目标在当前文件系统上,那么只需使用 改名。否则,将 src(使用 copy2())复制到 dst,然后删除 来源。

    那就check copy2吧!

    类似于 copy(),但元数据也会被复制——事实上,这是 只需 copy() 后跟 copystat()

    所以,是 copystat 失败了 - 因为它无法在这样的挂载上设置文件元数据。

    由于shutil 似乎没有在不复制元数据的情况下重命名的方法,所以我们必须自己做。我们来看看它的源码:

    In [3]: print inspect.getsource(shutil.move)
    def move(src, dst):
        """Recursively move a file or directory to another location. This is
        similar to the Unix "mv" command.
    
        If the destination is a directory or a symlink to a directory, the source
        is moved inside the directory. The destination path must not already
        exist.
    
        If the destination already exists but is not a directory, it may be
        overwritten depending on os.rename() semantics.
    
        If the destination is on our current filesystem, then rename() is used.
        Otherwise, src is copied to the destination and then removed.
        A lot more could be done here...  A look at a mv.c shows a lot of
        the issues this implementation glosses over.
    
        """
        real_dst = dst
        if os.path.isdir(dst):
            if _samefile(src, dst):
                # We might be on a case insensitive filesystem,
                # perform the rename anyway.
                os.rename(src, dst)
                return
    
            real_dst = os.path.join(dst, _basename(src))
            if os.path.exists(real_dst):
                raise Error, "Destination path '%s' already exists" % real_dst
        try:
            os.rename(src, real_dst)
        except OSError:
            if os.path.isdir(src):
                if _destinsrc(src, dst):
                    raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst)
                copytree(src, real_dst, symlinks=True)
                rmtree(src)
            else:
                copy2(src, real_dst)
                os.unlink(src)
    

    似乎正如预测的那样,我们需要做的就是将copy2 替换为copy。我们可以通过复制源代码并重命名函数或简单地通过

    def move_without_copying_stat(src,dst):
        old= shutil.copy2
        shutil.copy2= shutil.copy
        shutil.move(src,dst)
        shutil.copy2= old
    

    如果你今天感觉幸运的话。理解the consequences of such 留给读者作为练习

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-07-05
      • 2014-07-09
      • 1970-01-01
      • 2021-09-22
      • 1970-01-01
      • 2012-10-21
      • 2019-01-15
      • 1970-01-01
      相关资源
      最近更新 更多