Golang检查字符串是否为有效路径

huangapple go评论78阅读模式
英文:

Golang check if string is valid path

问题

Golang filepath模块(https://golang.org/pkg/path/filepath/)包含一些用于操作路径的函数,os.Stat函数可以用于检查文件是否存在。是否有一种方法可以检查一个字符串是否实际上形成了一个有效的路径(无论该路径上是否存在文件)?

英文:

The Golang filepath module (https://golang.org/pkg/path/filepath/) contains a few functions for manipulating paths and os.Stat can be used to check if a file exists. Is there a way to check if a string actually forms a valid path at all (regardless of whether there's a file at that path or not)?

答案1

得分: 24

这个问题听起来很简单,但实际上并不简单。我找到了两种可能的解决方案:

解决方案1 - 学术方法

这个思路是基于规则检查给定的文件路径。

问题:

  1. 操作系统(UNIX / Windows)
  2. 文件系统
  3. 保留关键字

操作系统:

第一个问题是最简单的。Go语言提供了各种用于特定操作系统的文件名/分隔符等工具。

os包中的示例:

const (
    PathSeparator     = '/' // 特定操作系统的路径分隔符
    PathListSeparator = ':' // 特定操作系统的路径列表分隔符
)

filepath包中的另一个示例:

// VolumeName返回前导卷名。
// 给定"C:\foo\bar",在Windows上返回"C:"。
// 给定"\\host\share\foo",返回"\\host\share"。
// 在其他平台上返回""。
func VolumeName(path string) string {
	return path[:volumeNameLen(path)]
}

文件系统:

文件系统有不同的限制。允许的最大长度或字符集可能会有所不同。不幸的是,你无法知道你的路径将穿越哪些文件系统(至少据我所知)。

保留关键字:

为给定的操作系统建立一个保留关键字的黑名单。

实现:

对于这个解决方案,我会构建一个词法分析器/语法分析器

权衡之处在于它不能保证100%的文件路径有效。

解决方案2 - 经验法

尝试创建文件,然后立即删除它。

func IsValid(fp string) bool {
  // 检查文件是否已经存在
  if _, err := os.Stat(fp); err == nil {
    return true
  }

  // 尝试创建文件
  var d []byte
  if err := ioutil.WriteFile(fp, d, 0644); err == nil {
    os.Remove(fp) // 然后删除文件
    return true
  }

  return false
}

这个解决方案的主要优点是简单直接,更准确。如果在给定路径上已经存在文件或者可以创建文件,那么它就是有效的。然而,由于受限访问权限,这个解决方案也可能将有效路径视为无效。

总结

第一个解决方案比第二个解决方案更不准确,尽管从纯粹主义的角度来看更正确。你应该根据自己的需求选择解决方案。你更喜欢假阳性还是假阴性?第一个解决方案可能会给出假阳性,而第二个解决方案可能会给出假阴性。

英文:

This problem sounds very simple, but it is actually not. Here is two possible solutions that I found :

Solution 1 - Academic

The idea here is to check a given filepath based on rules.

##Problems

  1. Operating system (UNIX / Windows)
  2. Filesystem
  3. Reserved keywords

Operating system

The first one is the easiest. Go provides various tools for OS-specific filenames/separators/...

Example in the os package:

const (
    PathSeparator     = '/' // OS-specific path separator
    PathListSeparator = ':' // OS-specific path list separator
)

Another one in the filepath package:

// VolumeName returns leading volume name.
// Given "C:\foo\bar" it returns "C:" on Windows.
// Given "\\host\share\foo" it returns "\\host\share".
// On other platforms it returns "".
func VolumeName(path string) string {
	return path[:volumeNameLen(path)]
}

Filesystem

Filesystems have different restrictions. The maximum length or the charset allowed may vary. Unfortunately, there is no way you can tell (not as far as I know at least) which filesystem(s) your path will traverse.

Reserved keywords

Have a blacklist of all reserved keywords for a given OS.

##Implementation

For this solution, I would build a lexer/parser.

The tradeoff is that it would not guarantee 100% that a filepath is valid.

Solution 2 - Empirical

Attempt to create the file and delete it right after.

func IsValid(fp string) bool {
  // Check if file already exists
  if _, err := os.Stat(fp); err == nil {
    return true
  }

  // Attempt to create it
  var d []byte
  if err := ioutil.WriteFile(fp, d, 0644); err == nil {
    os.Remove(fp) // And delete it
    return true
  }

  return false
}

The main benefit of this solution is that it is straightforward and more accurate. If a file already exists or can be created at a given path, it means it is valid. However, this solution can also invalidate valid paths because of restricted access.

#Summary

The first solution will be less accurate than the second one, even though more correct from a puristic point of view. The solution you should pick up depends on your need. Do you prefer false positives or false negatives? The first solution can give you false positives, while the second one false negatives.

huangapple
  • 本文由 发表于 2016年2月6日 03:20:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/35231846.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定