Skip to content

Instantly share code, notes, and snippets.

@nuintun
Created April 6, 2024 13:09
Show Gist options
  • Save nuintun/18fc891cb4a52dac3f46be1cd16fcb2d to your computer and use it in GitHub Desktop.
Save nuintun/18fc891cb4a52dac3f46be1cd16fcb2d to your computer and use it in GitHub Desktop.
获取指定目录及其子目录下的所有文件,符号链接除外。
/**
* @module getFiles
*/
import { Dirent } from 'fs';
import { join, resolve } from 'path';
import { readdir } from 'fs/promises';
type Waiting = [
// Current dirname
dirname: string,
// Current iterator
iterator: IterableIterator<Dirent>
];
function normalize(path: string): string {
return path.replace(/\\+/g, '/');
}
async function read(path: string): Promise<IterableIterator<Dirent>> {
const entries = await readdir(path, {
withFileTypes: true
});
return entries.values();
}
export async function getFiles(root: string): Promise<string[]> {
root = resolve(root);
const files: string[] = [];
const waiting: Waiting[] = [];
let current: Waiting | undefined = ['', await read(root)];
while (current) {
const [, iterator] = current;
const item = iterator.next();
if (item.done) {
current = waiting.pop();
} else {
const [dirname] = current;
const { value: stat } = item;
const path = join(dirname, stat.name);
if (stat.isFile()) {
files.push(normalize(path));
} else if (stat.isDirectory()) {
const realpath = join(root, path);
waiting.push([path, await read(realpath)]);
}
}
}
return files;
}
@nuintun
Copy link
Author

nuintun commented Apr 7, 2024

推荐 AsyncGenerator 方式

/**
 * @module getFiles
 */

import { Dirent } from 'fs';
import { join, resolve } from 'path';
import { readdir } from 'fs/promises';

type Waiting = [
  // Current dirname
  dirname: string,
  // Current iterator
  iterator: IterableIterator<Dirent>
];

function normalize(path: string): string {
  return path.replace(/\\+/g, '/');
}

async function read(path: string): Promise<IterableIterator<Dirent>> {
  const entries = await readdir(path, {
    withFileTypes: true
  });

  return entries.values();
}

export async function* getFiles(root: string): AsyncGenerator<string> {
  root = resolve(root);

  const waiting: Waiting[] = [];

  let current: Waiting | undefined = ['', await read(root)];

  while (current) {
    const [, iterator] = current;
    const item = iterator.next();

    if (item.done) {
      current = waiting.pop();
    } else {
      const [dirname] = current;
      const { value: stat } = item;
      const path = join(dirname, stat.name);

      if (stat.isFile()) {
        yield normalize(path);
      } else if (stat.isDirectory()) {
        const realpath = join(root, path);

        waiting.push([path, await read(realpath)]);
      }
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment