2012-05-06 25 views

Trả lời

29

Tôi đồng ý bạn nên sử dụng các chức năng fmt.Fprint nếu bạn có thể quản lý. Tuy nhiên, nếu bạn không kiểm soát mã có đầu ra bạn đang chụp, bạn có thể không có tùy chọn đó.

Câu trả lời của Mostafa hoạt động, nhưng nếu bạn muốn làm điều đó mà không có tệp tạm thời, bạn có thể sử dụng os.Pipe. Dưới đây là một ví dụ tương đương với Mostafa với một số mã lấy cảm hứng từ gói thử nghiệm của Go.

package main 

import (
    "bytes" 
    "fmt" 
    "io" 
    "os" 
) 

func print() { 
    fmt.Println("output") 
} 

func main() { 
    old := os.Stdout // keep backup of the real stdout 
    r, w, _ := os.Pipe() 
    os.Stdout = w 

    print() 

    outC := make(chan string) 
    // copy the output in a separate goroutine so printing can't block indefinitely 
    go func() { 
     var buf bytes.Buffer 
     io.Copy(&buf, r) 
     outC <- buf.String() 
    }() 

    // back to normal state 
    w.Close() 
    os.Stdout = old // restoring the real stdout 
    out := <-outC 

    // reading our temp stdout 
    fmt.Println("previous output:") 
    fmt.Print(out) 
} 
+0

Cái này giống với ví dụ Python hơn. :) –

+2

Bạn thực sự muốn/cần bắt đầu 'io.Copy' * trước * mọi thứ ghi vào đường ống vì có giới hạn về khả năng đệm của đường ống. Di chuyển bắt đầu goroutine là tầm thường và hoàn toàn bỏ qua vấn đề. Ví dụ: http://play.golang.org/p/PNqa5M8zo7 –

+0

Cũng đừng bỏ qua lỗi từ 'os.Pipe' và có thể sử dụng' defer' để khôi phục 'os.Stdout' để bất kỳ mã được thêm nào có thể thoát chức năng không cần phải lo lắng về nó. Và điều này là rất không an toàn để sử dụng đồng thời. –

1

Tôi nghĩ rằng toàn bộ ý tưởng không được khuyến khích (điều kiện chủng tộc) ở tất cả, nhưng tôi đoán người ta có thể gây rối với os.Stdout theo cách tương tự/tương tự với ví dụ của bạn.

+0

Những loại điều kiện chủng tộc bạn đang nghĩ đến? –

+3

'os.Stdout' là biến toàn cục. Cài đặt vô điều kiện/không được bảo vệ và khôi phục lại nó là một ví dụ kinh điển về điều kiện chủng tộc. – zzzz

10

Tôi không đề xuất điều này, nhưng bạn có thể đạt được điều này bằng cách thay đổi os.Stdout. Vì biến này thuộc loại os.File, đầu ra tạm thời của bạn cũng phải là tệp.

package main 

import (
    "fmt" 
    "io/ioutil" 
    "os" 
    "path/filepath" 
) 

func print() { 
    fmt.Println("output") 
} 

func main() { 
    // setting stdout to a file 
    fname := filepath.Join(os.TempDir(), "stdout") 
    fmt.Println("stdout is now set to", fname) 
    old := os.Stdout // keep backup of the real stdout 
    temp, _ := os.Create(fname) // create temp file 
    os.Stdout = temp 

    print() 

    // back to normal state 
    temp.Close() 
    os.Stdout = old // restoring the real stdout 

    // reading our temp stdout 
    fmt.Println("previous output:") 
    out, _ := ioutil.ReadFile(fname) 
    fmt.Print(string(out)) 
} 

Tôi không khuyên bạn nên vì đây là quá nhiều hack, và không phải là rất thành ngữ trong Go. Tôi khuyên bạn nên chuyển một số io.Writer đến các hàm và viết kết quả đầu ra cho điều đó. Đây là cách tốt hơn để làm gần như cùng một điều.

package main 

import (
    "bytes" 
    "fmt" 
    "io" 
    "os" 
) 

func print(w io.Writer) { 
    fmt.Fprintln(w, "output") 
} 

func main() { 
    fmt.Println("print with byes.Buffer:") 
    var b bytes.Buffer 
    print(&b) 
    fmt.Print(b.String()) 

    fmt.Println("print with os.Stdout:") 
    print(os.Stdout) 
} 
6

Câu trả lời này tương tự như câu trả lời trước nhưng trông sạch hơn bằng cách sử dụng io/ioutil.

http://play.golang.org/p/fXpK0ZhXXf

package main 

import (
    "fmt" 
    "io/ioutil" 
    "os" 
) 

func main() { 
    rescueStdout := os.Stdout 
    r, w, _ := os.Pipe() 
    os.Stdout = w 

    fmt.Println("Hello, playground") // this gets captured 

    w.Close() 
    out, _ := ioutil.ReadAll(r) 
    os.Stdout = rescueStdout 

    fmt.Printf("Captured: %s", out) // prints: Captured: Hello, playground 
} 
+1

Điều này làm cho cùng một sai lầm như câu trả lời được chấp nhận. Đó là một ý tưởng tồi để viết vào một đường ống và sau đó đọc nó trở lại từ cùng một goroutine; đặc biệt là nếu bạn ngụ ý rằng "khối" ở giữa của bạn có thể là bất kỳ thứ gì với bất kỳ lượng đầu ra nào. Nó không thể, đường ống có khả năng đệm hạn chế. –

+0

Tôi sử dụng điều này trong phần thử nghiệm của mình vì tôi đang sử dụng gói của bên thứ ba để in ra thiết bị xuất chuẩn và tôi cần tìm nạp kết quả đó. Tôi không kiểm soát mã của bên thứ ba vì vậy không có cách nào khác để làm điều đó. Nếu bạn nghĩ ra một giải pháp khác, tôi rất vui được học! ;-) – mattes

+1

mattes, chỉ cần sử dụng một goroutine như trong câu trả lời được chấp nhận nhưng bắt đầu nó trước đó. Nếu không, nếu bạn nhấn một trường hợp mã bên thứ ba bạn không kiểm soát quyết định đổ nhiều đầu ra (có thể là do lỗi, hoặc chạy một hệ điều hành khác nơi vùng đệm khác nhau), bạn sẽ nhận được "lỗi nghiêm trọng: tất cả các goroutines đang ngủ - bế tắc "(ví dụ: http: //play.golang.org/p/NtpJkCEXDX không thành công). –

Các vấn đề liên quan