Cool_Breeze 发表于 2021-5-28 12:54

批处理和C# 搜索文件和目录,复制文件和目录源代码,改天加个界面

本帖最后由 Cool_Breeze 于 2021-5-29 17:42 编辑

我在别处一个论坛上面回答一个网友的问题!个人感觉不错!在此分享给大家!

以下是问题描述:

现有:file.txt一个,里面有1000多个换行的文件名(有些有后缀,有些没,有些是文件夹)

根据这个txt里面列出来的文件名,到另一个文件夹a里(含下面所有级别的子文件夹)去依次检索文件名或文件夹名。

检索出来的文件/文件夹按照a文件夹下面的原有路径放到(复制)另一个指定文件夹b,注意b现在还是个空文件夹。

未找到的文件名输出到另一个"未找到.txt"文件里。

示例:

file.txt里面内容:
0007cebt
a400cebt
千岛湖3月拍摄.jpg
2016-5-7


需要进行的操作:
找到:a\ccbbt\2017\vae\0007cebt.pdf
放到:b\ccbbt\2017\vae\里面

未找到:a400cebt
将内容 "a400cebt" 写入"未找到.txt"里面

找到:a\照片\千岛湖3月拍摄.jpg
放到:b\照片\里面

找到:a\2016\2016-5-7(文件夹)
整个文件夹放到:b\2016里面

最后询问是否删除所有原路径下已经被复制的文件和文件夹


脚本文件必须要放在源目录盘符下。

批处理源代码
@echo off
title By Author GIN 2021/05/25
SETLOCAL ENABLEDELAYEDEXPANSION

set souceFile=files.txt
set targetDir=d:\gin\c#
set notFoundFileName=未找到.txt

set newDirectory=%cd%\newDirectory
if not exist %newDirectory% (md "%newDirectory%")
REM 源路径为:d:\gin\c#
REM 新路径为:D:\GIN\copyFile\newDirectory
echo 源路径为:%targetDir%
echo 新路径为:%newDirectory%

call :equalTotalChar "%targetDir%" "%newDirectory%"
set equalCharTotal=!errorlevel!
call :readFileList "%souceFile%"
call :getTargetinfo "%targetDir%"
call :matchTarget
call :deleteSourceFile

pause & exit

REM 计算顶部路径相同部分
:equalTotalChar
    set sourcePath=%~1
    set newPath=%~2
    for /l %%i in (0,1,255) do (
      if /i "!sourcePath:~%%i,1!" neq "!newPath:~%%i,1!" (
            if /i "!sourcePath:~%%i,1!" equ "\" (exit /b %%i) else (
                for /l %%b in (%%i,-1,0) do (
                  if "!sourcePath:~%%b,1!" equ "\" (exit /b %%b)
                )
            )
      )
    )
    exit /b 0

REM 读取文件列表
:readFileList
    set fileName=%1
    set /a sourceFileLines = 0
    for /f "tokens=*" %%L in ('type %fileName%') do (set /a sourceFileLines+=1 & set "source_!sourceFileLines!=%%L")
    exit /b

REM 获取目标目录信息
:getTargetinfo
    set targetDirectory=%1
    set /a targetNumber=0
    for /f "tokens=*" %%u in ('dir /b /s %targetDirectory%') do (set /a targetNumber+=1 & set "target_!targetNumber!=%%u")
    exit /b
   
REM 匹配目标
:matchTarget
    echo 数据源数量为:%sourceFileLines%
    set /a deleteNumber=0
    echo %date% %time% >> %notFoundFileName%
    for /l %%s in (1,1,%sourceFileLines%) do (
      echo 正在处理第 %%s 个,!source_%%s!
      set found=false
      for /l %%t in (1,1,%targetNumber%) do (
            call :getFileOrDirectoryName "!source_%%s!" "!target_%%t!" & set matchResult=!errorlevel!
            if !matchResult! equ 1 (
                set found=true
                set "tempNewDirOrFile=%newDirectory%!target_%%t:~%equalCharTotal%!"
                pushd "!target_%%t!" && popd & (
                  if not exist "!tempNewDirOrFile!" (
                        md "!tempNewDirOrFile!" && xcopy /e /y "!target_%%t!" "!tempNewDirOrFile!"
                  )
                ) || (
                  if exist "!tempNewDirOrFile!" (
                        echo f | xcopy /y "!target_%%t!" "!tempNewDirOrFile!"
                  ) else (
                        echo f | xcopy "!target_%%t!" "!tempNewDirOrFile!"
                  )
                )
                set /a deleteNumber+=1 & set "deleteSourceFileOrDirectory_!deleteNumber!=!target_%%t!"
            ) 1>nul 2>nul
      )
      if "!found!" equ "false" (
            echo !source_%%s! >> %notFoundFileName%
      )
    )
    exit /b

REM 匹配 目标判断
:getFileOrDirectoryName
    set "souce=%1"
    set "target=%~nx2"
    if %souce% == "%target%" (exit /b 1)
    exit /b 0

REM 删除源文件
:deleteSourceFile
    echo 是否删除所有原路径下已经被复制的文件和文件夹?
    echo 输入 Y 是,N 否:
    choice
    set input=%errorlevel%
    if %input% neq 1 (exit /b)
    for /l %%n in (1,1,!deleteNumber!) do (del /p /s !deleteSourceFileOrDirectory_%%n!)
    exit /b
C# 源代码
using System;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
      string sourceFile = "files.txt";
      string targetPath = @"d:\gin\c#";
      string newDirectory = @"d:\gin\NewDirectory";
      string[] SourceFileContent = File.ReadAllLines(sourceFile, System.Text.Encoding.Default);
      
      List<string> TargetAllDir;
      List<string> TargetAllDirName = GetFileName(Directory.EnumerateDirectories(targetPath, "*", SearchOption.AllDirectories), out TargetAllDir);
      
      List<string> TargetAllFile;
      List<string> TargetAllFileName = GetFileName(Directory.EnumerateFiles(targetPath, "*", SearchOption.AllDirectories), out TargetAllFile);
      
      List<int> res;
      bool found = false;
      foreach (string source in SourceFileContent)
      {
            found = false;
            // 复制目录(树)
            res = FindDirAndFileName(source, TargetAllDirName);
            if (res.Count > 0)
            {
                found = true;
                foreach (int index in res)
                {
                  
                  // 复制目录结构
                  string newTargetDir = PathReplace(TargetAllDir, newDirectory);
                  if (!Directory.Exists(newTargetDir))
                  {
                        Directory.CreateDirectory(newTargetDir);
                  }
                  
                  foreach (string subDir in Directory.EnumerateDirectories(TargetAllDir, "*", SearchOption.AllDirectories))
                  {
                        string newSubDir = PathReplace(subDir, newDirectory);
                        if (!Directory.Exists(newSubDir))
                        {
                            Directory.CreateDirectory(newSubDir);
                        }
                  }
                  
                  // 复制文件
                  foreach (string subFile in Directory.EnumerateFiles(TargetAllDir, "*", SearchOption.AllDirectories))
                  {
                        File.Copy(subFile, PathReplace(subFile, newDirectory), true);
                  }
                }
            }
            
            // Console.WriteLine(1);
            // 复制文件
            res = FindDirAndFileName(source, TargetAllFileName);
            if (res.Count > 0)
            {
                found = true;
                foreach (int index in res)
                {
                  string newFileFullName = PathReplace(TargetAllFile, newDirectory);
                  string newFileFullDir = Path.GetDirectoryName(newFileFullName);
                  if (!Directory.Exists(newFileFullDir))
                  {
                        Directory.CreateDirectory(newFileFullDir);
                  }
                  File.Copy(TargetAllFile, newFileFullName, true);
                }
            }
            
            if (!found)
            {
                Console.WriteLine("{0} 未找到!", source);
            }
      }
      
    }
   
    // 扫描目标目录文件目录结构
    static List<string> GetFileName(IEnumerable<string> Data, out List<string> ToTList)
    {
      List<string> FileName = new List<string>();
      ToTList = new List<string>();
      foreach (var dir in Data)
      {
            FileName.Add(Path.GetFileName(dir));
            ToTList.Add(dir);
      }
      return FileName;
    }
   
    // 查找文件或者目录
    static List<int> FindDirAndFileName(string source, List<string> Target)
    {
      List<int> result = new List<int>();
      int index = Target.IndexOf(source);
      if (index == -1) return result;
      result.Add(index);
      while (true)
      {
         index = Target.IndexOf(source, index + 1);
         if (index != -1)
         {
               result.Add(index);
         }
         else
         {
               break;
         }
      }
      return result;
    }
   
    // 路径替换
    static string PathReplace(string source, string newDirectory)
    {
      string newPath ;
      // 判断是否在一个盘符下面
      if (Path.GetPathRoot(source).ToUpper() == Path.GetPathRoot(newDirectory).ToUpper())
      {
            int index = 0;
            while (index < newDirectory.Length)
            {
                if (char.ToUpper(source) == char.ToUpper(newDirectory))
                {
                  index++;
                }
                else
                {
                  break;
                }
            }
            while (true)
            {
                if (source[--index] == '\\')
                {
                  newPath = Path.Combine(newDirectory, source.Substring(index + 1));
                  break;
                }
            }
      }
      else
      {
            newPath = Path.Combine(newDirectory, source.Substring(3));
      }
      return newPath;
    }
}

Cool_Breeze 发表于 2021-5-28 16:30

QQending 发表于 2021-5-28 14:30
对的,打包exe,主要是包太大了

不过说实话,本人,一方面批处理写的少,不光对语法,对换行也不熟练 ...

https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/echo

本路人 发表于 2021-5-28 14:15

Cool_Breeze 发表于 2021-5-28 13:57
python处理起来更方便!

python自用自然好,但如果给别人尤其是电脑小白使用还要打包exe啊,不然别人没有python环境的用不了:rggrg

本路人 发表于 2021-5-28 13:37

不错,谢谢分享。虽然我自己是用py脚本去做的,没有批处理可以直接发给别人就能使用了这样方便

as614001 发表于 2021-5-28 13:38

记得缺点好像是 不能中文路径

sutramusic 发表于 2021-5-28 13:39

多谢楼主分享!

newease 发表于 2021-5-28 13:46

感谢楼主分享,有空试试,加分致谢

泡泡汽水 发表于 2021-5-28 13:51

{:301_972:}真不错 解决了大量文件复制粘贴的事情了

Cool_Breeze 发表于 2021-5-28 13:55

as614001 发表于 2021-5-28 13:38
记得缺点好像是 不能中文路径

合法的路径应该是可以的。但是没有测试过。

Cool_Breeze 发表于 2021-5-28 13:57

本路人 发表于 2021-5-28 13:37
不错,谢谢分享。虽然我自己是用py脚本去做的,没有批处理可以直接发给别人就能使用了这样方便

python处理起来更方便!

a945882813 发表于 2021-5-28 14:02

学习了!
页: [1] 2 3
查看完整版本: 批处理和C# 搜索文件和目录,复制文件和目录源代码,改天加个界面