2015-12-09 3 views
2

Каким образом рекомендуется использовать более 1024 символов при чтении со стандартного ввода в Go?Go - Как увеличить максимальную длину входного сигнала Stdin?

Например, этот код с помощью bufio.Scanner имеет максимальную длину входного 1024.

package main 

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

func main() { 
    scanner := bufio.NewScanner(os.Stdin) 
    scanner.Scan() 
    input := scanner.Text() 
    fmt.Println(input) 
} 

Update после некоторых предложенных ответов ... К сожалению, ребят - я должен еще делать что-то неправильно, или искажен вопрос , Я попробовал оба предложения и по-прежнему вижу ту же проблему. Ниже приведена обновленная версия кода. Симптом заключается в том, что сканер не будет принимать ввод после 1024-го символа. например Попробуйте запустить это затем вставить в строку, которая давно 1025 символов, и это перестанет принимать входной сигнал после символа 1024.

package main 

import (
    "bufio" 
    "bytes" 
    "fmt" 
    "log" 
    "os" 
) 

func main() { 
    var buffer bytes.Buffer 
    scanner := bufio.NewScanner(os.Stdin) 

    for { 
     done := scanner.Scan() 
     buffer.WriteString(scanner.Text()) 
     if done == true { 
      if scanner.Err() != nil { 
       log.Fatal("Error scanning input") 
      } 
      break 
     } 
    } 
    fmt.Println(buffer.String()) 
} 
+1

[максимальный размер маркера сканера] (https://golang.org/pkg/bufio/#pkg-constants) - 64k. Существует [пример использования сканера в документах] (https://golang.org/pkg/bufio/#example_Scanner_lines) – JimB

+1

Вы не можете проверить это, вставив текст в терминал. В готовом режиме tty имеет жесткий кодированный входной буфер в ядре, обычно 4096 на Linux и 1024 на Darwin. – JimB

+0

Argh - спасибо JimB. Я не знал об этом, и это меня подтолкнуло. Это было запутанно, потому что мой терминал (iTerm on Darwin) допускает более 1024 символов, когда он не работает как часть команды. –

ответ

1

Основная проблема с этим кодом является то, что возвращаемое значение сканера.Scan не true, если сканер выполнен, но true если сканер не выполнен.

В то время как мы фиксируя, что, давайте убирать другую вещь, так как вам не нужно использовать

if done == true 

но может просто сделать

if done 

Кроме того, помните, что done = Scanner.Text(), и служит прекрасным условием, и мы можем очень хорошо привести в порядок код:

for scanner.Scan() { // This does what you want, looping until scanner 
        // is no longer true. 
    buffer.WriteString(scanner.Text()) 
} 
if err := scanner.Err(); err != nil {   // Let's hold on to err... 
    log.Fatalf("Error scanning input: %s", err) // and use it here. 
} 

Вы можете отбросить много строк, и вы только проверяете Err() один раз в конце цикла. Не нужно использовать перерыв.

Надеюсь, что это сработает для вас, и присылайте мне строку, если вам нужно что-то еще.

Редактировать: Еще две вещи, о которых нужно знать.

1) bufio.Scanner.Scan() будет потреблять все ваши разделительные жетоны. Может быть, это нормально, или может быть, вы хотите, чтобы добавлять их обратно.

2) bufio.Scanner.Scan() может паниковать, если ваш SplitFunc неправильно, или кто-то крафта плохой вход для SplitFunc и bytes.Buffer.WriteString() может запаниковать, если буфер становится слишком большим , Если вы используете их в производственной системе, убедитесь, что вы справляетесь с этими паниками, каким бы то ни было образом.

+0

Отметьте это как ответ, потому что он хорошо очищает образец кода, поэтому благодарим за это. Комментарий JimB в вопросе также был моей проблемой. Т.е. эта ситуация: http://unix.stackexchange.com/questions/131105/how-to-read-over-4k-input-without-new-lines-on-a-terminal –

5

Вы игнорируете возвращаемое значение scanner.Scan() которое является bool указанием ли вы Достигнуто конец.

В частности:

Это возвращает ложь, когда сканирование останавливается, либо путем достижения конца входного или об ошибке. После того, как Scan вернет false, метод Err возвращает любую ошибку, которая произошла во время сканирования, за исключением того, что если она была io.EOF, Err вернет нуль.

Таким образом, вы должны продолжать работать scanner.Scan() в цикле, пока он не возвращает ложь, а затем проверить .Err(), чтобы убедиться, что вы не остановить сканирование из-за ошибки, не EOF.

+0

Спасибо sberry - я попробовал предложение и у меня все еще проблема. Если у вас есть время, посмотрите мой обновленный код. –

0

Вы можете сделать это вместо того, чтобы использовать Scanner ...

reader := bufio.NewReaderSize(os.Stdin, 65536) 
line, isPrefix, err := reader.ReadLine() 

Написать вспомогательную функцию, чтобы держать чтения, пока вы не читали полную линейку ...

func ReadLine(reader *bufio.Reader) (string, error) { 
    result := "" 
    for { 
     line, isPrefix, err := reader.ReadLine() 
     if err != nil { 
      return result, err 
     } 
     result += string(line) 
     if !isPrefix { 
      return result, nil 
     } 
    } 
} 
+1

ReadString или ReadBytes делает это за вас (из документа ReadLine: «Большинство абонентов должны использовать ReadBytes ('\ n') или ReadString ('\ n') вместо этого или использовать сканер.") – JimB

+0

Спасибо FogleBird - я попробовал вариант вашего предложения и по-прежнему имел тот же вопрос, что и я упоминал выше. –

Смежные вопросы