This is a creation in Article, where the information may have evolved or changed.
"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org
to the public or website http://www.flysnow.org/, the first time to see follow-up notes. If you feel helpful, share it with your friends and thank you for your support.
Input and output
The Go Writer and reader interfaces are designed to follow UNIX input and output, and the output of one program can be an input to another program. They are simple and pure, so they can be very easy to write program code, but also through the concept of combinatorial, let our program do more things.
For example, in the previous go log log http://www.flysnow.org/2017/05/06/go-in-action-go-log.html, we introduced the UNIX three input and output input modes, They have a specific implementation in their corresponding go language.
12345 |
var (Stdin = NewFile (uintptr"/dev/stdin") Stdout = NewFile (uintptr"/dev/stdout" ) Stderr = NewFile (uintptr"/dev/stderr")) |
The input and output of these three standards is one *File
, and *File
exactly is the type of the io.Writer
io.Reader
two interfaces, so they have both input and output functions, can read from the inside of the data, but also to write data inside.
The Go standard library IO package is also based on the UNIX input and output concept, most of the interfaces are extended io.Writer
and io.Reader
, most of the types are also selected to implement io.Writer
and io.Reader
the two interfaces, and then the data input and output, abstract as a stream of read and write, So as long as the two interfaces are implemented, both the read and write functions of the stream can be used.
io.Writer
and io.Reader
two interfaces of the high abstraction, let us no longer face the specific business, we only focus on, is read or write, as long as we define the method function can receive the two interfaces as parameters, then we can do the stream read and write, without care about how the reading, where to write, this is the benefit of interface programming.
Reader and writer interfaces
These two highly abstract interfaces, with only one method, also embody the simplicity of the Go interface design and only do a thing.
123456789101112 |
// Writer is the interface that wraps the basic Write method. // //Write writes Len (p) bytes from p to the underlying data stream. //It returns the number of bytes written from p (0 <= n <= len (p)) //and any error encountered this caused the write to stop early. //Write must return a non-nil error if it returns n < Len (p). //Write must not modify the slice data, even temporarily. // //implementations must not retain p. type Writer interface {Write (p []byte ) (n int , err Error)} |
This is Wirter
the definition of the interface, it has only one Write
method, accepts a byte slice, returns two values, n
indicates the number of bytes written, and err
indicates the error that occurred while writing.
From its documentation annotations, this approach is prescriptive, and if we want to implement an interface, we need to io.Writer
follow these rules.
- The Write method writes Len (p) bytes of data to the underlying data stream, which is derived from the slice p
- Returns the number of bytes written n,0 <= n <= len (p)
- If N<len (p), you must return some non-nil err
- Return non-nil err if there is a problem in the middle
- The Write method must never modify the slice p and the data inside
These implementations io.Writer
of the interface rules, all of which implement the type of the interface to abide by, otherwise it may lead to inexplicable problems.
12345678910111213141516171819202122232425262728293031 |
//Reader is the interface that wraps the basic Read method.////Read reads up to Len (p) bytes into p. It returns the number of bytes//Read (0 <= n <= len (p)) and any error encountered. Even if Read///returns n < Len (p), it may use any of the p as scratch space during the call.//If Some data is available and not Len (p) bytes, Read conventionally//returns what's available instead of waiting for more.////When Read encounters a error or End-of-file condition after//successfully reading n > 0 bytes, it returns the number of//bytes read. It may return the (Non-nil) error from the same call//or return the error (and n = = 0) from a subsequent call.//An instance of the this general case was that a Reader returning//A non-zero number of bytes at the end of the input stream may//return either err = = EOF or err = nil. The next Read should//Return 0, EOF.////callers should always process the N > 0 bytes returned before//Considering the error err. Doing so correctly handles I/O errors//That happen after reading some bytes and also both of the//Allowed EOF behaviors.////implementations of Read is discouraged from returning a//Zero byte count with a nil error, except when Len (p) = = 0.//callers should treat a return of 0 and nil as indicating that//Nothing happened, in particular it does not indicate EOF.////implementations must not retain p.typeReaderInterface{Read (P []byte) (nint, err Error)} |
This is the io.Reader
interface definition, and there is only one read method, this method accepts a byte slice, and returns two values, one is the number of bytes read, and the other is the ERR error.
From its annotated document, there io.Reader
are more rules for interfaces.
- Read reads a maximum of Len (p) bytes of data and saves it to p.
- Returns the number of bytes read and any error messages that occurred
- N to meet 0 <= N <= len (p)
- N<len (p), indicates that the data read is not sufficient to fill p, and the method returns immediately instead of waiting for more data
- Error encountered during reading, the number of bytes read n and corresponding error is returned err
- At the end of the underlying input stream, the method returns n>0 bytes, but err may be EOF or nil
- In the 6th (above) case, when the Read method is called again, it will definitely return 0,eof
- When calling the Read method, if n>0, processing the read-in data first, and then processing the error err,eof to do the same
- The Read method does not encourage the return of n=0 and Err=nil cases,
The rule is Write
a little bit more than the interface, but it is also better understood, note 8th, even if we encountered errors while reading, but also should deal with the data already read, because these have read the data is correct, if not processed lost, the reading of the data is not complete.
"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org
to the public or website http://www.flysnow.org/, the first time to see follow-up notes. If you feel helpful, share it with your friends and thank you for your support.
Example
After understanding the two interfaces, we can try to use them, and now look at an example.
1234567891011 |
func main () {//define 0 value buffer type variable b var b bytes. Buffer//use the Write method to write the string b.write ([]byte ( "Hello" )) //this is to stitch a string into buffer FMT. Fprint (&b,, " http://www.flysnow.org ") //print the contents of buffer to the terminal console b.writeto (OS. Stdout)} |
This example is the concatenation of strings into Buffer
, and then output to the console, this example is very simple, but the use of the stream read and write, bytes.Buffer
is a variable byte type, can make it easy for us to operate on the byte, such as read and write, append and so on. bytes.Buffer
implementation io.Writer
and io.Reader
interface, so I can easily read and write operations, instead of focusing on specific implementations.
b.Write([]byte("你好"))
Implemented to write a string, we convert the string to a byte slice, and then invoke the Write
method to write, which is implemented bytes.Buffer
to implement io.Writer
the interface, a method that can help us write to the data stream.
12345 |
func (b *buffer) Write (p []byte) int, err error) {B.lastread = Opinvalidm: = B.grow (len(p))returncopynil} |
The above bytes.Buffer
is io.Writer
the way to implement the interface, and finally we see that we write the slices will be copied into the b.buf
, where the b.buf[m:]
copy is actually added meaning, will not overwrite the existing data.
From the implementation point of view, we found that only the b *Buffer
pointer implements the io.Writer
interface, so when we call the function in the sample code fmt.Fprint
, we pass an address &b
.
1234567 |
func Fprint (w io.) Writer, a ... Interface {})int, err error) {p: = Newprinter () p.doprint (a) n, err = W.write (p.buf) p.free ()return } |
This is the function fmt.Fprint
of the implementation, its function is to write data a
to an io.Writer
interface implementation, specifically how to write, it is not concerned about, because it io.Writer
will do, it only care can be written. w.Write(p.buf)
called Wirte
Method writes.
Finally, the b.WriteTo(os.Stdout)
final data is exported to the standard os.Stdout
, so that we can see the output, it receives an io.Writer
interface type parameters, the beginning we talked about os.Stdout
the implementation of this io.Writer
interface, so it is possible to pass as a parameter.
Here we will find that many methods of receiving parameters are io.Writer
interfaces, of course, there are io.Reader
interfaces, which is interface-oriented programming, we do not have to focus on the implementation, only with the attention of this interface can do what things, if we switch to output to the file, then it is very easy, just use the os.File
Type as a parameter. Any type that implements the interface can be used as a parameter.
In addition b.WriteTo
to the method, we can also use the io.Reader
interface method to Read
achieve the data read.
123 |
var p [+]byten,err:=b.read (p[:]) fmt. Println (N,err,string(P[:n])) |
This is the most primitive method, using the Read
method, n is the number of bytes read, and then we print out the output.
Because byte.Buffer
pointers implement io.Reader
interfaces, we can also read data information in the following ways.
12 |
Data,err:=ioutil. ReadAll (&b) fmt. Println (string(data), err) |
ioutil.ReadAll
Interface io.Reader
is an interface parameter that indicates that all data can be read from any type that implements the io.Reader
interface.
123456789101112131415161718 |
func readall(r io. Reader, capacity int64) (b []byte, err error) {buf: = bytes. Newbuffer ( Make([]byte,0, capacity))//If The buffer overflows, we'll get bytes. Errtoolarge.//Return that as an error. Any other panic remains.defer func() {e: =Recover()ifE = =Nil{return}ifPanicerr, OK: = E. (error); Ok && panicerr = = bytes. Errtoolarge {err = Panicerr}Else{Panic(e)}} () _, err = buf. Readfrom (R)returnBuf. Bytes (), err} |
The above is the ioutil.ReadAll
implementation of the source code, but also very simple, the basic principle is to create a byte.Buffer
, through this byte.Buffer
ReadFrom
method, the io.Reader
data in the reading, and finally through byte.Buffer
the Bytes
method to return the final read bytes of data information.
The entire stream read and write has been completely abstracted, io
most of the operation and type of the package is based on these two interfaces, and of course, HTTP and other involved in data flow, file flow, etc., can be fully used io.Writer
and io.Reader
interface to represent, through the connection between the two interfaces, We can implement any data read and write.
"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org
to the public or website http://www.flysnow.org/, the first time to see follow-up notes. If you feel helpful, share it with your friends and thank you for your support.