2 votes

entrée de fichiers dans golang

Je suis tout nouveau sur Go (c'est-à-dire depuis moins d'un jour) et je m'amuse avec un programme simple qui traite les données de stdin. Je voulais faire en sorte que si aucune donnée n'est fournie à stdin, le programme affiche un écran d'aide et se termine. Le problème que j'ai rencontré est que le programme semble se bloquer indéfiniment lorsqu'aucune donnée n'est fournie par stdin. Voici un court exemple du programme et de l'utilisation que je souhaite en faire :

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

Le deuxième cas où je ne fournis pas d'entrée est ce qui provoque le blocage du programme. En lisant la documentation, je ne vois pas comment je pourrais coder le programme pour qu'il n'attende pas indéfiniment une entrée, mais qu'il s'arrête si rien n'est présent sur stdin.

4voto

zzzz Points 23017

Le programme se comporte exactement comme le dit le code. Le code dit de lire à partir de stdin. L'entrée vers stdin peut être fournie par redirection (comme vous le montrez). Ou par piping. Ou par .... Ou par la saisie de l'utilisateur sur le clavier. Il serait très surprenant que, dans le dernier cas, le programme se termine avant que l'utilisateur ait pu saisir quelque chose.

Une approche courante consiste à faire quelque chose comme (simplifié) :

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)
        }
}

Par exemple, permettre de traiter un fichier nommé donné en argument de ligne de commande - mais revenir à la lecture de stdin par défaut si aucun argument de nom de fichier n'est donné au programme.

Cette approche se prête bien à la création de scripts shell, à l'enchaînement de commandes via des tuyaux, etc.

3voto

flexy Points 678

C'est peut-être un peu difficile pour votre cas d'utilisation, surtout si vous venez d'apprendre à utiliser go, mais en général, le comportement que vous souhaitez peut être imité en utilisant un select avec un timeout :

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
    }
   }
}

Considérez-le comme une source d'inspiration pour votre prochaine étape d'apprentissage.

PS : Bienvenu à vous, j'espère que vous aimez la langue :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X