根据拍摄时间一键将图片分组

说在前面

最近裸辞出去玩了两个多月,旅行的过程中少不了拍照,祖国的大好河山太美了,一趟旅行下来产出了1w多张图片,所以回来后总要整理一下图片,我这边想要的是根据拍摄时间来对图片进行分组,所以回到家后我就写了这样一个脚本来处理图片。

工具实现

1、模块导入

  • inquirer

通过require(“@jyeontu/j - inquirer”)导入,用于创建命令行交互,让用户选择需要分组的目录。

  • fs

使用require(“fs”)导入,用于进行文件系统的操作,如读取目录内容(readdirSync)、获取文件状态(statSync)、创建文件夹(mkdirSync)以及复制文件(copyFileSync)等操作。
path模块:通过require(“path”)导入,用于处理文件路径,如拼接路径(join)等操作。

  • exif

使用require(“exif”).ExifImage导入,用于读取图片的 Exif 数据,以便获取图片的拍摄时间。

2、获取图片拍摄时间

function getPictureTakingTime(imagePath) {
  return new Promise((resolve) => {
    try {
      new ExifImage({ image: imagePath }, function (error, exifData) {
        if (error) {
          resolve(null);
        } else {
          if (exifData && exifData.exif) {
            const takingTime = exifData.exif.DateTimeOriginal;
            resolve(takingTime);
          } else {
            resolve(null);
          }
        }
      });
    } catch (error) {
      resolve(null);
    }
  });
}
  • 函数接受一个图片路径imagePath作为参数,并返回一个Promise。
  • 在函数内部,通过new ExifImage来尝试读取图片的 Exif 数据。如果读取过程中出现错误(error)或者图片没有 Exif 数据(exifData && exifData.exif不满足),则Promise返回null;如果成功读取到 Exif 数据并且包含DateTimeOriginal属性(表示拍摄时间),则将该拍摄时间作为Promise的结果返回。

3、通过交互获取需要分组的目录

const baseDir = process.cwd();
const options = [
  {
    type: "folder",
    message: "请选择需要分组的目录:",
    name: "directory",
    default: "",
    dirname: baseDir,
  },
];
const answers = await new inquirer(options).prompt();
const dirPath = answers.directory;
  • 首先获取当前工作目录(process.cwd())作为基础目录baseDir。
  • 通过inquirer创建一个交互选项,提示用户选择需要分组的目录。用户选择的结果存储在answers.directory中,即dirPath变量。

4、遍历文件并分组

const files = fs.readdirSync(dirPath);
const map = {};
let sum = 0;
console.log(`正在获取图片信息,请稍等……`);
for (const file of files) {
  const newPath = path.join(dirPath, file);
  const info = fs.statSync(newPath);
  if (!info.isFile()) {
    continue;
  }
  sum++;
  const m = (await getPictureTakingTime(newPath)) || dateFormat(info.mtime);
  const mArr = m.split(" ");
  mArr[0] = mArr[0].split(":").join("-");
  const mtime = dateFormat(mArr.join(" "));
  if (!map[mtime]) {
    map[mtime] = [];
  }
  map[mtime].push(file);
}
  • 使用fs.readdirSync(dirPath)读取目标目录下的所有文件和文件夹。
  • 创建一个空对象map用于存储分组信息。
  • 定义变量sum用于统计文件数量,初始值为 0。
  • 遍历目标目录下的每个文件:
    • 通过path.join(dirPath, file)构建文件的完整路径newPath。
    • 使用fs.statSync(newPath)获取文件状态信息info,如果不是文件(!info.isFile())则跳过该文件。
    • 对于每个文件,sum自增 1,并尝试获取图片拍摄时间。如果getPictureTakingTime(newPath)返回null(即没有拍摄时间 Exif 数据),则使用dateFormat(info.mtime)对文件修改时间进行格式化;否则使用拍摄时间。
    • 对获取到的时间进行处理,将时间字符串中的:替换为-,然后再使用dateFormat进行格式化,得到最终的日期格式mtime。
    • 如果map中不存在以mtime为键的属性,则创建一个空数组作为值;然后将文件名称添加到对应的日期数组中。

5、创建分组目录并移动文件

for (const key in map) {
  const keyPath = path.join(dirPath, key);
  if (!fs.existsSync(keyPath)) {
    fs.mkdirSync(keyPath);
  }
  for (const p of map[key]) {
    const np = path.join(keyPath, p);
    if (fs.existsSync(np)) {
      continue;
    }
    fs.copyFileSync(path.join(dirPath, p), path.join(keyPath, p));
  }
}
  • 遍历map中的每个日期键key:
    • 通过path.join(dirPath, key)构建分组文件夹的路径keyPath。
    • 如果该文件夹不存在(!fs.existsSync(keyPath)),则使用fs.mkdirSync(keyPath)创建文件夹。
    • 遍历每个日期对应的文件数组中的文件p:
      • 通过path.join(keyPath, p)构建目标文件路径np。
      • 如果目标文件已经存在(fs.existsSync(np)),则跳过;否则使用fs.copyFileSync将文件从源路径(path.join(dirPath, p))复制到目标路径。

使用

该工具已经发布到 npm 上,可以直接通过命令npm i -g jyeontu进行安装,安装完后在控制台中输入jyeontu file即可进行操作。选择图片分组即可:

源码

Gitee

该工具的源码也已经开源,有兴趣的同学可以到Gitee上查看:https://gitee.com/zheng_yongtao/node-scripting-tool/tree/master/src/jyeontu

欢迎star~

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JYeontu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值