uTools自动化助手自用代码

1、移动文件到指定目录

// 文件/文件夹移动脚本 - 带合并提示的增强版
// 使用说明:修改下方的 targetDirectory 为你想要移动文件的目标目录路径
// 注意:目标目录必须已存在,否则脚本将提示错误

const fs = require('fs')
const path = require('path')
const { promisify } = require('util')
const crypto = require('crypto')

// 将fs方法转换为Promise版本
const renameAsync = promisify(fs.rename)
const statAsync = promisify(fs.stat)
const mkdirAsync = promisify(fs.mkdir)
const readdirAsync = promisify(fs.readdir)
const readFileAsync = promisify(fs.readFile)

// ⚠️ 请在这里修改为你想要移动文件的目标目录路径 ⚠️
// ⚠️ 注意:此目录必须已存在,脚本不会自动创建 ⚠️
const targetDirectory = 'C:\\Your\\Target\\Directory\\'

// 检查目录是否存在
async function checkDirectoryExists(dirPath) {
  try {
    const stats = await statAsync(dirPath)
    return stats.isDirectory()
  } catch (error) {
    if (error.code === 'ENOENT') return false
    throw error
  }
}

// 确保子目录存在,不存在则创建(仅用于合并文件夹时)
async function ensureSubDirectoryExists(dirPath) {
  try {
    await mkdirAsync(dirPath, { recursive: true })
  } catch (error) {
    if (error.code !== 'EEXIST') throw error
  }
}

// 检查目标位置是否存在同名项
async function checkNameConflict(source, target) {
  try {
    await statAsync(target)
    return true // 存在冲突
  } catch (error) {
    if (error.code === 'ENOENT') return false // 不存在冲突
    throw error // 其他错误
  }
}

// 计算文件的MD5哈希值
async function getFileHash(filePath) {
  try {
    const data = await readFileAsync(filePath)
    return crypto.createHash('md5').update(data).digest('hex')
  } catch (error) {
    console.error(`计算文件哈希值失败: ${filePath}`, error)
    return null
  }
}

// 比较两个文件是否相同
async function areFilesIdentical(file1, file2) {
  try {
    const hash1 = await getFileHash(file1)
    const hash2 = await getFileHash(file2)
    return hash1 === hash2
  } catch (error) {
    console.error(`比较文件失败: ${file1} 和 ${file2}`, error)
    return false
  }
}

// 合并文件夹内容(只移动不同的文件)
async function mergeFolderContents(source, target) {
  const conflicts = []
  const identical = []
  const moved = []
  let mergeNoticeShown = false
  
  try {
    // 确保目标子目录存在
    await ensureSubDirectoryExists(target)
    
    const items = await readdirAsync(source)
    
    for (const item of items) {
      const sourcePath = path.join(source, item)
      const targetPath = path.join(target, item)
      
      const stats = await statAsync(sourcePath)
      if (stats.isDirectory()) {
        if (await checkNameConflict(sourcePath, targetPath)) {
          // 显示同级文件夹合并提示(只显示一次)
          if (!mergeNoticeShown) {
            console.log(`正在合并文件夹: ${path.basename(source)} -> ${path.basename(target)}`)
            mergeNoticeShown = true
          }
          
          // 递归处理子文件夹
          const subResult = await mergeFolderContents(sourcePath, targetPath)
          if (subResult.conflicts) conflicts.push(...subResult.conflicts)
          if (subResult.identical) identical.push(...subResult.identical)
          if (subResult.moved) moved.push(...subResult.moved)
        } else {
          // 直接移动子文件夹
          await renameAsync(sourcePath, targetPath)
          moved.push(path.relative(source, sourcePath))
        }
      } else {
        if (await checkNameConflict(sourcePath, targetPath)) {
          // 检查文件是否相同
          const filesAreIdentical = await areFilesIdentical(sourcePath, targetPath)
          if (filesAreIdentical) {
            console.log(`跳过相同文件: ${path.relative(source, sourcePath)}`)
            identical.push(path.relative(source, sourcePath))
          } else {
            console.log(`跳过不同内容的同名文件: ${path.relative(source, sourcePath)}`)
            conflicts.push(path.relative(source, sourcePath))
          }
          continue // 跳过当前文件
        }
        await renameAsync(sourcePath, targetPath)
        moved.push(path.relative(source, sourcePath))
      }
    }
    
    const relativePath = path.relative(path.dirname(source), source)
    return { 
      success: true,
      conflicts,
      identical,
      moved,
      message: moved.length > 0 
        ? `合并完成: ${relativePath} (移动了 ${moved.length} 个文件/文件夹)` 
        : `没有需要移动的文件: ${relativePath}` 
    }
  } catch (error) {
    console.error(`合并文件夹出错:`, error)
    return { 
      success: false, 
      message: `合并 ${path.basename(source)} 时出错: ${error.message}` 
    }
  }
}

// 移动单个文件(遇到同名时检查内容)
async function moveFile(source, target) {
  try {
    if (await checkNameConflict(source, target)) {
      // 检查文件是否相同
      const filesAreIdentical = await areFilesIdentical(source, target)
      if (filesAreIdentical) {
        console.log(`跳过相同文件: ${path.basename(source)}`)
        return {
          success: false,
          identical: true,
          message: `已跳过: ${path.basename(source)} (文件内容相同)`
        }
      } else {
        console.log(`跳过不同内容的同名文件: ${path.basename(source)}`)
        return {
          success: false,
          skipped: true,
          message: `已跳过: ${path.basename(source)} (同名文件内容不同)`
        }
      }
    }
    
    await renameAsync(source, target)
    return { success: true, message: `已移动: ${path.basename(source)}` }
  } catch (error) {
    console.error(`移动文件出错:`, error)
    return { success: false, message: `移动 ${path.basename(source)} 出错: ${error.message}` }
  }
}

// 主处理函数
async function moveItemsToTarget() {
  // 检查目标目录是否存在
  const targetExists = await checkDirectoryExists(targetDirectory)
  if (!targetExists) {
    const errorMessage = `目标目录不存在: ${targetDirectory}\n请修改脚本中的 targetDirectory 变量为正确的目录路径。`
    console.error(errorMessage)
    utools.showNotification(errorMessage)
    return []
  }
  
  console.log('开始移动操作...')
  console.log(`目标目录: ${targetDirectory}`)
  
  const results = await Promise.all(ENTER.payload.map(async (item) => {
    const sourcePath = item.path
    const itemName = path.basename(sourcePath)
    const targetPath = path.join(targetDirectory, itemName)
    
    try {
      const stats = await statAsync(sourcePath)
      
      if (stats.isDirectory()) {
        if (await checkNameConflict(sourcePath, targetPath)) {
          console.log(`发现同名文件夹: ${itemName}, 开始合并...`)
          return await mergeFolderContents(sourcePath, targetPath)
        } else {
          console.log(`移动文件夹: ${itemName}`)
          await renameAsync(sourcePath, targetPath)
          return { success: true, message: `已移动文件夹: ${itemName}` }
        }
      } else if (stats.isFile()) {
        console.log(`处理文件: ${itemName}`)
        return await moveFile(sourcePath, targetPath)
      }
      
      return { success: false, message: `不支持的类型: ${itemName}` }
    } catch (error) {
      console.error(`处理项目出错:`, error)
      return { success: false, message: `处理 ${itemName} 出错: ${error.message}` }
    }
  }))
  
  // 统计结果
  const successCount = results.filter(r => r.success).length
  const skippedCount = results.filter(r => r.skipped).length
  const identicalCount = results.filter(r => r.identical).length
  const failedCount = results.filter(r => !r.success && !r.skipped && !r.identical).length
  
  // 统计移动的文件
  const movedFiles = results
    .filter(result => result.moved && result.moved.length > 0)
    .flatMap(result => result.moved)
  
  // 统计冲突情况
  const conflicts = results
    .filter(result => result.conflicts && result.conflicts.length > 0)
    .flatMap(result => result.conflicts)
  
  // 显示结果通知
  let notificationMessage = ''
  
  if (successCount > 0 || movedFiles.length > 0) {
    const totalMoved = successCount + movedFiles.length
    notificationMessage += `成功移动: ${totalMoved} 项\n`
  }
  
  if (skippedCount > 0 || conflicts.length > 0) {
    const totalSkipped = skippedCount + conflicts.length
    notificationMessage += `跳过不同内容: ${totalSkipped} 项\n`
  }
  
  if (identicalCount > 0) {
    notificationMessage += `跳过相同内容: ${identicalCount} 项\n`
  }
  
  if (failedCount > 0) {
    notificationMessage += `失败: ${failedCount} 项\n`
  }
  
  // 确保通知始终显示
  if (notificationMessage === '') {
    notificationMessage = '操作完成,但没有处理任何项目'
  } else {
    notificationMessage = `移动操作完成\n${notificationMessage}`
  }
  
  utools.showNotification(notificationMessage.trim())
  
  console.log('操作最终结果:', results)
  return results
}

// 主处理逻辑
if (ENTER.type === 'files') {
  console.log('开始处理选中的文件/文件夹...')
  moveItemsToTarget().catch(error => {
    console.error('操作出错:', error)
    utools.showNotification(`操作失败: ${error.message}`)
  })
} else if (ENTER.type === 'window') {
  utools.showNotification('请在文件管理器中选择文件或文件夹后再执行此操作')
} else {
  utools.showNotification('不支持的操作类型')
} 
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇