在Go语言中,表示换行最便携/跨平台的方式是什么?

46

目前,在Go程序中表示换行,我使用\n。例如:

package main

import "fmt"


func main() {
    fmt.Printf("%d is %s \n", 'U', string(85))
}

...将产生85 is U,然后换行。

然而,这似乎并不是很跨平台。看看其他语言,PHP使用全局常数(PHP_EOL)表示这一点。在Go / Golang中,\n是以跨平台特定方式表示换行的正确方法吗?

4个回答

27

我对此感到好奇,所以决定看看fmt.Println具体做了什么。 http://golang.org/src/pkg/fmt/print.go

如果向下滚动,您将看到一个if addnewline,其中始终使用\n。我几乎不能说这是否是最“跨平台”的方法,而且在早期,go最初与linux相关联,但对于std lib来说,就是在那里。

我最初想建议仅使用fmt.Fprintln,并且如果当前功能不合适,则可以提交错误报告,然后只需要使用最新的Go工具链编译代码即可。


4
因为换行符翻译是在非二进制输出流中启用的,所以直接将"\n"打印到某些输出流中是可以的。这是基于C运行时库的Go语言的一个特性:它会自动将行尾转换为平台使用的行尾,因此在程序代码中只使用"\n"是安全的。然而,这仅适用于非二进制流,并且仅使用C运行时不容易获取平台换行符(例如作为字符串)。 - Vladimir Matveev
4
@VladimirMatveev,你确定Go是基于C运行时的吗?看起来它的标准编译器并不依赖于C运行时,并且生成的静态链接二进制文件也不依赖于任何东西。 - kostix
3
@kostix,看起来你是正确的。研究Go I/O机制的内部结构表明,在Unix系统上它们使用POSIX的open()系统调用,在Windows系统上则使用CreateFile来打开文件。 os.File#Write提供的缓冲区似乎直接不经改变地发送到Windows的WriteFile API函数。 Windows API函数不会进行换行符的转换,因此如果源文件中只有LF,则输出将仅包含LF。 - Vladimir Matveev
2
顺便说一下,@VladimirMatveev,我最近实现了对简单文本文件的解析,基本上使用 bufio.ReadString(),并且认为我也想要一个更高级的函数来完成这样的任务,它将读取到 \r\n\n(单个 \r 似乎不再相关),并返回不包括 EOL 序列的文本。 Tcl 的 gets 就是这样工作的。但这真的是一个在 golang-nuts 上讨论的话题... - kostix

21

让操作系统确定换行符通常在许多情况下都是错误的。你真正想知道的是"记录"分隔符是什么,Go假设作为程序员的你应该知道。

即使二进制文件在Windows上运行,它可能正在消耗来自Unix操作系统的文件。

行尾是由文件或文档源说过的行尾确定的,而不是二进制文件所在的操作系统。


18

您始终可以使用特定于操作系统的文件来声明某些常量。就像_test.go文件仅在执行go test时使用一样,_[os].go仅在构建到该目标平台时包含。

基本上,您需要添加以下文件:

 - main.go
 - main_darwin.go     // Mac OSX
 - main_windows.go    // Windows
 - main_linux.go      // Linux

你可以在每个 main_[os].go 文件中声明一个 LineBreak 常量,并将逻辑放在 main.go 中。

文件的内容大致如下:

main_darwin.go

package somepkg

const LineBreak = "\n"

main_linux.go

package somepkg

const LineBreak = "\n"

main_windows.go

package somepkg

const LineBreak = "\r\n"

只需在您的 main.go 文件中编写代码并引用 LineBreak 即可。

main.go

package main

import "fmt"


func main() {
    fmt.Printf("%d is %s %s", 'U', string(85), LineBreak)
}

在Windows和非Windows之间进行分割应该足够了。请注意,在linuxdarwinwindows之外还有更多的GOOS值。 - undefined

-1
您可以使用os.PathSeparator
func main() {
    var PS = fmt.Sprintf("%v", os.PathSeparator)
    var LineBreak = "\n"
    if PS != "/" {
        LineBreak = "\r\n"
    }
    fmt.Printf("Line Break %v", LineBreak)
}

https://play.golang.com/p/UTnBbTJyL9c


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接