批处理和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;
}
} QQending 发表于 2021-5-28 14:30
对的,打包exe,主要是包太大了
不过说实话,本人,一方面批处理写的少,不光对语法,对换行也不熟练 ...
https://docs.microsoft.com/zh-cn/windows-server/administration/windows-commands/echo Cool_Breeze 发表于 2021-5-28 13:57
python处理起来更方便!
python自用自然好,但如果给别人尤其是电脑小白使用还要打包exe啊,不然别人没有python环境的用不了:rggrg 不错,谢谢分享。虽然我自己是用py脚本去做的,没有批处理可以直接发给别人就能使用了这样方便 记得缺点好像是 不能中文路径 多谢楼主分享! 感谢楼主分享,有空试试,加分致谢 {:301_972:}真不错 解决了大量文件复制粘贴的事情了 as614001 发表于 2021-5-28 13:38
记得缺点好像是 不能中文路径
合法的路径应该是可以的。但是没有测试过。 本路人 发表于 2021-5-28 13:37
不错,谢谢分享。虽然我自己是用py脚本去做的,没有批处理可以直接发给别人就能使用了这样方便
python处理起来更方便! 学习了!