Skip to content

Commit d4f600f

Browse files
committed
Add io.Pipe() example
1 parent ea20aea commit d4f600f

File tree

3 files changed

+107
-0
lines changed

3 files changed

+107
-0
lines changed

examples/basic/streams/examples.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ func NewRegister() mappings.Register {
1616
// Regist -- 登録します.
1717
func (r *register) Regist(m mappings.ExampleMapping) {
1818
m["streams_nopcloser"] = UsingNopCloser
19+
m["iopipe_basic"] = IoPipeBasic
1920
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package streams
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"fmt"
7+
"io"
8+
"io/ioutil"
9+
"log"
10+
"os"
11+
)
12+
13+
type (
14+
_filterWriter struct {
15+
w io.Writer
16+
}
17+
18+
_upperWriter struct {
19+
w io.Writer
20+
}
21+
)
22+
23+
var _ io.Writer = (*_filterWriter)(nil)
24+
var _ io.Writer = (*_upperWriter)(nil)
25+
26+
var (
27+
filterTarget = []byte("wars")
28+
)
29+
30+
func (me *_filterWriter) Write(p []byte) (n int, err error) {
31+
if bytes.HasPrefix(p, filterTarget) {
32+
return me.w.Write(p)
33+
}
34+
35+
return ioutil.Discard.Write(p)
36+
}
37+
38+
func (me *_upperWriter) Write(p []byte) (n int, err error) {
39+
return me.w.Write(bytes.ToUpper(p))
40+
}
41+
42+
// IoPipeBasic -- io.Pipe の基本的なサンプルです.
43+
//
44+
// REFERENCES:
45+
// - https://www.geeksforgeeks.org/io-pipe-function-in-golang-with-examples/
46+
// - https://medium.com/eureka-engineering/file-uploads-in-go-with-io-pipe-75519dfa647b
47+
func IoPipeBasic() error {
48+
// ----------------------------------------------------------------
49+
// io.Pipe() は、インメモリの同期パイプを生成してくれる。
50+
// io.Pipe() は、片方が io.Reader を必要としていて
51+
// もう片方が、io.Writer を必要としてる時に、その2つを接続することが出来る。
52+
//
53+
// 通常、このような場合は中間バッファを作成し結果を蓄積し
54+
// 出力先の io.Writer に出力することが多い。
55+
// しかし、大容量のデータを中間バッファに蓄積する場合は
56+
// それがメモリを大量に消費する原因となる可能性がある。
57+
//
58+
// io.Pipe() で取得できる *PipeReader と *PipeWriter は
59+
// 同期しており、かつ、バッファリング無しとなっているので
60+
// *PipeWriter に書き込んだデータは、即座に *PipeReader 側に渡る。
61+
//
62+
// 注意点として、同期しているストリームなので
63+
// 片方だけ利用するということは出来ない。デッドロックが発生する。
64+
// *PipeReaderで読むためには、必ず *PipeWriter 側で書き込みを行っていないといけない
65+
// 逆も然り。
66+
//
67+
// なので、io.Pipe() を利用する場合は、ゴルーチンが必要となる。
68+
// ----------------------------------------------------------------
69+
var (
70+
pr *io.PipeReader
71+
pw *io.PipeWriter
72+
)
73+
74+
pr, pw = io.Pipe()
75+
76+
// 書き込み側を非同期で実行
77+
// io.Pipe() から取得できる2つのストリームは同期しているので
78+
// 同時に扱わないとデッドロックする.
79+
go func() {
80+
defer pw.Close()
81+
82+
f, err := os.Open("/usr/share/dict/words")
83+
if err != nil {
84+
log.Println(err)
85+
return
86+
}
87+
defer f.Close()
88+
89+
scanner := bufio.NewScanner(f)
90+
for scanner.Scan() {
91+
fmt.Fprintf(pw, "%s\n", scanner.Text())
92+
}
93+
94+
if err := scanner.Err(); err != nil {
95+
log.Println(err)
96+
}
97+
}()
98+
99+
// 読み込み
100+
// *PipeReader側で読み込むと*PipeWriter側のデータはクリアされる
101+
upperW := &_upperWriter{os.Stdout}
102+
filterW := &_filterWriter{upperW}
103+
io.Copy(filterW, pr)
104+
105+
return nil
106+
}

trygolang

11.1 MB
Binary file not shown.

0 commit comments

Comments
 (0)