Хаскелл:Как передать содержимое одного дескриптора в другой в режиме реального времени

StackOverflow https://stackoverflow.com/questions/671610

  •  21-08-2019
  •  | 
  •  

Вопрос

Я пишу программу, которая запускает внешний подпроцесс в интерактивном режиме, и мне нужно, чтобы содержимое дескриптора вывода выводилось на стандартный вывод, как только оно станет доступно.Я пробовал что-то вроде этого:

main = do processInfo <- createProcess (proc "ghci" []){std_out = CreatePipe,
                                                    std_in  = CreatePipe }
       case processInfo of
          (Just hIn, Just hOut, _, _) -> do mainloop hIn hOut
                                          hClose hIn
                                          hClose hOut
       _                              -> do error "Unable to start process"

mainloop :: Handle -> Handle -> IO ()
mainloop inh outh = 
    do ineof <- hIsEOF outh
       if ineof
          then return ()
          else do inpStr <- hGetLine outh
                  putStrLn inpStr
                  mainloop inh outh

Но это не работает, поскольку он распознает вывод только построчно, поэтому любой вывод в дескрипторе вывода процесса, который не завершается символом новой строки, не отображается.Я пробовал то же самое с hGetContents, но результат тот же.Я прочитал документацию как по System.Process, так и по System.IO и не нашел ничего убедительного.

Это было полезно?

Решение

hSetBuffering это то, что вы ищете, по умолчанию (по крайней мере, в Unix) используется буферизация строк.Используйте его на стандартном вводе перед запуском основного цикла.

hSetBuffering hIn NoBuffering

и, при необходимости, также в дескрипторе вывода, если вы хотите сразу увидеть результаты на стороне вывода.Однако обратите внимание, что отключение буферизации может существенно снизить производительность.

Другие советы

Я новичок в Haskell, но помню, что недавно наткнулся на пример посимвольной обработки входных данных.Является hSetBuffering возможно, то, что вы ищете?

Буферизация — это одно, но вы также используете gGetLine который будет ждать целой строки (или конца файла).Рассмотрите возможность использования hGetChar если вы действительно хотите читать по одному символу за раз.И кстати, еще один способ обойти буферизацию — использовать hFlush.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top