简体   繁体   English

Node.js archiver 需要通过 glob 排除文件类型的语法

[英]Node.js archiver Need syntax for excluding file types via glob

Using archiver.js (for Node.js), I need to exclude images from a recursive (multi-subdir) archive.使用 archiver.js(对于 Node.js),我需要从递归(多子目录)存档中排除图像。 Here is my code:这是我的代码:

const zip = archiver('zip', { zlib: { level: 9 } });
const output = await fs.createWriteStream(`backup/${fileName}.zip`);
res.setHeader('Content-disposition', `attachment; filename=${fileName}.zip`);
res.setHeader('Content-type', 'application/download');
output.on('close', function () {
  res.download(`backup/${fileName}.zip`, `${fileName}.zip`);
});
output.on('end', function () {
  res.download(`backup/${fileName}.zip`, `${fileName}.zip`);
});
zip.pipe(output);
zip.glob('**/*',
  {
    cwd: 'user_uploads',
    ignore: ['*.jpg', '*.png', '*.webp', '*.bmp'],
  },
  {});
zip.finalize();

The problem is that it did not exclude the ignore files.问题是它没有排除忽略文件。 How can I correct the syntax?如何更正语法?

Archiver uses Readdir-Glob for globbing which uses minimatch to match. Archiver使用Readdir-Glob进行通配,使用minimatch进行匹配。

The matching in Readdir-Glob ( node-readdir-glob/index.js#L147 ) is done against the full filename including the pathname and it does not allow us to apply the option matchBase which will much just the basename of the full path. Readdir-Glob ( node-readdir-glob/index.js#L147 ) 中的匹配是针对包括路径名在内的完整文件名完成的,它不允许我们应用选项matchBase ,它只会是完整路径的基本名称。

In order for to make it work you have 2 options:为了让它工作,你有两个选择:


1. Make your glob to exclude the file extensions 1. 让你的 glob 排除文件扩展名

You can just convert your glob expression to exclude all the file extensions you don't want to be in your archive file using the glob negation .(...) and it will include everything except what matches the negation expression:您可以使用 glob 否定.(...)转换您的 glob 表达式以排除您不想在存档文件中出现的所有文件扩展名,它将包括除匹配否定表达式之外的所有内容:

zip.glob(
  '**/!(*.jpg|*.png|*.webp|*.bmp)',
  {
    cwd: 'user_uploads',
  },
  {}
);

2. Make minimatch to work with full file pathname 2.使最小匹配与完整文件路径名一起使用

To make minimatch to work without us being able to set the matchBase option, we have to include the matching directory glob for it to work:为了使minimatch在我们无法设置matchBase选项的情况下工作,我们必须包含匹配的目录 glob 才能工作:

zip.glob(
  '**/*',
  {
    cwd: 'user_uploads',
    ignore: ['**/*.jpg', '**/*.png', '**/*.webp', '**/*.bmp'],
  },
  {}
);

Behaviour行为

This behaviour of Readdir-Glob is a bit confusing regarding the ignore option:关于ignore选项, Readdir-Glob的这种行为有点令人困惑:

Options选项

ignore : Glob pattern or Array of Glob patterns to exclude matches. ignore :要排除匹配项的 Glob 模式或 Glob 模式数组。 If a file or a folder matches at least one of the provided patterns, it's not returned.如果文件或文件夹至少与提供的模式之一匹配,则不会返回。 It doesn't prevent files from folder content to be returned.它不会阻止返回文件夹内容中的文件。

This means that igrore items have to be actual glob expressions that must include the whole path/file expression.这意味着igrore必须是实际的 glob 表达式,必须包含整个路径/文件表达式。 When we specify *.jpg , it will match files only in the root directory and not the subdirectories .当我们指定*.jpg时,它将只匹配根目录中的文件,而不匹配子目录中的文件。 If we want to exclude JPG files deep into the directory tree, we have to do it using the include all directories pattern in addition with the file extension pattern which is **/*.jpg .如果我们想将 JPG 文件排除在目录树的深处,我们必须使用包括所有目录模式以及文件扩展名模式**/*.jpg来做到这一点。

Exclude only in subdirectories仅在子目录中排除

If you want to exclude some file extensions only inside specific subdirectories, you can add the subdirectory into the path with a negation pattern like this:如果你只想排除特定子目录中的某些文件扩展名,你可以将子目录添加到具有否定模式的路径中,如下所示:

// The glob pattern '**/!(Subdir)/*.jpg' will exclude all JPG files,
// that are inside any 'Subdir/' subdirectory.

zip.glob(
  '**/*',
  {
    cwd: 'user_uploads',
    ignore: ['**/!(Subdir)/*.jpg'],
  },
  {}
);

The following code is working with this directory structure:以下代码使用此目录结构:

node-app
    |
    |_ upload
         |_subdir1
         |_subdir2
         |_...

In the code __dirname is the node-app directory ( node-app is the directory where your app resides).在代码中, __dirnamenode-app目录( node-app是您的应用程序所在的目录)。 The code is an adaptation of the code on https://www.archiverjs.com/ in paragraph Quick Start该代码改编自https://www.archiverjs.com/快速入门段落中的代码

// require modules
const fs = require('fs');
const archiver = require('archiver');

// create a file to stream archive data to.
const output = fs.createWriteStream(__dirname + '/example.zip');
const archive = archiver('zip', {
  zlib: { level: 9 } // Sets the compression level.
});

// listen for all archive data to be written
// 'close' event is fired only when a file descriptor is involved
output.on('close', function() {
  console.log(archive.pointer() + ' total bytes');
  console.log('archiver has been finalized and the output file descriptor has closed.');
});

// This event is fired when the data source is drained no matter what was the data source.
// It is not part of this library but rather from the NodeJS Stream API.
// @see: https://nodejs.org/api/stream.html#stream_event_end
output.on('end', function() {
  console.log('Data has been drained');
});

// good practice to catch warnings (ie stat failures and other non-blocking errors)
archive.on('warning', function(err) {
  if (err.code === 'ENOENT') {
    // log warning
  } else {
    // throw error
    throw err;
  }
});

// good practice to catch this error explicitly
archive.on('error', function(err) {
  throw err;
});

// pipe archive data to the file
archive.pipe(output);

    
archive.glob('**', 
             {
                cwd: __dirname + '/upload',
                ignore: ['*.png','*.jpg']}
);

// finalize the archive (ie we are done appending files but streams have to finish yet)
// 'close', 'end' or 'finish' may be fired right after calling this method so register to them beforehand
archive.finalize();

glob is an abbreviation for 'global' so you use wildcards like * in the filenames ( https://en.wikipedia.org/wiki/Glob_(programming) ). glob是“global”的缩写,因此您可以在文件名中使用*等通配符 ( https://en.wikipedia.org/wiki/Glob_(programming) )。 So one possible accurate wildcard expression is *.jpg , *.png ,... depending on the file type you want to exclude.因此,一种可能的准确通配符表达式是*.jpg*.png ……,具体取决于您要排除的文件类型。 In general the asterisk wildcard * replaces an arbitrary number of literal characters or an empty string in in the context of file systems ( file and directory names, https://en.wikipedia.org/wiki/Wildcard_character )通常,星号通配符 * 在文件系统上下文中替换任意数量的文字字符或空字符串(文件和目录名称, https://en.wikipedia.org/wiki/Wildcard_character

See also node.js - Archiving folder using archiver generate an empty zip另请参阅node.js - 使用归档程序的归档文件夹生成一个空的 zip

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM