JavaScript File对象的type属性 js file对象 文件路径_js 读取文件


背景

在写 Node.js 时,会遇到一个关于文件路径大小写的问题,就是当我们在调用 fs.existsfs.readFilerequire 等读取文件的 API 时,会发现即使大小写没有写对,你也能正常读取到这个文件。

这种情况在某些情况下可能会出现一些问题,比如说我们将一个文件夹构建成一个文件树大对象,比如这样:


// 文件树
[{
  name: 'src',
  children: [
    { name: 'fooBar.js' }
  ]
}]


这时候,'fooBar.js' 是一个字符串的形态存在,当我们要做对比的时候,会发现对比是失败的,比如:


fileTree[0].children.find(name => name === 'foobar.js') // => undefined


但是如果我们读取这个文件,却有可能会读取成功:


require('src/foobar.js') // 有可能会读取成功


原因

之所以会这样,其实是因为操作系统——或者说是文件系统——的限制不一样,像 macOS(BSD UNIX)、Windows 等操作系统,其文件系统默认都是大小写不敏感的;而像其它一些 Linux 系统(包括 Android 系统),则是大小写敏感的。

所以此问题其实不仅存在于 Node.js,大家用 Git 可能也会遇到同样的问题,我听说 Android 的程序员还会在 macOS 上分个大小写敏感的磁盘分区。

解决方案

那这样的问题如何解决呢?我们要根据业务需求的不同,来进行不同的策略。具体来说要考虑以下这两点:

  • 程序会在哪些系统上运行?
  • 是否要对文件名进行比对?

只在大小写敏感系统上只在大小写不敏感系统上运行,且无需对文件名进行比对的情况下,无需做特殊处理。否则,建议通过约定禁止大小写不敏感的代码写法。比如可以通过代码静态分析,在 push 代码前做校验。

如果希望尊重文件系统的设计,可以通过特性检测的方法来做。在读取文件时,直接沿用文件系统 API(如 Node.js 的 fs 模块、require 方法等),这个特性检测我没找到 API,可以通过这样的小技巧来检测:在程序里 require 一个 明显写错大小写的文件,看看能不能正常加载。

代码示例:


export default function checkCaseSensitive (): boolean {
  try {
    require('/path/to/file');
    delete require.cache['/path/to/file']
    return false;
  } catch () {
    return true;
  }
}


当然也可以缓存一下结果:


export const isCaseSensitive = checkCaseSensitive();


那么,当我们要使用时,就可以根据不同的文件系统特性,而进行不同的对比逻辑,比如这样:


import { isCaseSensitive } from './checkCaseSensitive'

export default function foo (fileTree) {
  return fileTree[0].children.find(name => 
    isCaseSensitive 
    ? name === target
    : name.toLowerCase() === target.toLowerCase()
  );
}