Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Go中,如何将函数的stdout捕获到字符串中?_Go_Stdout - Fatal编程技术网

在Go中,如何将函数的stdout捕获到字符串中?

在Go中,如何将函数的stdout捕获到字符串中?,go,stdout,Go,Stdout,例如,在Python中,我可以执行以下操作: realout = sys.stdout sys.stdout = StringIO.StringIO() some_function() # prints to stdout get captured in the StringIO object result = sys.stdout.getvalue() sys.stdout = realout 你能在围棋中做到这一点吗?我认为整个想法根本不可取(竞赛条件),但我想人们可能会以类似于/类似于你

例如,在Python中,我可以执行以下操作:

realout = sys.stdout
sys.stdout = StringIO.StringIO()
some_function() # prints to stdout get captured in the StringIO object
result = sys.stdout.getvalue()
sys.stdout = realout

你能在围棋中做到这一点吗?

我认为整个想法根本不可取(竞赛条件),但我想人们可能会以类似于/类似于你的例子的方式弄乱os.Stdout。

我不推荐这样做,但你可以通过改变
os.Stdout
来实现它。由于此变量的类型为
os.File
,因此临时输出也应为文件

package main

import (
    "fmt"
    "io/ioutil"
    "os"
    "path/filepath"
)

func print() {
    fmt.Println("output")
}

func main() {
    // setting stdout to a file
    fname := filepath.Join(os.TempDir(), "stdout")
    fmt.Println("stdout is now set to", fname)
    old := os.Stdout // keep backup of the real stdout
    temp, _ := os.Create(fname) // create temp file
    os.Stdout = temp

    print()

    // back to normal state
    temp.Close()
    os.Stdout = old // restoring the real stdout

    // reading our temp stdout
    fmt.Println("previous output:")
    out, _ := ioutil.ReadFile(fname)
    fmt.Print(string(out))
}
我不推荐这样做,因为这是太多的黑客行为,而且在围棋中也不太习惯。我建议向函数传递一个
io.Writer
,并向其写入输出。这是做同样事情的更好方法

package main

import (
    "bytes"
    "fmt"
    "io"
    "os"
)

func print(w io.Writer) {
    fmt.Fprintln(w, "output")
}

func main() {
    fmt.Println("print with byes.Buffer:")
    var b bytes.Buffer
    print(&b)
    fmt.Print(b.String())

    fmt.Println("print with os.Stdout:")
    print(os.Stdout)
}

我同意如果你能管理的话,你应该使用
fmt.Fprint
功能。但是,如果不控制要捕获其输出的代码,则可能没有该选项

Mostafa的答案是可行的,但是如果你想在没有临时文件的情况下使用它,你可以使用。这里有一个与Mostafa相当的示例,其中一些代码是受Go的测试包启发编写的

package main

import (
    "bytes"
    "fmt"
    "io"
    "os"
)

func print() {
    fmt.Println("output")
}

func main() {
    old := os.Stdout // keep backup of the real stdout
    r, w, _ := os.Pipe()
    os.Stdout = w

    print()

    outC := make(chan string)
    // copy the output in a separate goroutine so printing can't block indefinitely
    go func() {
        var buf bytes.Buffer
        io.Copy(&buf, r)
        outC <- buf.String()
    }()

    // back to normal state
    w.Close()
    os.Stdout = old // restoring the real stdout
    out := <-outC

    // reading our temp stdout
    fmt.Println("previous output:")
    fmt.Print(out)
}
主程序包
进口(
“字节”
“fmt”
“io”
“操作系统”
)
func print(){
fmt.Println(“输出”)
}
func main(){
old:=os.Stdout//保留真实Stdout的备份
r、 w,u:=os.Pipe()
os.Stdout=w
打印()
outC:=制造(成串)
//将输出复制到单独的goroutine中,这样打印就不会无限期地阻塞
go func(){
var buf字节。缓冲区
io.副本(&buf,r)

outC这个答案与前面的答案类似,但是使用io/ioutil看起来更干净


这一个与Python示例更为相似。:)您确实希望/需要在写入管道之前启动
io.Copy
,因为管道的缓冲能力受到限制。将start移动到goroutine非常简单,完全可以绕过此问题。例如:也不要忽略
os.pipe
中的错误,并且,可能使用
defer
来还原
os.Stdout
,这样可能退出函数的任何添加的代码都不需要担心。这对于并发使用来说是非常不安全的。为什么代码比Python示例多得多?不尝试使用troll,真正好奇的是,为什么Go似乎需要更复杂的代码来完成这个看似简单的任务le操作。我将您的逻辑放入一个库中:您在考虑什么样的争用条件?
os。Stdout
是一个全局变量。无条件/无保护设置和恢复它是争用条件的典型示例。这与公认的答案犯了相同的错误。写入管道,然后再读取它是一个坏主意来自同一个goroutine的ack;特别是如果你暗示你的中间“块”可以是任何数量的输出。它不能,管道的缓冲能力有限。我在我的测试中使用它,因为我使用的是打印到stdout的第三方软件包,我需要获取该输出。我不控制第三方代码,所以没有其他方法。如果你想出另一个解决方案,我很乐意earn!;-)不重要,只需按照公认的答案使用goroutine,但要提前启动它。否则,如果您遇到一个情况,即您无法控制的第三方代码决定转储大量输出(可能是在失败时,或者在管道缓冲不同的操作系统上运行),您将得到“致命错误:所有goroutine都处于休眠状态-死锁”(例如失败)。这是我编写的小插件的简单解决方案。谢谢!
package main

import (
  "fmt"
  "io/ioutil"
  "os"
)

func main() {
  rescueStdout := os.Stdout
  r, w, _ := os.Pipe()
  os.Stdout = w

  fmt.Println("Hello, playground") // this gets captured

  w.Close()
  out, _ := ioutil.ReadAll(r)
  os.Stdout = rescueStdout

  fmt.Printf("Captured: %s", out) // prints: Captured: Hello, playground
}