@danieldietrich/copy

中文文档
0.4.2发布于 2019/12/26MITTypeScriptCommonJS零依赖近 30 天下载 11.5万

简单而强大的复制工具 .

中文使用文档
文档目录9 节
  1. 安装
  2. 使用量
  3. 实例
  4. 使用复制操作
  5. 更改文件属性
  6. 执行进展指标
  7. API 密码
  8. 选项
  9. 选项优先

npm versionvulnerabilitiesminzipped size   buildcoverage   Platform   Sponsordonatelicense   Follow

复制

简单而强大的复制工具 .

复制工具递归复制文件,目录,以及从源目录到目的目录的链接.

特征 :

  • 重命名和移动文件和目录
  • 过滤路径
  • 文件内容的转换
  • 在每个路径复制后执行动作
  • 保留用户权限
  • 覆盖或保存已存在文件
  • 创建或调试链接
  • 保留原始时间戳
  • 收集结果( 目录、文件和链接的大小和数量)
  • 不写入文件进行干线运行
  • 可用作 fs-extra/拷贝,参见 选项

复制工具故意没有

  • 提供同步 API
  • 检查周期, 即如果目的地是源的子目录
  • 提供基于流和块的变换 API
  • 保存链接的时间戳( 因为节点不为此提供OS 独立的 API)
  • 如果源和(或)目的地被重新命名或移动,则重写符号链接的相对链接

安装

npm i @danieldietrich/copy

使用量

该模块支持ES6 导入 和通用JS系统 需求 样式.

import copy from '@danieldietrich/copy';

(async function() {

    // Performs a dry run of copying ./node_modules to ./temp
    const totals = await copy('node_modules', 'temp', { dryRun: true });

    console.log('Totals:', totals);

})();

共计 包含复制操作信息 :

{
    directories: 1338,
    files: 7929,
    symlinks: 48,
    size: 87873775
}

这个 编号 目录、文件和同义链接对应源。 这个 大小 反映写入字节的数目。 特别是,如果现有文件没有被删除,其大小可能小于来源.

实例

使用复制操作

另见 选项优先。 。 。 .

const copy = require('@danieldietrich/copy');
const path = require('path');

(async function() {

    // move dist/ dir contents to parent dir and rename index.js files to index.mjs
    const rename = (source, target) => {
        if (source.stats.isDirectory() && source.path.endsWith('/dist')) {
            return path.dirname(target.path);
        } else if (source.stats.isFile() && source.path.endsWith('/index.js')) {
            return path.join(path.dirname(target.path), 'index.mjs');
        } else {
            return;
        }
    };

    // recursively copy all .js files
    const filter = (source, target) =>
        source.stats.isDirectory() || source.stats.isFile() && source.path.endsWith('.js');

    // transform the contents of all index.mjs files to upper case
    const transform = (data, source, target) => {
        if (source.stats.isFile() && target.path.endsWith('/index.mjs')) {
            return Buffer.from(data.toString('utf8').toUpperCase(), 'utf8');
        } else {
            return data;
        }
    };

    // log some information about copied files
    const afterEach = (source, target, options) => {
        const dryRun = options.dryRun ? '[DRY RUN] ' : '';
        if (source.stats.isDirectory()) {
            console.log(`${dryRun}Created ${target.path}`);
        } else {
            // target.stats is undefined on a dry run if the target does not already exist!
            const size = target.stats?.size || '?';
            console.log(`${dryRun}Copied ${source.path} to ${target.path} (${size} bytes)`);
        }
    };

    const totals = await copy('node_modules', 'temp', {
        rename,
        filter,
        transform,
        afterEach
    });

    console.log('Totals:', totals);

})();

更改文件属性

在下面的例子中,我们更改文件所有者 uid 。 chgrp或chmod可能以类似方式进行.

import * as copy from '@danieldietrich/copy';
import * as fs from 'fs';

const { lchown } = fs.promises;

async function changeOwner(src: string, dst: string, uid: number) {
    copy(src, dst, {
        afterEach: async (source, target) => {
            lchown(target.path, uid, source.stats.gid);
        }
    });
}

执行进展指标

import * as copy from '@danieldietrich/copy';

async function copyWithProgress(src: string, dst: string, callback: (curr: copy.Totals, sum: copy.Totals) => void) {
    const curr: copy.Totals = {
        directories: 0,
        files: 0,
        symlinks: 0,
        size: 0
    };
    const sum = await copy(src, dst, { dryRun: true });
    const interval = 100; // ms
    let update = Date.now();
    await copy(src, dst, { afterEach: (source) => {
        if (source.stats.isDirectory()) {
            curr.directories += 1;
        } else if (source.stats.isFile()) {
            curr.files += 1;
            curr.size += source.stats.size;
        } else if (source.stats.isSymbolicLink()) {
            curr.symlinks += 1;
            curr.size += source.stats.size;
        }
        if (Date.now() - update >= interval) {
            update = Date.now();
            callback(curr, sum);
        }
    }});
    callback(sum, sum);
}

// usage
(async function() {
    copyWithProgress('node_modules', 'temp', (curr, sum) => {
        const progress = Math.min(100, Math.floor(curr.size / sum.size * 100));
        console.log(`${Number.parseFloat(progress).toFixed(1)} %`);
    });
})();

API 密码

普遍签署: 复制 为:

async function copy(sourcePath: string, targetPath: string, options?: copy.Options): Promise<copy.Totals>;

公共类型有:

// compatible to fs-extra.copy
type Options = {
    overwrite?: boolean;
    errorOnExist?: boolean;
    dereference?: boolean;
    preserveTimestamps?: boolean;
    dryRun?: boolean;
    rename?: (source: Source, target: Target, options: Options) => string | void | Promise<string | void>;
    filter?: (source: Source, target: Target, options: Options) => boolean | Promise<boolean>;
    transform?: (data: Buffer, source: Source, target: Target, options: Options) => Buffer | Promise<Buffer>;
    afterEach?: (source: Source, target: Target, options: Options) => void | Promise<void>;
};

type Source = {
    path: string;
    stats: fs.Stats;
};

type Target = {
    path: string;
    stats?: fs.Stats;
};

type Totals = {
    directories: number;
    files: number;
    symlinks: number;
    size: number; // not size on disk in blocks
};

选项

复制是Fs-extra/复制的超级集. 选项名称和默认值对应fs-extra/复制选项.

选项说明
覆盖设置到时保存扩展文件 虚假默认 : 真实
存在时出错与 覆盖: 假默认 : 虚假
调试复制文件,如果 真实默认 : 虚假
保存时间戳保留了原来的时间戳. 默认 : 虚假
干流页:1不执行任何写操作. 之后的每个 被调用,需要检查 选项. dryRun默认 : 虚假
重命名页:1可选重命名函数 。 目标路径在返回非空时重新命名 字符串,否则取出原名。 当将目录移动到不同的位置时,内部可能会使用递归式mkdir. 在这种情况下,至少是节点 第10.12条 需要时间.
过滤器可选路径过滤器 。 返回时排除路径 虚假 并列入 真实。 。 。 .
转换页:1文件内容的可选转换 .
之后的每个页:1在路径被复制后执行的可选动作,甚至在干线上进行. 请检查 选项. dryRun 和/或如果 目标. 数据 定义.

*) fs-extra没有这个特性

选项优先

  1. 首先,目标路径通过调用 重命名 函数,如果存在。 请注意,当前的目标路径被传递到函数上.
  2. 然后选择权 过滤器 函数被应用。 因为我们在目标被重新命名后就这样做了,所以我们能够考虑到现有目标的内容.
  3. 接下来,可选 转换 函数调用.
  4. 目标写完后,可选 之后的每个 函数调用.

版权:2020年 丹尼尔·迪特里希。释放 麻省理工学院 执照.

版本与发布记录

@danieldietrich/copy 共发布 16 个版本,首次发布于 2019/09/20;过去 12 个月发布了 0 个版本。

版本发布日期距今
0.4.2latest2019/12/266 年前
0.4.12019/12/266 年前
2.0.02019/12/256 年前
1.0.02019/12/256 年前
0.4.02019/12/256 年前
0.3.22019/12/246 年前

关于 @danieldietrich/copy 的常见问题

@danieldietrich/copy 是什么?

简单而强大的复制工具 .

如何安装 @danieldietrich/copy?

在项目目录运行 npm install @danieldietrich/copy,或使用 pnpm add / yarn add / bun add。

@danieldietrich/copy 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@danieldietrich/copy 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@danieldietrich/copy 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=10.12.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@danieldietrich/copy 可以商用吗?

@danieldietrich/copy 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@danieldietrich/copy 的下载量有多少?

根据 npm 官方下载统计,@danieldietrich/copy 在 2026/10/11 – 2026/11/09 这 30 天内被下载 115,068 次,日均约 3,836 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@danieldietrich/copy 还在维护吗?

最新版本 0.4.2 发布于 2019/12/26(6 年前);至今共发布 16 个版本,其中过去 12 个月发布了 0 个;首次发布于 2019/09/20。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。