diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..a8c2003
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,5 @@
+{
+ "python-envs.defaultEnvManager": "ms-python.python:conda",
+ "python-envs.defaultPackageManager": "ms-python.python:conda",
+ "python-envs.pythonProjects": []
+}
\ No newline at end of file
diff --git a/App.xaml.cs b/App.xaml.cs
index e874970..48b8709 100644
--- a/App.xaml.cs
+++ b/App.xaml.cs
@@ -1,4 +1,4 @@
-using System.Configuration;
+using System.Configuration;
using System.Data;
using System.Windows;
@@ -7,7 +7,7 @@ namespace CopyRou
///
/// Interaction logic for App.xaml
///
- public partial class App : Application
+ public partial class App : System.Windows.Application
{
}
diff --git a/AppConfig.cs b/AppConfig.cs
new file mode 100644
index 0000000..0703a93
--- /dev/null
+++ b/AppConfig.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text.Json;
+
+namespace CopyRou
+{
+ public class AppConfig
+ {
+ public List SourcePaths { get; set; } = new();
+ public string DestPath { get; set; } = string.Empty;
+
+ private static readonly string ConfigPath = Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ "CopyRou", "config.json");
+
+ public static AppConfig Load()
+ {
+ try
+ {
+ if (File.Exists(ConfigPath))
+ {
+ var json = File.ReadAllText(ConfigPath);
+ return JsonSerializer.Deserialize(json) ?? new AppConfig();
+ }
+ }
+ catch (Exception ex)
+ {
+ // 如果加载失败,返回默认配置
+ System.Diagnostics.Debug.WriteLine($"加载配置失败: {ex.Message}");
+ }
+
+ return new AppConfig
+ {
+ SourcePaths = new List
+ {
+ @"Z:\Routing\A1-ROUTING\NEW-ROUTING",
+ @"Z:\Routing\A2-ROUTING\NEW-ROUTING"
+ },
+ DestPath = @"D:\ARPTWork\rou"
+ };
+ }
+
+ public void Save()
+ {
+ try
+ {
+ var directory = Path.GetDirectoryName(ConfigPath);
+ if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
+ Directory.CreateDirectory(directory);
+
+ var json = JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
+ File.WriteAllText(ConfigPath, json);
+ }
+ catch (Exception ex)
+ {
+ System.Diagnostics.Debug.WriteLine($"保存配置失败: {ex.Message}");
+ }
+ }
+
+ public string GetSourcePathsText()
+ {
+ return string.Join(Environment.NewLine, SourcePaths);
+ }
+
+ public void SetSourcePathsFromText(string text)
+ {
+ SourcePaths.Clear();
+ if (!string.IsNullOrWhiteSpace(text))
+ {
+ var paths = text.Split(new[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);
+ foreach (var path in paths)
+ {
+ var trimmedPath = path.Trim();
+ if (!string.IsNullOrEmpty(trimmedPath))
+ {
+ SourcePaths.Add(trimmedPath);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/CopyRou.csproj b/CopyRou.csproj
index f01bf10..efbaa4d 100644
--- a/CopyRou.csproj
+++ b/CopyRou.csproj
@@ -1,4 +1,4 @@
-
+
WinExe
@@ -6,6 +6,7 @@
enable
enable
true
+ true
AnyCPU;x86
diff --git a/FileService.cs b/FileService.cs
new file mode 100644
index 0000000..9f965ec
--- /dev/null
+++ b/FileService.cs
@@ -0,0 +1,151 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace CopyRou
+{
+ public class FileService : IFileService
+ {
+ public bool MatchFolderName(string folderName, string numPart, string versionPart)
+ {
+ if (string.IsNullOrEmpty(folderName) ||
+ string.IsNullOrEmpty(numPart) ||
+ string.IsNullOrEmpty(versionPart))
+ return false;
+
+ var folderNameLower = folderName.ToLower();
+ var numLength = numPart.Length;
+
+ // 检查文件夹名长度是否足够
+ if (folderNameLower.Length < 3 + numLength)
+ return false;
+
+ // 从第4个字符开始匹配数字编号(索引3)
+ var numInName = folderNameLower.Substring(3, numLength);
+ if (numInName != numPart.ToLower())
+ return false;
+
+ // 检查版本部分
+ var versionInName = folderNameLower.Substring(3 + numLength);
+ return versionInName.StartsWith(versionPart.ToLower());
+ }
+
+ public List CopyRouFiles(string sourceFolder, string number, string destPath, ILogger logger)
+ {
+ var copiedFiles = new List();
+ var edFoldersFound = 0;
+ var rouExtensions = new[] { ".rou", ".rou1", ".rou2", ".rou3" };
+
+ try
+ {
+ // 确保目标目录存在
+ Directory.CreateDirectory(destPath);
+
+ foreach (var item in Directory.GetDirectories(sourceFolder))
+ {
+ var folderName = Path.GetFileName(item);
+ if (folderName.StartsWith("ED", StringComparison.OrdinalIgnoreCase) ||
+ folderName.StartsWith("ROU", StringComparison.OrdinalIgnoreCase))
+ {
+ edFoldersFound++;
+ logger?.Log($"正在处理ED文件夹: {folderName}");
+
+ // 递归查找所有.rou文件
+ var rouFiles = Directory.GetFiles(item, "*.*", SearchOption.AllDirectories)
+ .Where(file => rouExtensions.Contains(Path.GetExtension(file).ToLower()))
+ .ToList();
+
+ foreach (var srcFile in rouFiles)
+ {
+ var fileName = Path.GetFileName(srcFile);
+ var baseName = $"{number}_{folderName}_{fileName}";
+ var destFile = Path.Combine(destPath, baseName);
+
+ File.Copy(srcFile, destFile, true);
+ copiedFiles.Add(baseName);
+ }
+ }
+ }
+
+ if (edFoldersFound == 0)
+ {
+ logger?.LogWarning("未找到任何以ED或ROU开头的文件夹");
+ }
+ else if (!copiedFiles.Any())
+ {
+ logger?.LogWarning("在ED文件夹中未找到任何.rou系列文件");
+ }
+ else
+ {
+ logger?.Log($"成功从 {edFoldersFound} 个ED文件夹复制 {copiedFiles.Count} 个文件");
+ }
+ }
+ catch (Exception ex)
+ {
+ logger?.LogError($"复制文件时发生错误: {ex.Message}");
+ }
+
+ return copiedFiles;
+ }
+
+ public async Task ProcessCodes(List codes, List sourcePaths, string destPath,
+ IProgress progress, ILogger logger)
+ {
+ var totalCodes = codes.Count;
+ var processedCodes = 0;
+
+ foreach (var code in codes)
+ {
+ var trimmedCode = code.Trim();
+ if (string.IsNullOrEmpty(trimmedCode))
+ continue;
+
+ logger?.Log($"\n处理编号: {trimmedCode}");
+
+ var numPart = trimmedCode.Length >= 5 ? trimmedCode.Substring(0, 5) : trimmedCode;
+ var versionPart = trimmedCode.Length > 5 ? trimmedCode.Substring(5) : "";
+
+ var found = false;
+
+ foreach (var sourceRoot in sourcePaths)
+ {
+ var numFolder = Path.Combine(sourceRoot, numPart);
+ if (!Directory.Exists(numFolder))
+ continue;
+
+ try
+ {
+ var folders = Directory.GetDirectories(numFolder);
+ foreach (var folder in folders)
+ {
+ var folderName = Path.GetFileName(folder);
+ if (MatchFolderName(folderName, numPart, versionPart))
+ {
+ logger?.Log($"找到匹配文件夹: {folder}");
+ CopyRouFiles(folder, numPart, destPath, logger ?? new Logger());
+ found = true;
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ logger?.LogError($"访问文件夹 {numFolder} 时发生错误: {ex.Message}");
+ }
+ }
+
+ if (!found)
+ {
+ logger?.Log("未找到匹配的文件夹");
+ }
+
+ processedCodes++;
+ progress?.Report((int)((double)processedCodes / totalCodes * 100));
+
+ // 添加小延迟以避免UI阻塞
+ await Task.Delay(10);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/IFileService.cs b/IFileService.cs
new file mode 100644
index 0000000..f9bc87e
--- /dev/null
+++ b/IFileService.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.Threading.Tasks;
+
+namespace CopyRou
+{
+ public interface IFileService
+ {
+ bool MatchFolderName(string folderName, string numPart, string versionPart);
+ List CopyRouFiles(string sourceFolder, string number, string destPath, ILogger logger);
+ Task ProcessCodes(List codes, List sourcePaths, string destPath, IProgress progress, ILogger logger);
+ }
+}
\ No newline at end of file
diff --git a/ILogger.cs b/ILogger.cs
new file mode 100644
index 0000000..e2c730a
--- /dev/null
+++ b/ILogger.cs
@@ -0,0 +1,11 @@
+namespace CopyRou
+{
+ public interface ILogger
+ {
+ void Log(string message);
+ void LogError(string message);
+ void LogWarning(string message);
+ void Clear();
+ event System.EventHandler? MessageLogged;
+ }
+}
\ No newline at end of file
diff --git a/Logger.cs b/Logger.cs
new file mode 100644
index 0000000..44fb54d
--- /dev/null
+++ b/Logger.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace CopyRou
+{
+ public class Logger : ILogger
+ {
+ public event EventHandler? MessageLogged;
+
+ public void Log(string message)
+ {
+ var timestampedMessage = $"[{DateTime.Now:HH:mm:ss}] {message}";
+ MessageLogged?.Invoke(this, timestampedMessage);
+ }
+
+ public void LogError(string message)
+ {
+ var timestampedMessage = $"[{DateTime.Now:HH:mm:ss}] [错误] {message}";
+ MessageLogged?.Invoke(this, timestampedMessage);
+ }
+
+ public void LogWarning(string message)
+ {
+ var timestampedMessage = $"[{DateTime.Now:HH:mm:ss}] [警告] {message}";
+ MessageLogged?.Invoke(this, timestampedMessage);
+ }
+
+ public void Clear()
+ {
+ MessageLogged?.Invoke(this, "[LOG CLEARED]");
+ }
+ }
+}
\ No newline at end of file
diff --git a/MainWindow.xaml b/MainWindow.xaml
index 4a33dc9..354a9c2 100644
--- a/MainWindow.xaml
+++ b/MainWindow.xaml
@@ -1,12 +1,215 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/MainWindow.xaml.cs b/MainWindow.xaml.cs
index 55fe1a4..316f33a 100644
--- a/MainWindow.xaml.cs
+++ b/MainWindow.xaml.cs
@@ -1,13 +1,13 @@
-using System.Text;
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
+using MessageBox = System.Windows.MessageBox;
namespace CopyRou
{
@@ -16,9 +16,269 @@ namespace CopyRou
///
public partial class MainWindow : Window
{
+ private readonly IFileService _fileService;
+ private readonly ILogger _logger;
+ private AppConfig _config;
+ private bool _isProcessing = false;
+
public MainWindow()
{
InitializeComponent();
+ _fileService = new FileService();
+ _logger = new Logger();
+ _config = AppConfig.Load();
+
+ InitializeUI();
+ SubscribeToEvents();
+ }
+
+ private void InitializeUI()
+ {
+ // 加载配置到UI
+ SourcePathsTextBox.Text = _config.GetSourcePathsText();
+ DestPathTextBox.Text = _config.DestPath;
+
+ // 设置初始状态
+ StartButton.IsEnabled = true;
+ ProgressBar.Value = 0;
+ }
+
+ private void SubscribeToEvents()
+ {
+ // 订阅日志事件
+ _logger.MessageLogged += (sender, message) =>
+ {
+ Dispatcher.Invoke(() =>
+ {
+ LogTextBox.AppendText(message + Environment.NewLine);
+ LogTextBox.ScrollToEnd();
+ });
+ };
+ }
+
+ private async void StartButton_Click(object sender, RoutedEventArgs e)
+ {
+ if (_isProcessing)
+ return;
+
+ var codesText = CodesTextBox.Text;
+ if (string.IsNullOrWhiteSpace(codesText))
+ {
+ System.Windows.MessageBox.Show("请输入要处理的料号", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ var sourcePaths = GetSourcePaths();
+ if (!sourcePaths.Any())
+ {
+ System.Windows.MessageBox.Show("请至少配置一个源路径", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ var destPath = DestPathTextBox.Text;
+ if (string.IsNullOrWhiteSpace(destPath))
+ {
+ System.Windows.MessageBox.Show("请配置目标路径", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ _isProcessing = true;
+ StartButton.IsEnabled = false;
+ ProgressBar.Value = 0;
+ LogTextBox.Clear();
+
+ try
+ {
+ _logger.Log("=== 开始处理 ===");
+ _logger.Log($"源路径: {string.Join(", ", sourcePaths)}");
+ _logger.Log($"目标路径: {destPath}");
+
+ var materialNumbers = codesText.Split(new[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries)
+ .ToList();
+
+ var progress = new Progress(value =>
+ {
+ ProgressBar.Value = value;
+ });
+
+ await _fileService.ProcessCodes(materialNumbers, sourcePaths, destPath, progress, _logger);
+
+ _logger.Log("=== 处理完成 ===");
+ System.Windows.MessageBox.Show("处理完成!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"处理过程中发生错误: {ex.Message}");
+ System.Windows.MessageBox.Show($"处理过程中发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ finally
+ {
+ _isProcessing = false;
+ StartButton.IsEnabled = true;
+ }
+ }
+
+ private void ClearButton_Click(object sender, RoutedEventArgs e)
+ {
+ CodesTextBox.Clear();
+ LogTextBox.Clear();
+ ProgressBar.Value = 0;
+ }
+
+ private void SaveConfigButton_Click(object sender, RoutedEventArgs e)
+ {
+ _config.SetSourcePathsFromText(SourcePathsTextBox.Text);
+ _config.DestPath = DestPathTextBox.Text;
+ _config.Save();
+
+ System.Windows.MessageBox.Show("配置已保存", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ }
+
+ private void AddSourceButton_Click(object sender, RoutedEventArgs e)
+ {
+ var dialog = new System.Windows.Forms.FolderBrowserDialog();
+ dialog.Description = "选择源路径";
+
+ if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
+ {
+ var currentPaths = GetSourcePaths();
+ if (!currentPaths.Contains(dialog.SelectedPath))
+ {
+ currentPaths.Add(dialog.SelectedPath);
+ SourcePathsTextBox.Text = string.Join(Environment.NewLine, currentPaths);
+ }
+ }
+ }
+
+ private void BrowseDestButton_Click(object sender, RoutedEventArgs e)
+ {
+ var dialog = new System.Windows.Forms.FolderBrowserDialog();
+ dialog.Description = "选择目标路径";
+
+ if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
+ {
+ DestPathTextBox.Text = dialog.SelectedPath;
+ }
+ }
+
+ private List GetSourcePaths()
+ {
+ var paths = new List();
+ if (!string.IsNullOrWhiteSpace(SourcePathsTextBox.Text))
+ {
+ paths = SourcePathsTextBox.Text.Split(new[] { Environment.NewLine, "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries)
+ .Select(p => p.Trim())
+ .Where(p => !string.IsNullOrEmpty(p))
+ .ToList();
+ }
+ return paths;
+ }
+
+ private void SingleCodeTextBox_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
+ {
+ if (e.Key == System.Windows.Input.Key.Enter)
+ {
+ ProcessSingleCode();
+ }
+ }
+
+ private async void AddSingleCodeButton_Click(object sender, RoutedEventArgs e)
+ {
+ await ProcessSingleCodeAsync();
+ }
+
+ private void ProcessSingleCode()
+ {
+ if (_isProcessing)
+ return;
+
+ var code = SingleCodeTextBox.Text.Trim();
+ if (string.IsNullOrWhiteSpace(code))
+ {
+ System.Windows.MessageBox.Show("请输入要处理的料号", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ // 异步处理单个料号
+ _ = ProcessSingleCodeAsync();
+ }
+
+ private async Task ProcessSingleCodeAsync()
+ {
+ if (_isProcessing)
+ return;
+
+ var code = SingleCodeTextBox.Text.Trim();
+ if (string.IsNullOrWhiteSpace(code))
+ {
+ System.Windows.MessageBox.Show("请输入要处理的料号", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ var sourcePaths = GetSourcePaths();
+ if (!sourcePaths.Any())
+ {
+ System.Windows.MessageBox.Show("请至少配置一个源路径", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ var destPath = DestPathTextBox.Text;
+ if (string.IsNullOrWhiteSpace(destPath))
+ {
+ System.Windows.MessageBox.Show("请配置目标路径", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
+ return;
+ }
+
+ _isProcessing = true;
+ AddSingleCodeButton.IsEnabled = false;
+ SingleCodeTextBox.IsEnabled = false;
+
+ try
+ {
+ _logger.Log($"=== 开始处理单个料号: {code} ===");
+ _logger.Log($"源路径: {string.Join(", ", sourcePaths)}");
+ _logger.Log($"目标路径: {destPath}");
+
+ var materialNumbers = new List { code };
+
+ // 创建一个简单的进度报告器,单个料号处理时直接设置为100%
+ var progress = new Progress(value =>
+ {
+ // 对于单个料号,我们可以直接设置进度条
+ ProgressBar.Value = value;
+ });
+
+ await _fileService.ProcessCodes(materialNumbers, sourcePaths, destPath, progress, _logger);
+
+ _logger.Log("=== 单个料号处理完成 ===");
+
+ // 清空输入框
+ SingleCodeTextBox.Clear();
+
+ // 将焦点返回到输入框,方便继续输入
+ SingleCodeTextBox.Focus();
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError($"处理单个料号时发生错误: {ex.Message}");
+ System.Windows.MessageBox.Show($"处理单个料号时发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+ }
+ finally
+ {
+ _isProcessing = false;
+ AddSingleCodeButton.IsEnabled = true;
+ SingleCodeTextBox.IsEnabled = true;
+ }
+ }
+
+ protected override void OnClosed(EventArgs e)
+ {
+ // 自动保存配置
+ _config.SetSourcePathsFromText(SourcePathsTextBox.Text);
+ _config.DestPath = DestPathTextBox.Text;
+ _config.Save();
+
+ base.OnClosed(e);
}
}
}
\ No newline at end of file
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d680fbd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,87 @@
+# ROU文件复制工具
+
+这是一个基于WPF的C#应用程序,用于根据编号和版本匹配文件夹,然后复制其中的.rou文件到目标位置。
+
+## 功能特性
+
+- 根据输入的料号(如"27362a")自动匹配特定格式的文件夹
+- 批量处理多个料号
+- 复制匹配文件夹中的.rou、.rou1、.rou2、.rou3文件
+- 实时显示处理进度和日志信息
+- 配置管理(源路径、目标路径)
+- 简洁易用的用户界面
+
+## 使用方法
+
+### 1. 配置路径
+
+- **源路径**:在"源路径"文本框中输入要搜索的根目录,每行一个路径
+ - 默认路径:
+ - `Z:\Routing\A1-ROUTING\NEW-ROUTING`
+ - `Z:\Routing\A2-ROUTING\NEW-ROUTING`
+- **目标路径**:在"目标路径"文本框中输入复制文件的目标位置
+ - 默认路径:`D:\ARPTWork\rou`
+
+### 2. 输入料号
+
+在"料号输入"文本框中输入要处理的料号,每行一个,例如:
+```
+27362a
+27363b
+27364c
+```
+
+### 3. 开始处理
+
+点击"开始处理"按钮,应用程序将:
+1. 根据每个料号的前5位作为数字部分,剩余部分作为版本部分
+2. 在源路径中查找匹配的文件夹
+3. 复制找到的.rou系列文件到目标路径
+4. 显示处理进度和详细日志
+
+### 4. 其他功能
+
+- **清空**:清空输入的料号和日志
+- **保存配置**:保存当前的路径配置
+- **添加**:通过文件夹浏览器添加源路径
+- **浏览**:通过文件夹浏览器选择目标路径
+
+## 文件夹匹配规则
+
+应用程序使用以下规则匹配文件夹:
+- 料号格式:前5位为数字部分,剩余部分为版本部分
+- 文件夹匹配:从文件夹名第4个字符开始匹配数字编号
+- 搜索范围:在源路径下的数字编号文件夹中查找匹配的子文件夹
+
+## 文件复制规则
+
+- 只处理以"ED"或"ROU"开头的文件夹
+- 复制扩展名为.rou、.rou1、.rou2、.rou3的文件
+- 目标文件名格式:`{数字部分}_{文件夹名}_{原文件名}`
+
+## 技术架构
+
+- **框架**:.NET 6.0 WPF
+- **架构模式**:分层架构,使用接口和依赖注入
+- **主要组件**:
+ - `FileService`:核心文件操作逻辑
+ - `AppConfig`:配置管理
+ - `Logger`:日志记录
+ - `MainWindow`:用户界面
+
+## 构建和运行
+
+```bash
+# 构建项目
+dotnet build
+
+# 运行应用程序
+dotnet run
+```
+
+## 注意事项
+
+- 确保有足够的权限访问源路径和目标路径
+- 目标路径会自动创建(如果不存在)
+- 处理过程中请勿关闭应用程序
+- 配置会自动保存,下次启动时会自动加载
\ No newline at end of file
diff --git a/demo/copy_rou.py b/demo/copy_rou.py
new file mode 100644
index 0000000..125ac3f
--- /dev/null
+++ b/demo/copy_rou.py
@@ -0,0 +1,108 @@
+import os
+import shutil
+
+SOURCE_PATHS = [
+ r"Z:\Routing\A1-ROUTING\NEW-ROUTING",
+ r"Z:\Routing\A2-ROUTING\NEW-ROUTING"
+]
+DEST_PATH = r"D:\ARPTWork\rou"
+
+def match_folder_name(folder_name, num_part, version_part):
+ """匹配逻辑:从第四个字符开始匹配数字编号"""
+ folder_name_lower = folder_name.lower()
+ num_length = len(num_part)
+
+ if len(folder_name_lower) < 3 + num_length:
+ return False
+
+ num_in_name = folder_name_lower[4 : 4+num_length]
+ if num_in_name != num_part.lower():
+ return False
+
+ version_in_name = folder_name_lower[4+num_length:]
+ return version_in_name.startswith(version_part.lower())
+
+def copy_rou_files(source_folder, number):
+ """复制所有.rou系列文件"""
+ os.makedirs(DEST_PATH, exist_ok=True)
+ copied_files = []
+ ed_folders_found = 0
+
+ for item in os.listdir(source_folder):
+ item_path = os.path.join(source_folder, item)
+
+ if os.path.isdir(item_path) and (item.lower().startswith('ed') or item.lower().startswith('rou')):
+ ed_folders_found += 1
+ print(f"正在处理ED文件夹: {item}")
+
+ for root, _, files in os.walk(item_path):
+ for file in files:
+ if file.lower().endswith(('.rou', '.rou1', '.rou2', '.rou3')):
+ src_file = os.path.join(root, file)
+ base_name = f"{number}_{item}_{file}"
+ dest_file = os.path.join(DEST_PATH, base_name)
+
+ shutil.copy2(src_file, dest_file)
+ copied_files.append(base_name)
+
+ if ed_folders_found == 0:
+ print("警告: 未找到任何以ED开头的文件夹")
+ elif not copied_files:
+ print("警告: 在ED文件夹中未找到任何.rou系列文件")
+ else:
+ print(f"成功从 {ed_folders_found} 个ED文件夹复制 {len(copied_files)} 个文件:")
+
+def process_codes(code_list):
+ """处理多个代码"""
+ for code in code_list:
+ code = code.strip()
+ if not code:
+ continue
+
+ print(f"\n处理编号: {code}")
+ num_part = code[:5]
+ version_part = code[len(num_part):]
+
+ found = False
+ for source_root in SOURCE_PATHS:
+ num_folder = os.path.join(source_root, num_part)
+ if not os.path.exists(num_folder):
+ continue
+
+ for folder in os.listdir(num_folder):
+ if match_folder_name(folder, num_part, version_part):
+ full_path = os.path.join(num_folder, folder)
+ print(f"找到匹配文件夹: {full_path}")
+ copy_rou_files(full_path, num_part)
+ found = True
+
+ if not found:
+ print("未找到匹配的文件夹")
+
+def main():
+ print("=== 文件复制工具 ===")
+ print(f"搜索路径: {SOURCE_PATHS}")
+ print(f"目标路径: {DEST_PATH}")
+ print("输入说明:")
+ print("1. 直接输入单个编号,如: 27362a")
+ print("2. 输入多行编号(每行一个),最后输入end结束")
+ print("3. 输入exit退出程序")
+
+ while True:
+ print("\n请输入编号(支持多行输入):")
+ user_inputs = []
+
+ while True:
+ line = input().strip()
+ if line.lower() == 'end':
+ break
+ if line.lower() == 'exit':
+ return
+ if line:
+ user_inputs.append(line)
+
+ if user_inputs:
+ process_codes(user_inputs)
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file