golang中的文件输入

时间:2013-08-01 19:26:22

标签: go stdin

我是Go的新手(就像在最后一天一样),我正在玩一个处理stdin数据的简单程序。我想做的是使得如果没有向stdin提供数据,那么程序将输出帮助屏幕然后退出。我遇到的问题是,当没有通过stdin提供数据时程序似乎无限期挂起。以下是该计划的简短示例和我的预期用法:

package main

import (
    "fmt"
    "bufio"
    "os"
)


func main() {
    scanner := bufio.NewScanner(os.Stdin)
    scanner.Split(bufio.ScanLines)
    for scanner.Scan() {
        str := scanner.Text()
        fmt.Println(str)
    }
}


Running with input:
go run test.go < lines.txt
line1
line2
line3


Running with no input:
go run test.go

我不提供输入的第二种情况是导致程序挂起的原因。通过文档阅读我不清楚我如何能够编写程序以便无限期地等待输入,而是在stdin上没有任何内容时中断。

2 个答案:

答案 0 :(得分:3)

程序的行为与代码完全一致。代码说从stdin读取。可以通过重定向(如您所示)提供对stdin的输入。或者通过管道。或....或用户键入键盘。如果在最后一种情况下程序会在人类输入之前退出,那将是非常令人惊讶的。

一种常见的方法是执行类似(简化)的操作:

var in *os.File
var err error

switch name := flag.Arg(0); {
case name == "":
        in = os.Stdin
default:
        if in, err = os.Open(name); err != nil {
                log.Fatal(err)
        }
}

IE中。允许处理作为命令行参数给出的命名文件 - 但是当没有给程序提供文件名参数时,回退/默认为读取stdin。

这种方法可以很好地处理shell脚本,通过管道链接命令等等。

答案 1 :(得分:2)

对于你的用例来说,这可能有点拉伸,特别是如果你只是选择了go,但一般来说,你想要的行为可以通过使用带超时的select来模仿:

func scanForInput() chan string{
    lines := make(chan string)
    go func(){
       scanner := bufio.NewScanner(os.Stdin)
       scanner.Split(bufio.ScanLines)
       for scanner.Scan() {
           lines <- scanner.Text()
       }
       close(lines)
    }
    return lines
}

func main(){
    lines := scanForInput()
    for {
    select{
         case line, closed := <- lines:
              fmt.Prinln(line)
              if closed {
                  return
              }
         case time.After(1 * time.Second):
              printHelpMessage()
              return
    }
   }
}

将它视为您下一个学习步骤的灵感。

PS:恩惠,我希望像语言一样: - )