How to read multiple times from same io.Reader - go

I want to use request.Body(type io.ReadCloser) which is containing a image.
I dont want to use ioutil.ReadAll() as i want to write this body directly to the file as well as want to decode it, so i only want to use the reference to the content to pass to further function calls,
I tried creating multiple instances of reader for example shown below
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
a := &r
b := &r
log.Println(ioutil.ReadAll(*a))
log.Println(ioutil.ReadAll(*b))
}
but in second call it always results into nil.
Please help me how can i pass multiple separate reference for the same reader?

io.Reader is treated like a stream. Because of this you cannot read it twice. Imagine an incoming TCP connection - you cannot rewind what's coming in.
But you can use the io.TeeReader to duplicate the stream:
package main
import (
"bytes"
"io"
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
var buf bytes.Buffer
tee := io.TeeReader(r, &buf)
log.Println(ioutil.ReadAll(tee))
log.Println(ioutil.ReadAll(&buf))
}
Example on Go Playground
Edit: As #mrclx pointed out: You need to read from the TeeReader first, otherwise the buffer will be empty.

When you call ReadAll it's going to empty the buffer, so the second call will always return nothing. What you could do is save the result of ReadAll and reuse that in your functions. For example:
bytes, _ := ioutil.ReadAll(r);
log.Println(string(bytes))

When you read from ioutil.ReadAll(r) then, the content is gone. You can’t read from it a second time.
For an example:
var response *http.Response
//Read the content
rawBody, err := ioutil.ReadAll(response.Body)
if err != nil {
t.Error(err)
}
// Restore the io.ReadCloser to it's original state
response.Body = ioutil.NopCloser(bytes.NewBuffer(rawBody))

Technically, on one reader, you cannot read multiple times.
Even if you create different references but
when you read once it will be same object referred by all references.
so what you can do is read the content and store it in one variable.
Then use that variable as many times as you want.
This will print twice.
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
stringData, _ := ioutil.ReadAll(r)
log.Println(stringData)
log.Println(stringData)
}

Clone the Reader struct.
package main
import (
"io/ioutil"
"log"
"strings"
)
func main() {
r := strings.NewReader("some io.Reader stream to be read\n")
v := new(strings.Reader)
*v = *r
log.Println(ioutil.ReadAll(r))
log.Println(ioutil.ReadAll(v))
}

Related

Send stdout of running command to its stdin in go

I have a somewhat challenging situation where I need to write into a system command stdin the same stdout it outputs (in another running program), here's an example program that represents what I mean:
package main
import (
"bufio"
"fmt"
"math/rand"
"os"
)
func main() {
rand.Seed(time.Now().Unix())
var greetings []string = []string{"hi", "hola", "bonjour", "hallo", "whats up"}
var greeting string = greetings[rand.Intn(len(greetings))]
fmt.Println(greeting)
reader := bufio.NewReader(os.Stdin)
message, _ := reader.ReadString('\n')
if message == greeting+"\n" {
fmt.Println("nice to meet you!")
} else {
fmt.Println("oops!")
}
}
Since you greet with a random greeting, you have to read the stdout, send it to stdin and also capture if it was the correct answer or not. I've tried with stdinpipes but it freezes waiting for the stdin close since I think that only works for the start of the command run only, so for a running program it hasn't been working for me...
I appreciate any help!
EDIT
I wanted to add sort of what I was trying to do, I've tried without channels as well but it didn't seem to make a difference on the outcome, it just freezes waiting for stdin to close and I need to get first stdout before closing stdin since it consists of it:
package main
import (
"io"
"os/exec"
)
func main() {
cmd := exec.Command("./executable_program")
stdout, _ := cmd.StdoutPipe()
stdin, _ := cmd.StdinPipe()
var c chan []byte = make(chan []byte)
cmd.Start()
go func() {
b, _ := io.ReadAll(stdout)
c <- b
}()
stdin.Write(<-c)
stdin.Close()
cmd.Wait()
}
You can use a pipe to join the stdout to the stdin of the program that you execute:
package main
import (
"io"
"os/exec"
)
func main() {
r, w := io.Pipe()
cmd := exec.Command("<name-of-program-to-run>")
cmd.Stdin = r
cmd.Stdout = w
cmd.Run()
}
To see this in action, first let's prepare a test program to be executed by the program above. This test program simply prints a line to stdout, and then reads each line of stdin and prints it to stdout until stdin is closed.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Fprint(os.Stdout, "priming the pump!\n")
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
line := s.Text()
fmt.Fprint(os.Stdout, line+"\n")
}
}
Then, we modify our initial program to print the bytes traversing through the pipe so we see what's going on.
package main
import (
"fmt"
"io"
"os/exec"
)
func main() {
r, w := io.Pipe()
sr := &readSpy{r: r}
wr := &writeSpy{w: w}
cmd := exec.Command("./test-program")
cmd.Stdin = sr
cmd.Stdout = wr
cmd.Run()
}
type readSpy struct {
r io.Reader
}
func (s *readSpy) Read(d []byte) (int, error) {
size, err := s.r.Read(d)
fmt.Println("readSpy read", string(d[:size]))
return size, err
}
type writeSpy struct {
w io.Writer
}
func (s *writeSpy) Write(d []byte) (int, error) {
size, err := s.w.Write(d)
fmt.Println("writeSpy wrote", string(d[:size]))
return size, err
}
Running the above, you will see the following getting printed in a infinite loop, which makes sense since the priming the pump! string is printed to stdout and fed right back to the stdin of the test program:
writeSpy wrote priming the pump!
readSpy read priming the pump!
...repeated forever...

data save on txt file using golang

I am trying to save my data to txt file , which is working fine , but when I give it to new data it is stored in the place of old data but I want it to that new data will store next to my old data...! please help
package main
import (
"fmt"
"io"
"log"
"os"
"strconv"
"strings"
"time"
)
func main() {
stop := Stoploss()
fmt.Println(stop)
}
func Stoploss() string {
stoploss := 12342
str := strconv.Itoa(stoploss)
Time := time.Now()
value := `stoploss =` + str + `\n at the time of -> ` + Time.Format("01-02-2006 15:04:05")
data, err := os.Create("stoploss.txt")
if err != nil {
log.Fatal("whoops", err)
}
io.Copy(data, strings.NewReader(value))
return str
}
os.Create("stoploss.txt") truncates file if already exists. So you need to use os.OpenFile function to append new content to already exists file.

how to convert string like "11aacc" to hex value []byte("\x11\xaa\cc") in golang

i want to use UDP to send packet with content like 0x11AACC, "11AACC" is fetched from database, so it's string.
I don't know how to change it to hex value 11AACC, if I use []byte("11AACC")to convert it, it'll change to 6 bytes content.
thanks.
You can use DecodeString from encoding/hex package to convert your hex string to []byte.
example: https://play.golang.org/p/t200M1LqJQ3
package main
import (
"encoding/hex"
"fmt"
"log"
)
func main() {
s := "11AACC"
h, err := hex.DecodeString(s)
if err != nil {
log.Fatal(err)
}
fmt.Println(h)
}
Link to DecodeString: https://golang.org/pkg/encoding/hex/#DecodeString

Golang for loop wont stop

So I am starting to learn the Go Programming Language and was hoping someone might be able to clarify why I'm getting the results I'm getting. I'm trying to have the program read input from the user and display it back until the user only enters the newline character.
package main
import (
"fmt"
"os"
"bufio"
"strings"
)
func main(){
inputBuff := bufio.NewReader(os.Stdin)
line,_ := inputBuff.ReadString('\n')
for (!strings.EqualFold(line,"\n")){
line,err := inputBuff.ReadString('\n')
if err!=nil {
fmt.Println(err)
}
fmt.Println(line)
fmt.Println(!strings.EqualFold(line,"\n"))
}
}
I am trying to read in full strings at a time so i thought the bufio would be better the using Scan. I added the last print to show that the method is returning false but the loop continues to execute. Any help would be greatly appreciated.
the line inside the loop is not the same line you initiated for the check. FTFY:
package main
import (
"fmt"
"os"
"bufio"
"strings"
)
func main(){
inputBuff := bufio.NewReader(os.Stdin)
line,_ := inputBuff.ReadString('\n')
var err error
for (!strings.EqualFold(line,"\n")){
line,err = inputBuff.ReadString('\n')
if err!=nil {
fmt.Println(err)
}
fmt.Println(line)
fmt.Println(!strings.EqualFold(line,"\n"))
}
You used the := assignment operator inside the loop, as in line, err := .....
This makes Go create a new symbol inside the the for loop with the name line. But the for's check is outside the inner scope of the loop code block. So it refers to the old line that was initiated outside the loop.
Changing the operator inside the loop to = doesn't create a new variable, but also doesn't init err, so I defined it beforehand too. err can be declared inside the loop but that's redundant.

In Go, how do I capture stdout of a function into a string?

In Python, for example, I can do the following:
realout = sys.stdout
sys.stdout = StringIO.StringIO()
some_function() # prints to stdout get captured in the StringIO object
result = sys.stdout.getvalue()
sys.stdout = realout
Can you do this in Go?
I agree you should use the fmt.Fprint functions if you can manage it. However, if you don't control the code whose output you're capturing, you may not have that option.
Mostafa's answer works, but if you want to do it without a temporary file you can use os.Pipe. Here's an example that's equivalent to Mostafa's with some code inspired by Go's testing package.
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)
}
This answer is similar to the previous ones but looks cleaner by using 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
}
I don't recommend this, but you can achieve it with altering os.Stdout. Since this variable is of type os.File, your temporary output should also be a file.
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))
}
I don't recommend because this is too much hacking, and not very idiomatic in Go. I suggest passing an io.Writer to the functions and writing outputs to that. This is the better way to do almost the same thing.
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)
}
I think the whole idea is not advisable (race condition) at all, but I guess one can mess with os.Stdout in a way similar/analogical to your example.
Even though the options listed above works, there is a clean approach in modern Go, that makes use of io.Pipe and io.Copy.
package main
import (
"bytes"
"fmt"
"io"
"os"
)
// Your function
func some_function(w *io.PipeWriter) {
defer w.Close()
// Fill pipe writer
fmt.Fprintln(w, "Hello World")
}
// main function
func main() {
// create a pipe reader and writer
pr, pw := io.Pipe()
// pass writer to function
go some_function(pw)
// custom buffer to get standard output of function
var b bytes.Buffer
// create a multi writer that is a combination of
// os.Stdout and variable byte buffer `b`
mw := io.MultiWriter(os.Stdout, &b)
// copies pipe reader content to standard output & custom buffer
_, err := io.Copy(mw, pr)
if err != nil {
if err != io.EOF {
panic(err)
}
}
// use variable
fmt.Println(b.String())
}
The above program works this way:
Create a pipe that gives a reader and writer. It means, if you write something into pipe writer, will be copied to pipe reader by go
Create a MultiWriter with os.Stdout and custom buffer b
some_function(as a go-routine) will write a string into pipe writer
io.Copy will then copy content from pipe reader into multi-writer
os.Stdout will receive the output as well as your custom buffer b
Use buffer b
io package comes with all batteries included to work with io.Reader and io.Writer. No need to use os package, unless files are involved.
Running snippet:
https://goplay.tools/snippet/3NcLVNmbEDd

Resources