有没有办法从另一个文件夹中的文件夹中删除文件?


20

假设我从文件夹A复制并粘贴文件,其中包括:

文件夹A:

file1.cfg  
file2.txt  
file3.esp  
file4.bsa  

进入文件夹B,更新后有:

文件夹B:

apples.mp3  
file1.cfg    *
file2.txt    *
file3.esp    *
file4.bsa    *
turtles.jpg

有没有办法删除文件夹A中文件夹B中的所有文件(标有*)? 除了手动选择每个并删除它,或在复制粘贴后立即ctrl-Z'ing

我更喜欢Windows方法或一些可以做到这一点的软件

谢谢!


4
你怎么知道它们是内容相同的文件?我无法想象一个场景,你只想根据文件名盲目地认为文件是重复的。
rory.ap

@roryap我认为这个问题是因为OP将文件从文件夹1复制到文件夹2,替换了所有,现在认为,嗯,这是一个错误,但是意识到第二天,所以撤消是不可能的。但你是对的,你不知道内容。
LPChip

13
只是一个愚蠢的问题......为什么不使用“剪切”和“粘贴”?
DaMachk

@DaMachk如果您正在使用网络驱动器或可移动媒体,请复制>验证 - >清理是一个合理的路线。如果文件被某些进程使用,那么在副本上测试它可能是一个好主意(如果我自己的代码中的错误破坏了输入文件(例如),我会使用文件进行python数据分析。)不像过去那样必要,但是旧的习惯和所有这些。或者OP可能有错误点击的副本而不是削减,
Chris H

Answers:


34

那里有免费软件 的WinMerge 。您可以使用此软件来匹配重复项。首先,使用 FileOpen,并选择两个目录,包含要保留在左侧的文件的文件夹,以及不在右侧的文件夹。然后,去 View,并取消选择 Show Different ItemsShow Left Unique Items,和 Show Right Unique Items。这将只留下列表中剩余的相同文件。之后,选择 EditSelect All,右键单击任何文件,然后单击 DeleteRight。这将从右侧文件夹中删除重复项。

demo of WinMerge


这种方法的好处是它可以检测文件是否与内容类似,如果这很重要。 WinMerge可以比较所有重要因素。

24

这可以通过使用命令通过命令行完成 forfiles

让我们假设你有一个文件夹A. c:\temp\Folder A,和文件夹B位于 c:\temp\Folder B

该命令将是:

c:\>forfiles /p "c:\temp\Folder A" /c "cmd /c del c:\temp\Folder B\@file"

完成此操作后,文件夹B将删除文件夹A中存在的所有文件。请记住,如果文件夹B具有相同名称但内容不同的文件,它们仍将被删除。

可以扩展它以使用子文件夹中的文件夹,但出于担心这变得不必要复杂,我决定不发布它。它需要/ s和@relpath选项(并进一步测试xD)


11

您可以使用此PowerShell脚本:

$folderA = 'C:\Users\Ben\test\a\' # Folder to remove cross-folder duplicates from
$folderB = 'C:\Users\Ben\test\b\' # Folder to keep the last remaining copies in
Get-ChildItem $folderB | ForEach-Object {
    $pathInA = $folderA + $_.Name
    If (Test-Path $pathInA) {Remove-Item $pathInA}
}

希望它是相当不言自明的。它查看文件夹B中的每个项目,检查文件夹A中是否存在具有相同名称的项目,如果是,则删除文件夹A项目。注意最后的 \ 在文件夹路径中很重要。

单行版:

gci 'C:\Users\Ben\test\b\' | % {del ('C:\Users\Ben\test\a\' + $_.Name) -EA 'SilentlyContinue'}

如果您不关心控制台中是否出现大量红色错误,则可以删除 -EA 'SilentlyContinue'

把它保存为 .ps1 文件,例如 dedupe.ps1。在运行PowerShell脚本之前,您需要启用它们的执行:

Set-ExecutionPolicy Unrestricted -Scope CurrentUser

然后你就可以调用它了 .\dedupe.ps1 当你在包含它的文件夹中时。


4

rsync

rsync 是一个用于同步目录的程序。从你有很多(很多)选项,有自我解释 --ignore-non-existing--remove-source-files--recursive

你可以做

rsync -avr --ignore-non-existing --recursive --remove-source-files   B/ A -v

如果我们假设你有目录A(4)和B(4 + 2)中的文件。

A       B
├── a   ├── a
├── b   ├── b
├── c   ├── c
└── d   ├── d
        ├── e
        └── f     # Before


A       B
├── a   ├── e
├── b   └── f
├── c   
└── d             # After

4

LPChip的回答 是更好的一个。

但是因为我开始学习Python,我想,“哎呀,为什么不写一个Python脚本来回答这个问题?”

安装Python和Send2Trash

在从命令行运行脚本之前,您需要安装Python。

然后安装 Send2Trash 所以删除的文件不会无可挽回地消失,但最终会在操作系统的垃圾中消失:

pip install Send2Trash

创建脚本

使用例如名称创建一个新文件 DeleteDuplicateInFolderA.py

将以下脚本复制到该文件中。

#!/usr/bin/python

import sys
import os
from send2trash import send2trash


class DeleteDuplicateInFolderA(object):
    """Given two paths A and B, the application determines which files are in
       path A which are also in path B and then deletes the duplicates from
       path A.

       If the "dry run" flag is set to 'true', files are deleted. Otherwise
       they are only displayed but not deleted.
    """

    def __init__(self, path_A, path_B, is_dry_run=True):
        self._path_A = path_A
        self._path_B = path_B
        self._is_dry_run = is_dry_run

    def get_filenames_in_folder(self, folder_path):
        only_files = []
        for (dirpath, dirnames, filenames) in os.walk(folder_path):
            only_files.extend(filenames)
        return only_files

    def print_files(sel, heading, files):
        print(heading)
        if len(files) == 0:
            print("   none")
        else:
            for file in files:
                print("   {}".format(file))

    def delete_duplicates_in_folder_A(self):
        only_files_A = self.get_filenames_in_folder(self._path_A)
        only_files_B = self.get_filenames_in_folder(self._path_B)

        files_of_A_that_are_in_B = [file for file in only_files_A if file in only_files_B]

        self.print_files("Files in {}".format(self._path_A), only_files_A)
        self.print_files("Files in {}".format(self._path_B), only_files_B)

        if self._is_dry_run:
            self.print_files("These files would be deleted: ", [os.path.join(self._path_A, file) for file in files_of_A_that_are_in_B])
        else:
            print("Deleting files:")
            for filepath in [os.path.join(self._path_A, file) for file in files_of_A_that_are_in_B]:
                print("   {}".format(filepath))
                # os.remove(filepath)  # Use this line instead of the next if Send2Trash is not installed
                send2trash(filepath)

if __name__ == "__main__":
    if len(sys.argv) == 4:
        is_dry_run_argument = sys.argv[3]
        if not is_dry_run_argument == "--dryrun":
            println("The 3rd argument must be '--dryrun' or nothing.")
        else:
            app = DeleteDuplicateInFolderA(sys.argv[1], sys.argv[2], is_dry_run=True)
    else:
        app = DeleteDuplicateInFolderA(sys.argv[1], sys.argv[2], is_dry_run=False)
    app.delete_duplicates_in_folder_A()

用法

干运行模式,显示哪些文件将被删除而不实际删除任何文件:

c:\temp> python .\DeleteDuplicateInFolderA.py c:\temp\test\A c:\temp\test\B --dryrun

文件删除模式,确实删除文件,所以要小心:

c:\temp> python .\DeleteDuplicateInFolderA.py c:\temp\test\A c:\temp\test\B

输出干运行模式

Files in C:\temp\A
  1.txt
  2.txt
Files in C:\temp\B
  2.txt
  3.txt
These files would be deleted:
  C:\temp\A\2.txt

输出文件删除模式

Files in C:\temp\A
  1.txt
  2.txt
Files in C:\temp\B
  2.txt
  3.txt
Deleting files:
  C:\temp\A\2.txt

单元测试

如果要测试上面的应用程序,请创建一个名为的文件 DeleteDuplicateInFolderATest.py 并将这些单元测试粘贴到其中:

import unittest
import os
import shutil
from DeleteDuplicateInFolderA import DeleteDuplicateInFolderA


class DeleteDuplicateInFolderATest(unittest.TestCase):

    def __init__(self, *args, **kwargs):
        super(DeleteDuplicateInFolderATest, self).__init__(*args, **kwargs)
        self._base_directory = r"c:\temp\test"
        self._path_A = self._base_directory + r"\A"
        self._path_B = self._base_directory + r"\B"

    def create_folder_and_create_some_files(self, path, filename_list):
        if os.path.exists(path):
            shutil.rmtree(path)
        os.makedirs(path)
        for filename in filename_list:
            open(os.path.join(path, filename), "w+").close()

    def setUp(self):
        # Create folders and files for testing
        self.create_folder_and_create_some_files(self._path_A, ["1.txt", "2.txt"])
        self.create_folder_and_create_some_files(self._path_B, ["2.txt", "3.txt"])

    def tearDown(self):
        for path in [self._path_A, self._path_B, self._base_directory]:
            if os.path.exists(path):
                shutil.rmtree(path)

    def test_duplicate_file_gets_deleted(self):
        # Arrange
        app = DeleteDuplicateInFolderA(self._path_A, self._path_B, is_dry_run=False)

        # Act
        app.delete_duplicates_in_folder_A()

        # Assert
        self.assertFalse(os.path.isfile(self._path_A + r"\2.txt"), "File 2.txt has not been deleted.")

    def test_duplicate_file_gets_not_deleted_in_mode_dryrun(self):
        # Arrange
        app = DeleteDuplicateInFolderA(self._path_A, self._path_B, is_dry_run=True)

        # Act
        app.delete_duplicates_in_folder_A()

        # Assert
        self.assertTrue(os.path.isfile(self._path_A + r"\2.txt"), "File 2.txt should not have been deleted in mode '--dryrun'")

def main():
    unittest.main()

if __name__ == '__main__':
    main()

你能告诉我为什么这个剧本“丑陋地狱”吗?我只是通读了它,你正在做的事情非常清楚。我几乎想把它粘贴在CodeReview.SE上,以了解什么是不喜欢它。
user1717828

添加md5sum以检查文件内容是否相同将是一个不错的选择。也使用了 OS垃圾机制 而不是删除。
lolesque

@ user1717828:我重新构建了代码,删除了该评论并将你的建议带到了 在CodeReview.SE上发布代码
Lernkurve

@lolesque:Send2Trash部分:完成。谢谢你的想法!
Lernkurve

1
@barlop,我回复了原帖,不是评论。
user1717828

1

使用bash

for f in $(ls /path/to/folderB/); do 
    rm -rf /path/to/folderA/$f
done

当然,通过检查文件是否存在,或检查文件名是否安全,您可以更安全。但假设您只是想完成这项工作,并且没有任何可笑的命名文件 folderB - 这是一种快速而肮脏的方式来完成它。 (并且您可以使用随附的bash模拟器 混帐 ,如果你没有运行Win10 + bash)


1

假设我将文件夹A中的文件复制并粘贴到文件夹B中。

有没有办法删除文件夹B中文件夹A中的所有文件?除了手动选择每个并删除它,或ctrl-Z'ing   复制粘贴后

Windows方法

如果您始终需要将文件从一个位置复制到另一个位置,然后确保成功复制的文件也从原始源位置删除,则下面是一个批处理脚本解决方案,您可以使用该解决方案自动完成整个任务简单点击每次运行。

  • 一定要设置 SourceDirDestDir 相应的变量满足您的需求。

  • 另外,在下面的脚本部分中 ("%SourceDir%\*.*") DO 你可以简单地改变 *.* 值更明确的文件名( File A.txt )或文件扩展名( *.wav ) 如所须。


@ECHO ON
SET SourceDir=C:\Users\User\Desktop\Source
SET DestDir=C:\Users\User\Desktop\Dest

FOR %%A IN ("%SourceDir%\*.*") DO XCOPY /F /Y "%%~A" "%DestDir%\" && DEL /Q /F "%%~A"
GOTO EOF

更多资源


0

任何NC风格的程序,如Total Commander,都有一个目录差异命令,用于选择两个选项卡中与其他选项卡不同的文件。调用此命令, tab 到较大的目录(B),使用反转选择 * 并删除。这样做的好处是不会删除可能已经改变的文件(某种程度上)并且不一样,尽管它们在名称上是一致的。您可以使用相同的目录diff命令在删除后找到它们。

我想我已经陷入了九十年代......但是我没有真正看到任何更优雅的东西:-)到目前为止,这是唯一需要5个击键而且没有任何脚本/命令行的答案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.