如何在Windows上的Node.js中获取文件的大小写确切路径?

时间:2015-10-12 17:32:25

标签: node.js windows macos path case-sensitive

我有一条路径,让我们说C:\temp\something.js我希望在Windows上获得路径的大小写确切版本 - 所以如果磁盘上存有C:\Temp\someThing.js,我希望得到这个值(路径)。

如何从前一个路径中获取Node.js中的后一个路径?

我已经通过了FS API(https://nodejs.org/api/fs.html)并且我没有找到任何有用的内容(即fs.realpathSyncfs.statSyncfs.accessSync没有返回我需要的内容)

3 个答案:

答案 0 :(得分:12)

使用case -Insensitive文件系统(Windows,macOS)的平台令人惊讶地难以获得给定的,可能是case-variant路径的 case-exact 形式 - 似乎没有系统 API,因此Node.js(或Python,Perl,...)等环境不应受到责备。

更新@barsh非常适合package以下代码用于npm,因此您可以轻松安装 npm install true-case-path 即可。 功能

glob npm package及其nocase选项可以解决这个问题(虽然它需要在Windows上进行一些调整);基本上,将输入路径视为glob - 即使它是 literal 路径 - 使glob()返回存储在文件系统中的真实案例:

  • 在项目文件夹中安装包glob npm install glob (根据需要添加--save--save-dev)。

  • 使用下面的 trueCasePathSync()功能;查看有关使用和限制的评论;值得注意的是,虽然输入路径也已标准化,但 ..开头的路径 不支持,因为path.normalize()无法解析它们相对到目前的目录。

    • 注意trueCasePathSync() 返回规范路径:如果传入相对路径,则会获得相对输出路径好吧,并没有解决任何符号链接。如果您需要规范路径,请将fs.realPathSync()应用于结果。
  • 应该在 Windows,macOS和Linux 上工作(虽然对区分大小写的文件系统的用处有限),使用Node.js v4.1.1测试

    • 注意:在Windows上,没有尝试对路径的驱动器号或UNC共享组件(服务器名称,共享名称)进行大小写更正。< / LI>
/*
SYNOPSIS
  trueCasePathSync(<fileSystemPath>)
DESCRIPTION
  Given a possibly case-variant version of an existing filesystem path, returns
  the case-exact, normalized version as stored in the filesystem.
  Note: If the input path is a globbing *pattern* as defined by the 'glob' npm
        package (see prerequisites below), only the 1st match, if any,
        is returned.
        Only a literal input path guarantees an unambiguous result.
  If no matching path exists, undefined is returned.
  On case-SENSITIVE filesystems, a match will also be found, but if case
  variations of a given path exist, it is undefined which match is returned.
PLATFORMS
    Windows, OSX, and Linux (though note the limitations with case-insensitive
    filesystems).
LIMITATIONS
  - Paths starting with './' are acceptable, but paths starting with '../'
    are not - when in doubt, resolve with fs.realPathSync() first.
    An initial '.' and *interior* '..' instances are normalized, but a relative
    input path still results in a relative output path. If you want to ensure
    an absolute output path, apply fs.realPathSync() to the result.
  - On Windows, no attempt is made to case-correct the drive letter or UNC-share
    component of the path.
  - Unicode support:
    - Be sure to use UTF8 source-code files (with a BOM on Windows)
    - On OSX, the input path is automatically converted to NFD Unicode form
      to match how the filesystem stores names, but note that the result will
      invariably be NFD too (which makes no difference for ASCII-characters-only
      names).
PREREQUISITES
  npm install glob    # see https://www.npmjs.com/search?q=glob
EXAMPLES
  trueCasePathSync('/users/guest') // OSX: -> '/Users/Guest'
  trueCasePathSync('c:\\users\\all users') // Windows: -> 'c:\Users\All Users'
*/
function trueCasePathSync(fsPath) {

  var glob = require('glob')
  var path = require('path')

  // Normalize the path so as to resolve . and .. components.
  // !! As of Node v4.1.1, a path starting with ../ is NOT resolved relative
  // !! to the current dir, and glob.sync() below then fails.
  // !! When in doubt, resolve with fs.realPathSync() *beforehand*.
  var fsPathNormalized = path.normalize(fsPath)

  // OSX: HFS+ stores filenames in NFD (decomposed normal form) Unicode format,
  // so we must ensure that the input path is in that format first.
  if (process.platform === 'darwin') fsPathNormalized = fsPathNormalized.normalize('NFD')

  // !! Windows: Curiously, the drive component mustn't be part of a glob,
  // !! otherwise glob.sync() will invariably match nothing.
  // !! Thus, we remove the drive component and instead pass it in as the 'cwd' 
  // !! (working dir.) property below.
  var pathRoot = path.parse(fsPathNormalized).root
  var noDrivePath = fsPathNormalized.slice(Math.max(pathRoot.length - 1, 0))

  // Perform case-insensitive globbing (on Windows, relative to the drive / 
  // network share) and return the 1st match, if any.
  // Fortunately, glob() with nocase case-corrects the input even if it is 
  // a *literal* path.
  return glob.sync(noDrivePath, { nocase: true, cwd: pathRoot })[0]
}

答案 1 :(得分:1)

我相信唯一的方法是遍历父目录中的文件,然后找到将匹配的文件。下面提供了不区分大小写的系统的示例实现。

如果文件系统不区分大小写,则在同一文件夹中不能有两个文件以小写字母共享相同的名称。下面的实现利用了这一点。

/**
 * @param {string} filePath
 * @returns {string|undefined}
 */
function getRealPath(filePath) {
    /** @type {number} */
    var i;
    /** @type {string} */
    var dirname = path.dirname(filePath);
    /** @type {string} */
    var lowerFileName = path.basename(filePath).toLowerCase();
    /** @type {Array.<string>} */
    var fileNames = fs.readdirSync(dirname);

    for (i = 0; i < fileNames.length; i += 1) {
        if (fileNames[i].toLowerCase() === lowerFileName) {
            return path.join(dirname, fileNames[i]);
        }
    }
}

如果您的用例需要处理区分大小写的文件系统,建议您保留以下内容的列表: 潜在匹配项,然后打开潜在匹配项以检查内容,以确定合适的匹配项。

答案 2 :(得分:1)

从节点9开始,fs.realpathSync.native似乎可以解决问题。