Cách (tạm thời) chụp stdout
Làm cách nào để chụp tạm thời stdout trong Nim?
Tôi muốn có một mẫu với chữ ký sau:
template captureStdout(ident: untyped, body: untyped) = discard
Sao cho mã này ( main.nim) chạy mà không có lỗi:
var msg = "hello"
echo msg & "1"
var s: string
captureStdout(s):
echo msg & "2"
msg = "ciao"
echo msg & "3"
assert s == "hello2\n"
và đầu ra phải là:
hello1
ciao3
nỗ lực hiện tại
hiện tại, tôi có thể chụp stdout bằng một tệp tạm thời, nhưng tôi không thể phát hành trở lại stdout. Tôi làm điều này với những điều sau:
template captureStdout*(ident: untyped, body: untyped) =
discard reopen(stdout, tmpFile, fmWrite)
body
ident = readFile(tmpFile)
với điều này main.nimchạy mà không có lỗi xác nhận nhưng đầu ra chỉ
hello1
và trong tmpFile tôi thấy:
hello2
ciao3
Trả lời
Khi bạn gọi, reopenbạn gán lại biến stdoutcho một biến được Fileghi vào tmpFile.
Để in kết quả đầu ra cho STDOUT hệ thống, bạn cần gán lại biến stdoutthành một biến Fileghi vào STDOUT systel của bạn.
Do đó, câu trả lời là khác nhau giữa Linux và Windows.
Đối với Linux, cách thực hiện điều này là sử dụng hàm C trùng lặp và lặp lại 2 để sao chép bộ stdoutmô tả tệp và sử dụng một tệp khác (để bạn có thể khôi phục stdout). Vì sao chép và trùng lặp2 không có system/iotrong Nim nên chúng tôi cần có các ràng buộc unistd.h.
Đây là một ví dụ:
#Create dup handles
proc dup(oldfd: FileHandle): FileHandle {.importc, header: "unistd.h".}
proc dup2(oldfd: FileHandle, newfd: FileHandle): cint {.importc,
header: "unistd.h".}
# Dummy filename
let tmpFileName = "tmpFile.txt"
template captureStdout*(ident: untyped, body: untyped) =
var stdout_fileno = stdout.getFileHandle()
# Duplicate stoud_fileno
var stdout_dupfd = dup(stdout_fileno)
echo stdout_dupfd
# Create a new file
# You can use append strategy if you'd like
var tmp_file: File = open(tmpFileName, fmWrite)
# Get the FileHandle (the file descriptor) of your file
var tmp_file_fd: FileHandle = tmp_file.getFileHandle()
# dup2 tmp_file_fd to stdout_fileno -> writing to stdout_fileno now writes to tmp_file
discard dup2(tmp_file_fd, stdout_fileno)
#
body
# Force flush
tmp_file.flushFile()
# Close tmp
tmp_file.close()
# Read tmp
ident = readFile(tmpFileName)
# Restore stdout
discard dup2(stdout_dupfd, stdout_fileno)
proc main() =
var msg = "hello"
echo msg & "1"
var s: string
captureStdout(s):
echo msg & "2"
msg = "ciao"
echo msg & "3"
echo ">> ", s
assert s == "hello2\n"
when isMainModule:
main()
# Check it works twice
main()