This is the second and last part of the series of articles explaining Data Streams in Golang. If you have not read the first part, you can find it here.
As discussed in the last part, we meet certain use cases wherein we have read data from a source that are not static, and we use Readers for that.
On similar grounds, we also need to write data continuously to a data sink and we use Writer to serve the purpose.

A writer streams data from the buffer and writes it to a sink or target.

The io.Writer

In golang, a writer is represented by the  io.Writer interface. All the writers must satisfy the io.Writer interface and for doing so, they have to implement the Write(p []byte) function.

type Writer interface {
   Write(p []byte) (n int, err error)
 }

 

The function Write is supposed to read the data from the byte array p  (buffer) and write it to the target source/ sink.  It also returns the n number of bytes written, or any error encountered while writing the bytes.

 

Standard Library Writers

As in the case of readers, the golang standard library provides many pre-implemented io.Writer types, that are more than enough to solve day to day problems.

bytes.Buffer is one type that implements io.Writer . It can be used to write data in-memory buffer. Let us take a look at a simple example.

func main() {
 fruits := []string{
        "Apple",
        "Banana",
        "Pear"
  }
 
 var fruitWriter := bytes.Buffer
 for _, fruit := range fruits {
    n, err := fruitWriter.Write([]byte(fruit))
    if err != nil {
       fmt.Println(err)
     }
     if n != len(fruit) {
       fmt.Println("not able to write fruit name")
     }
   }
}

Let us try to understand what happened here.
We began with initializing a string array containing names of fruits.

Then we made an instance of type bytes.Buffer called fruitWriter.
Then we iterate over each fruit name in the array and call the fruitWriter.Write function to write the fruit name in the memory buffer.
Last we check if the returned n (number of bytes written by the writer) is equal to the length of the fruit name or not, to make sure if our writer was able to write the complete name into the memory or not.

And that is it, it is this simple to use a pre-implemented writer function.

 

Custom io.Writer

In this section, we try to implement a custom io.Writer . This writer will write the data bytes into a byte array. Please note that is just an example, and in no way is the most optimized way of achieving this task.

 

 

 

type Ob struct {
  Data []byte
}

func GetNewOb() *Ob {
  return &Ob{Data: make([]byte, 1024)}
}

func (o *Ob) Write(p []byte) (n int, err error) {
  n = 0
  for _, d := range p {
     o.Data = append(o.Data, d)
     n++
  }
 return n, nil
}

func main() {
  ob := GetNewOb()
  fruits := []string{"Apple", "Banana", "Pear"}
  for _, fruit := range fruits {
    n, err := ob.Write([]byte(fruit))
    if err != nil {
      fmt.Println(err)
    }
    if n != len(fruit) {
      fmt.Println("not able to write fruit name")
     }
 }
fmt.Println(string(ob.Data))
}


And this is how we handle the Data Streams in Golang. For more articles on Golang, please make sure to go through other articles on Golang.


0 Comments

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *