npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

upload-many-files

v1.3.2

Published

命令行上传多文件工具

Downloads

6

Readme

upload-many-files

多文件上传,适合大规模上传文件,包含动态配置、多层文件夹扫描、中断续传、进度显示、上传统计等特性。设计容量标准为总量 1T 以下,单个文件 1M - 1G 之间。

使用相关

安装

$ npm install -g upload-many-files

配置初始化

upload-many-files-init --server-url http://xx.xx.xx --folder-path /home/user/xxx --extname .jpeg,.png
  • server-url,接收上传的服务。
  • folder-path,本地文件存储的文件夹,将对文件夹中的全部文件进行扫描,如果你是 Windows 记得加上盘符 D:\testqun。
  • extname,要上传文件的后缀,注意扩展名不区分大小写。

开始上传

upload-many-files-start --upload-params source=hz,batch=hz-2019-6-24,diseasesType=fundus

上传的逻辑是先扫面全部需要上传的文件,将每个需要上传的文件生成一条上传任务,写入 data/jobs.json。upload-params 为可选参数,定义上传时额外的自定义参数。

查看初始化配置

upload-many-files-get-init-config

将设置回归到安装初始化状态

upload-many-files-reset

对接收上传文件的接口要求,返回如下数据为上传成功:

{
  "data": {
    "success": true
  }
}
// '{"data": {"success": true}}'

由于使用了 chalk 和 cli-spinner,在 Windows 的 cmd 下部分日志无法输出,建议使用自带的 PowerShell。

辅助源码阅读 与 二次开发相关

支持两种模式:

  • 参数形式: upload-many-files init --server-url http://xx.xx.xx --folder-path /home/user/xxx --extname .jpeg,.png
  • 多命令形式: upload-many-files-init --server-url http://xx.xx.xx --folder-path /home/user/xxx --extname .jpeg,.png

参数形式采用了管道模型来做控制,将判断逻辑放在了子模块中,便于加工和处理,

// index.js
// 配置初始化
setConfig.pipe(program);
// 开始上传
startUpload.pipe(program);

多命令模式在 package.json 的 bin 中配置每一个子命令,直接指向 bin 目录对应的文件。

"bin": {
  "upload-many-files": "bin/index.js",
  "upload-many-files-init": "bin/init.js",
  "upload-many-files-start": "bin/start.js",
  "upload-many-files-reset": "bin/reset.js",
  "upload-many-files-get-init-config": "bin/get-init-config.js"
}

每次上传一个文件,每一个上传任务定义为一个 job,每 1000 个上传任务定义为一个上传组(最后剩余不足 1000 的组成一组),上传组对应的文件为 jobs-n.json。

上传的流程大体是:

    1. 根据初始化设置的文件夹路径和后缀名,扫描要上传的文件;
    1. 每 1000 个文件生成一个上传组文件,记录文件路径和上传情况,内容结构如下:
[
  {
    "path": "/home/user/xxx/t1/1.jpeg",
    "isUploaded": false
  }
  ...
]
    1. 扫描完成后,上传任务还会生成一个主文件,内容结构如下:
{
  "status": 1,
  // 上传已完成的上传组编号,从 0 开始
  "uploadedGroupIndex": 0,
  // 上传任务数(每个上传任务对应一个文件)
  "jobsTotal": 288,
  // 扫描过的文件
  "filesTotal": 289,
  "currentJobsList": []
}
    1. 开始上传,内存中最多常驻 10 个异步任务,每成功一个任务从总任务中提取一个加入,直到全部上传完成。
    1. 在 jobs-n.json 中记录文件上传的成功与失败,方便中断后续传。

在二次开发中,你可能需要按自己的业务逻辑来定义上传成功和失败的逻辑,这个逻辑在 lib/start.js 的 postFile 方法中指定,例如:

async function postFile(index, end) {
    ...
    request.post({
        url: config.serverUrl,
        formData
    }, async (error, res, body) => {
        // 如果有一些自定义的业务定义,可以在这里处理,比如下面就是自定义失败的处理
        let isSuccess = false;
        if (res.statusCode === 200 && body[0] === '{') {
            body = JSON.parse(body);
            isSuccess = body.data && body.data.success;
        }
        if (!error && res.statusCode === 200 && isSuccess) {
            ...
        }
    });
}

编外

还有另一个思路,就是先直接上传,失败的放在另一个地方存储,等全部上传一遍之后再上传之前失败的文件。这种思路和当前实现互有优劣,这种思路的优点有两个:

一、不需要等一个任务组结束后再开始下一个,理论上会快一些;

二、不会因为一个文件多次重试上传失败而影响后面的上传。

那为什么没有采用这种思路呢?

原因有点俗套 -- 得不偿失。针对第一条速度而言,每个任务组有 1000 条任务 10 个异步进程,两个任务组之间的“阻塞衔接” 和 “非阻塞衔接”在速度上只相差千分之几,但代价是需要更复杂的数据结构来区分两个任务组,如果考虑有些任务横跨 3 个以上任务组,那需要考虑的逻辑就更多了,在工程上将问题“扼杀在摇篮中”是比“遗祸后人”更好的一种实现,代码是给人读的只是偶尔让计算机执行一下。对于第二条多次上传失败的情况,在实际操作中多数是网络抖动或者后端不堪重负才失败的,前面大规模失败如果无节制的继续发送请求会引发更大规模的失败,相反将重试和请求控制在一个小范围内是成功率更高的一种方案。