dtx9931
dtx9931
2016-02-11 14:28
浏览 27

可以在Go中使用类似“ freopen”的构造吗?

In C++ there's a freopen func, which is very useful to r/w files with just stdin/out(cin/cout). So I decided to find similar solution in Go, but found only

import "os"
os.Stdin, err = os.OpenFile("input.txt",
    os.RDONLY | os.O_CREATE, 0666)
os.Stdout, err = os.OpenFile("output.txt",
    os.O_WRONLY | os.O_CREATE | os.O_TRUNC, 0666)

, which is not working anymore! Am I wrong? So, do you know other way?

图片转代码服务由CSDN问答提供 功能建议

在C ++中,有一个 freopen 函数,该函数对于使用以下命令读/写文件非常有用 只是标准输入/输出(cin / cout)。 因此,我决定在Go中找到类似的解决方案,但只能找到

  import“ os” 
os.Stdin,err = os.OpenFile(“ input.txt”,
  os.RDONLY | os.O_CREATE,0666)
os.Stdout,err = os.OpenFile(“ output.txt”,
 os.O_WRONLY | os.O_CREATE | os.O_TRUNC,0666)
  <  / pre> 
 
 

,它不再起作用了! 我错了吗? 所以,您知道其他方式吗?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • duanfei1268
    duanfei1268 2016-02-11 14:43
    已采纳

    You cannot declare and assign to a variable in another package (os.Stdin, for example).

    However this works:

    package main
    
    import (
        "fmt"
        "log"
        "os"
    )
    
    func main() {
        stdin, err := os.OpenFile("input.txt",
            os.O_RDONLY|os.O_CREATE, 0666)
        if err != nil {
            log.Fatal(err)
        }
        os.Stdin = stdin
    
        stdout, err := os.OpenFile("output.txt",
            os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
        if err != nil {
            log.Fatal(err)
        }
        os.Stdout = stdout
    
        fmt.Println("out")
        return
    }
    
    点赞 评论
  • dongruoqiong9017
    dongruoqiong9017 2016-02-11 15:52

    While Jeff Allen provided a good answer, there's a minor low-level "catch" to the approach presented there: the os.File values representing new destinations for the standard output streams will refer to file descriptors different from those of stdout and stderr as the OS sees them.1

    The thing is, when a process starts on a POSIX-compatible system, it has its three standard streams open to file descriptors 0, 1 and 2 for stdin, stdout and stderr, correspondingly.

    Hence in an obscure case of some bit of the code relying on the fact the standard streams being connected to the standard file descriptors, the code provided by Jeff Allen will not be quite correct.

    To make it 100% correct, we may rely on another POSIX property which reuses the lowest free file descriptor when opening a new file. Hence if we close the file representing one standard stream and immediately open another one,—that new file will be open using the file descriptor of the just closed standard stream. To guarantee that no file is open between the sequence of steps just presented, we must run our code before any goroutine except the main one starts running—that is, in main() or any init().

    Here's the code to demonstrate the idea:

    package main
    
    import (
        "os"
    )
    
    func init() {
        err := os.Stdout.Close()
        if err != nil {
            panic(err)
        }
    
        fd, err := os.OpenFile("output.txt",
            os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
        if err != nil {
            panic(err)
        }
    
        os.Stdout = fd
    }
    
    func main() {
        myfd := os.NewFile(1, "")
    
        _, err := myfd.Write([]byte("Direct output to FD 1
    "))
        if err != nil {
            panic(err)
        }
    
        _, err = os.Stdout.Write([]byte("Write to redirected os.Stdout
    "))
        if err != nil {
            panic(err)
        }
    
        os.Exit(1)
    }
    

    …and here is how it works:

    $ go build
    $ ./freopen 
    $ cat output.txt 
    Direct output to FD 1
    Write to redirected os.Stdout
    

    It might seem like nitpicking but I think it worth explaning the "full stack" of what's going on.

    Oh, and redirecting this way will also provide sensible view to the process for outside observers: say, on Linux, inspecting the file descriptors opened by the process via something like

    $ vdir /proc/<pid>/fd
    

    will provide sensible results.


    1 …and everything else which does not know about Go—for instance, a bit of linked in C code which calls something like write(1, "OK ", 3);

    点赞 评论

相关推荐