如何解释 os.FileMode 的显示值?

chm*_*ike 2 go

我有一个程序试图过滤 NamedPipe 文件。由于它没有按预期工作,所以我打印了结果,但对输出感到惊讶。你能解释一下吗?

\n\n
package main\n\nimport (\n    "io/ioutil"\n    "log"\n    "os"\n)\n\nfunc main() {\n    files, err := ioutil.ReadDir(".")\n    if err != nil {\n        log.Fatal(err)\n    }\n    for _, info := range files {\n        log.Printf("file: %s mode: %x\\n", info.Name(), info.Mode()&os.ModeNamedPipe)\n        log.Printf("file: %s mode: %v\\n", info.Name(), info.Mode()&os.ModeNamedPipe)\n        log.Printf("file: %s mode: %v\\n", info.Name(), info.Mode()&os.ModeNamedPipe != 0)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这输出

\n\n
2020/02/06 18:06:46 file: main.go mode: 2d2d2d2d2d2d2d2d2d2d\n2020/02/06 18:06:46 file: main.go mode: ----------\n2020/02/06 18:06:46 file: main.go mode: false\n2020/02/06 18:06:46 file: status.kch mode: 702d2d2d2d2d2d2d2d2d\n2020/02/06 18:06:46 file: status.kch mode: p---------\n2020/02/06 18:06:46 file: status.kch mode: true\n
Run Code Online (Sandbox Code Playgroud)\n\n

我不明白的是当我以十六进制打印模式时的输出。我希望模式是一个位设置,而 os.ModeNamedPipe 是一个位掩码。所以我假设info.Mode()&os.ModeNamedPipe当文件不是命名管道时会产生整数 0。但我得到了不同的价值。

\n\n

我终于找到了如何测试文件是否是命名管道,但它是违反直觉的。

\n\n

您能解释一下这些不同的输出吗?

\n

icz*_*cza 5

info.Mode()返回类型为 的值os.FileMode,并且os.ModeNamedPipe也是类型为 的值os.FileMode。所以这将是您想要打印/记录的值的类型。

os.FileMode不仅仅是一个整数类型,它是一个独特的类型并且它实现了fmt.Stringer. 并使用动词、包 doc%x中的规则打印它:

如果格式(对于 Println 等隐式为 %v)对于字符串 (%s %q %v %x %X) 有效,则适用以下两个规则:

  1. 如果操作数实现了错误接口,则将调用 Error 方法将对象转换为字符串,然后根据动词(如果有)要求对其进行格式化。

  2. 如果操作数实现 String() 字符串方法,则将调用该方法将对象转换为字符串,然后根据动词(如果有)的要求对其进行格式化。

所以FileMode.String()会先调用该方法,然后使用 打印字符串值%x,这意味着:

字符串和字节切片(与这些动词等效处理):

%x    base 16, lower-case, two characters per byte
Run Code Online (Sandbox Code Playgroud)

因此,您看到的 ( 2d2d2d2d2d2d2d2d2d2d) 是结果的字符串表示形式的 (UTF-8) 字节的十六进制表示形式os.FileMode。如果它不是命名管道,则它是“充满破折号”,否则它有一个前导'p'.

uint32如果您想将其视为数字(是的,os.ModeNamedPipe仅设置了一位) ,则可以将其转换为整数 ( ):

fmt.Printf("as-is         : %x\n", os.ModeNamedPipe)
fmt.Printf("hexa string   : %x\n", os.ModeNamedPipe.String())
fmt.Printf("default string: %v\n", os.ModeNamedPipe.String())
fmt.Printf("decimal       : %d\n", os.ModeNamedPipe)
fmt.Printf("hexa          : %x\n", uint32(os.ModeNamedPipe))
fmt.Printf("binary        : %b\n", os.ModeNamedPipe)
Run Code Online (Sandbox Code Playgroud)

它输出(在Go Playground上尝试):

as-is         : 702d2d2d2d2d2d2d2d2d
hexa string   : 702d2d2d2d2d2d2d2d2d
default string: p---------
decimal       : 33554432
hexa          : 2000000
binary        : 10000000000000000000000000
Run Code Online (Sandbox Code Playgroud)