You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#实现按文件名规则将多层目录文件移动到对应指定文件夹

功能实现说明

现有代码仅完成了目标文件夹创建逻辑,未实现实际文件移动,且原有逻辑仅遍历根目录文件、无异常容错,无法适配数千万级多子文件夹文件的批量移动需求。
功能界面预览

原有代码片段:

using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;

namespace File2Folders
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        List<string> fileName = null;
        List<string> fileNames = null;
        private void btn_browse_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog fbd = new FolderBrowserDialog())
            {
                if (fbd.ShowDialog() == DialogResult.OK)
                {
                    listBox1.Items.Clear();
                    // 原有逻辑仅读取根目录文件,未遍历子文件夹
                    fileName = Directory.GetFiles(fbd.SelectedPath).ToList();
                    fileNames = fileName.Select(item => Path.GetFileNameWithoutExtension(item).Substring(1, 4)).OrderBy(n=>n).ToList();
                    listBox1.DataSource = fileName.Select(f => Path.GetFileName(f)).ToList();
                    listBox2.DataSource = fileNames;         
                }
            }
        }
        private void btn_move_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog fbd = new FolderBrowserDialog())
            {
                if (fbd.ShowDialog() == DialogResult.OK)
                {
                    // 原有逻辑仅创建文件夹,未执行移动
                    fileNames.ForEach(item => Directory.CreateDirectory(Path.Combine(fbd.SelectedPath, item)));
                
                }
改造后完整实现

核心改造点:

  • 用Directory.EnumerateFiles递归遍历所有子文件夹文件,采用迭代读取方式,避免一次性加载数千万文件路径导致内存溢出
  • 增加文件名长度校验,避免短文件名调用Substring时抛出索引越界异常
  • 增加重名文件处理逻辑,默认给重名文件追加序号后缀,不会中断批量任务
  • 增加单文件异常捕获,单个文件移动失败不影响整体任务执行
  • 移动操作放在后台线程执行,避免UI界面卡死

完整代码如下:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace File2Folders
{
    public partial class Form1 : Form
    {
        private string _sourcePath = string.Empty;
        public Form1()
        {
            InitializeComponent();
        }

        private void btn_browse_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog fbd = new FolderBrowserDialog())
            {
                if (fbd.ShowDialog() == DialogResult.OK)
                {
                    _sourcePath = fbd.SelectedPath;
                    listBox1.Items.Clear();
                    listBox2.Items.Clear();
                    // 仅预览前100个文件,避免全量加载导致卡顿
                    var previewFiles = Directory.EnumerateFiles(_sourcePath, "*", SearchOption.AllDirectories)
                        .Take(100)
                        .Select(f => Path.GetFileName(f))
                        .ToList();
                    listBox1.Items.AddRange(previewFiles.ToArray());
                    MessageBox.Show("已选择源目录,因文件量较大仅预览前100个文件");
                }
            }
        }

        private async void btn_move_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(_sourcePath))
            {
                MessageBox.Show("请先选择要处理的源文件目录");
                return;
            }
            using (FolderBrowserDialog fbd = new FolderBrowserDialog())
            {
                if (fbd.ShowDialog() == DialogResult.OK)
                {
                    string targetRootPath = fbd.SelectedPath;
                    btn_move.Enabled = false;
                    long movedCount = 0;
                    long errorCount = 0;
                    try
                    {
                        // 后台执行移动操作,不阻塞UI线程
                        await Task.Run(() =>
                        {
                            // 递归遍历所有子文件夹文件,逐次返回文件路径,内存占用极低
                            foreach (string filePath in Directory.EnumerateFiles(_sourcePath, "*", SearchOption.AllDirectories))
                            {
                                try
                                {
                                    string fileNameWithoutExt = Path.GetFileNameWithoutExtension(filePath);
                                    // 校验文件名长度,避免短文件名报错
                                    if (fileNameWithoutExt.Length < 5)
                                    {
                                        errorCount++;
                                        continue;
                                    }
                                    // 匹配原有规则:取文件名第2位开始的4个字符作为目标文件夹名
                                    string targetFolderName = fileNameWithoutExt.Substring(1, 4);
                                    string targetFolderPath = Path.Combine(targetRootPath, targetFolderName);
                                    // 文件夹不存在才创建,减少重复IO操作
                                    if (!Directory.Exists(targetFolderPath))
                                    {
                                        Directory.CreateDirectory(targetFolderPath);
                                    }
                                    string targetFilePath = Path.Combine(targetFolderPath, Path.GetFileName(filePath));
                                    // 重名文件自动追加序号
                                    int dupIndex = 1;
                                    while (File.Exists(targetFilePath))
                                    {
                                        string dupFileName = $"{Path.GetFileNameWithoutExtension(filePath)}_{dupIndex}{Path.GetExtension(filePath)}";
                                        targetFilePath = Path.Combine(targetFolderPath, dupFileName);
                                        dupIndex++;
                                    }
                                    // 执行文件移动
                                    File.Move(filePath, targetFilePath);
                                    movedCount++;
                                    // 每处理1000个文件更新一次进度
                                    if (movedCount % 1000 == 0)
                                    {
                                        Invoke(new Action(() =>
                                        {
                                            listBox2.Items.Add($"已移动{movedCount}个文件");
                                            listBox2.TopIndex = listBox2.Items.Count - 1;
                                        }));
                                    }
                                }
                                catch
                                {
                                    errorCount++;
                                }
                            }
                        });
                        MessageBox.Show($"移动完成,成功移动{movedCount}个文件,失败{errorCount}个文件");
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show($"执行出错:{ex.Message}");
                    }
                    finally
                    {
                        btn_move.Enabled = true;
                    }
                }
            }
        }
    }
}

注意:正式处理数千万文件前,建议先拿少量测试文件验证文件夹命名规则、移动逻辑符合预期,避免规则错误导致文件归类混乱。

内容的提问来源于stack exchange,提问作者Mohini Singh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 09:18:17