ChatGPT解决这个技术问题 Extra ChatGPT

Node.js 检查路径是文件还是目录

我似乎无法获得任何解释如何执行此操作的搜索结果。

我想要做的就是能够知道给定路径是文件还是目录(文件夹)。

请注意,还有符号链接,可以链接到文件、链接到目录或被破坏。除了文件、目录和符号链接之外,还有其他类型的路径。因此,您必须注意不要只检查“目录”并假设其他所有内容都是“文件”等。并且您必须考虑是否希望透明地遵循符号链接。一个问题是 scandir() 返回的 Direntstat() 返回的 Stat 都具有 isFile()isDirectory() 方法,但前者不遵循符号链接,而后者则遵循。

Z
Zade Viggers

下面应该告诉你。从 docs

fs.lstatSync(path_string).isDirectory() 

从 fs.stat() 和 fs.lstat() 返回的对象属于这种类型。 stats.isFile() stats.isDirectory() stats.isBlockDevice() stats.isCharacterDevice() stats.isSymbolicLink() // (只对fs.lstat()有效) stats.isFIFO() stats.isSocket()

笔记:

上述解决方案throw一个Error如果;例如,filedirectory 不存在。

如果您想要 truefalse 方法,请尝试 Joseph 在下面的评论中提到的 fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory();


请注意,如果您关心一般应用程序性能,异步版本通常更可取。
请记住,如果目录或文件不存在,那么您将收到错误消息。
let isDirExists = fs.existsSync(dirPath) && fs.lstatSync(dirPath).isDirectory();
我觉得奇怪的是,当他们第一次制作 lstat 时,他们并没有在其中包含一个 exists() 函数?我想这就是为什么 node_modules 比黑洞更深的原因。
为什么每个人都使用 fs.lstat()?文档说它始终是 false:“如果 <fs.Stats> 对象是从 fs.lstat() 获得的,则此方法 [<fs.Stats>.isDirectory()] 将始终返回 false。这是因为 fs.lstat() 返回有关符号的信息链接本身,而不是它解析到的路径。”
M
Marcos Casagrande

更新:Node.Js >= 10

我们可以使用新的 fs.promises API

const fs = require('fs').promises;

(async() => {
    const stat = await fs.lstat('test.txt');
    console.log(stat.isFile());
})().catch(console.error)

任何 Node.Js 版本

以下是检测路径是异步的文件还是目录的方法,这是 node.js 中推荐的方法。使用 fs.lstat

const fs = require("fs");

let path = "/path/to/something";

fs.lstat(path, (err, stats) => {

    if(err)
        return console.log(err); //Handle error

    console.log(`Is file: ${stats.isFile()}`);
    console.log(`Is directory: ${stats.isDirectory()}`);
    console.log(`Is symbolic link: ${stats.isSymbolicLink()}`);
    console.log(`Is FIFO: ${stats.isFIFO()}`);
    console.log(`Is socket: ${stats.isSocket()}`);
    console.log(`Is character device: ${stats.isCharacterDevice()}`);
    console.log(`Is block device: ${stats.isBlockDevice()}`);
});

使用同步 API 时注意:

使用同步形式时,会立即抛出任何异常。您可以使用 try/catch 来处理异常或允许它们冒泡。

try{
     fs.lstatSync("/some/path").isDirectory()
}catch(e){
   // Handle error
   if(e.code == 'ENOENT'){
     //no such file or directory
     //do something
   }else {
     //do something else
   }
}

截至 2020 年 3 月,这仍然被认为是实验性的吗?我们在哪里可以看到? -- 糟糕,当我单击上面的链接时,我看到它现在已经稳定(这意味着不再是实验性的)。
H
Hubro

说真的,问题存在五年而没有漂亮的外观?

function isDir(path) {
    try {
        var stat = fs.lstatSync(path);
        return stat.isDirectory();
    } catch (e) {
        // lstatSync throws an error if path doesn't exist
        return false;
    }
}

[Error: EACCES: permission denied, scandir '/tmp/snap.skype'] 当我提供 /tmp/ 时,它是一个目录且可访问。
@MarinosAn我假设您没有该文件的读取权限,因此它失败了。
c
cndw

根据您的需要,您可能可以依赖节点的 path 模块。

您可能无法访问文件系统(例如,尚未创建文件)并且您可能希望避免访问文件系统,除非您确实需要额外的验证。如果您可以假设要检查的内容遵循 .<extname> 格式,只需查看名称即可。

显然,如果您正在寻找一个没有 extname 的文件,您需要点击文件系统来确定。但保持简单,直到你需要更复杂。

const path = require('path');

function isFile(pathItem) {
  return !!path.extname(pathItem);
}

显然,这并非在所有情况下都有效,但如果您可以做出所需的假设,它比其他答案更快、更容易。
目录可以命名为 folder.txt,这表示它是一个文件,或者该文件可以是 LICENSE,没有扩展
Z
Zdenek F

如果您在遍历目录时需要它1

从 Node 10.10+ 开始,fs.readdir 具有 withFileTypes 选项,使其返回目录条目 fs.Dirent 而不仅仅是文件名。目录条目包含其 name 和有用的方法,例如 isDirectoryisFile,因此您无需显式调用 fs.lstat

你可以像这样使用它:

import { promises as fs } from 'fs';

// ./my-dir has two subdirectories: dir-a, and dir-b
const dirEntries = await fs.readdir('./my-dir', { withFileTypes: true });

// let's filter all directories in ./my-dir
const onlyDirs = dirEntries.filter(de => de.isDirectory()).map(de => de.name);
// onlyDirs is now [ 'dir-a', 'dir-b' ]

1)因为这就是我发现这个问题的方式。


v
vdegenne

这是我使用的一个功能。没有人在这篇文章中使用 promisifyawait/async 功能,所以我想我会分享。

const promisify = require('util').promisify;
const lstat = promisify(require('fs').lstat);

async function isDirectory (path) {
  try {
    return (await lstat(path)).isDirectory();
  }
  catch (e) {
    return false;
  }
}

注意:我不使用require('fs').promises;,因为它已经实验了一年,最好不要依赖它。


T
TamusJRoyce

上面的答案检查文件系统是否包含文件或目录的路径。但它并不能确定给定路径本身是文件还是目录。

答案是使用“/”来识别基于目录的路径。比如 --> "/c/dos/run/." <-- 尾随期间。

就像尚未写入的目录或文件的路径。或者来自不同计算机的路径。或同时存在同名文件和目录的路径。

// /tmp/
// |- dozen.path
// |- dozen.path/.
//    |- eggs.txt
//
// "/tmp/dozen.path" !== "/tmp/dozen.path/"
//
// Very few fs allow this. But still. Don't trust the filesystem alone!

// Converts the non-standard "path-ends-in-slash" to the standard "path-is-identified-by current "." or previous ".." directory symbol.
function tryGetPath(pathItem) {
    const isPosix = pathItem.includes("/");
    if ((isPosix && pathItem.endsWith("/")) ||
        (!isPosix && pathItem.endsWith("\\"))) {
        pathItem = pathItem + ".";
    }
    return pathItem;
}
// If a path ends with a current directory identifier, it is a path! /c/dos/run/. and c:\dos\run\.
function isDirectory(pathItem) {
    const isPosix = pathItem.includes("/");
    if (pathItem === "." || pathItem ==- "..") {
        pathItem = (isPosix ? "./" : ".\\") + pathItem;
    }
    return (isPosix ? pathItem.endsWith("/.") || pathItem.endsWith("/..") : pathItem.endsWith("\\.") || pathItem.endsWith("\\.."));
} 
// If a path is not a directory, and it isn't empty, it must be a file
function isFile(pathItem) {
    if (pathItem === "") {
        return false;
    }
    return !isDirectory(pathItem);
}

节点版本:v11.10.0 - 2019 年 2 月

最后的想法:为什么还要访问文件系统?


如果文件夹名称的末尾有一个点,例如 .git 甚至 myFolder.txt,该怎么办?
您必须了解 posix 文件路径约定(由于 Windows 在内核级别兼容 posix,因此 Windows 部分遵守了哪些约定)。请阅读stackoverflow.com/questions/980255/…en.wikipedia.org/wiki/…
我真的没有回答这个吗? .git 和 myFolder.txt 可以是文件夹或文件。你不知道,直到你检查。由于文件夹也被视为文件,因此您不能拥有同名的文件夹和文件。 .git/.和 myFolder.txt/。都是文件夹。 .git/ 和 myFolder.txt/ 是该文件夹中的所有文件。 man readline 记录了这个(模糊地)。孤独的。很特别。包含 .不是。
.和 .. 都很特别
P
Pierrelasse

我可以使用以下方法检查目录或文件是否存在:

// This returns if the file is not a directory.
if(fs.lstatSync(dir).isDirectory() == false) return;

// This returns if the folder is not a file.
if(fs.lstatSync(dir).isFile() == false) return;