Documentation ¶
Index ¶
Examples ¶
Constants ¶
const ( // DefBufSize is the default buffer size. DefBufSize = uint(32 * 1024) // DefaultInterval is the default interval to report count of written bytes. DefaultInterval = 500 * time.Millisecond )
Variables ¶
This section is empty.
Functions ¶
func Start ¶
func Start( ctx context.Context, dst io.Writer, src io.Reader, bufSize uint, total uint64, interval time.Duration) <-chan Event
Start returns a channel for the caller to receive IO copy events and start a goroutine to do IO copy. ctx: context.Context. It can be created using context.WithCancel, context.WithDeadline, context.WithTimeout... dst: io.Writer to copy to. src: io.Reader to copy from. bufSize: size of the buffer. It'll create a buffer in the new goroutine according to the buffer size. total: total number of bytes to copy. Set it to 0 if it's unknown. interval: It'll create a time.Ticker by given interval to send the EventWritten event to the channel during the IO copy. A negative or zero duration causes it to stop the ticker immediately. In this case, it'll send the EventWritten to the channel only once when IO copy succeeds. You may set it to DefaultInterval.
It returns a channel to receive IO copy events. Available events:
(1). n bytes have been written successfully. It'll send an EventWritten to the channel.
(2). an error occured It'll send an EventError to the channel and close the channel.
(3). IO copy stopped(context is canceled or context's deadline exceeded). It'll send an EventStop to the channel and close the channel.
(4). IO copy succeeded. It'll send an EventOK to the channel and close the channel.
You may use a for-range loop to read events from the channel.
Example ¶
package main import ( "context" "crypto/sha256" "fmt" "log" "net/http" "strconv" "time" "github.com/northbright/iocopy" ) func main() { // Example of iocopy.Start() // It reads a remote file and calculates its SHA-256 hash. // It shows how to read events and process them from the event channel. // URL of remote file. // SHA-256: 9e2f2a4031b215922aa21a3695e30bbfa1f7707597834287415dbc862c6a3251 downloadURL := "https://golang.google.cn/dl/go1.20.1.darwin-amd64.pkg" // Do HTTP request and get the response. resp, err := http.Get(downloadURL) if err != nil { log.Printf("http.Get() error: %v", err) return } // Check status code. if resp.StatusCode != 200 && resp.StatusCode != 206 { log.Printf("status code is not 200 or 206") return } // response.Body is an io.ReadCloser. // Do not forget to close the body. defer resp.Body.Close() // Get remote file size. contentLength := resp.Header.Get("Content-Length") total, _ := strconv.ParseUint(contentLength, 10, 64) if total <= 0 { log.Printf("Content-Length <= 0: %v", total) return } // Create a hash.Hash for SHA-256. // hash.Hash is an io.Writer. hash := sha256.New() // create a context. // It can be created by context.WithCancel, context.WithDeadline, // context.WithTimeout... // You may test timeout context. // The IO copy will be stopped // and an EventStop will be sent to the channel. // event.Err() will return "context deadline exceeded". // ctx, cancel := context.WithTimeout(context.Background(), 1200*time.Millisecond) // defer cancel() // Use background context by default. // IO copy should succeed and an EventOK will be sent to the channel. ctx := context.Background() // Start a goroutine to do IO copy. // Read from response.Body and write to hash.Hash to compute hash. ch := iocopy.Start( // Context ctx, // Writer(dst) hash, // Reader(src) resp.Body, // Buffer size 16*1024*1024, // Total size, set it to 0 if it's unknown. total, // Interval to report written bytes 500*time.Millisecond) // Read the events from the channel. for event := range ch { switch ev := event.(type) { case *iocopy.EventWritten: // n bytes have been written successfully. // Get the count of bytes. n := ev.Written() percent := ev.Percent() log.Printf("on EventWritten: %v/%v bytes written(%.2f%%)", n, total, percent) case *iocopy.EventStop: // Context is canceled or // context's deadline exceeded. // Get EventWritten from EventStop. ew := ev.EventWritten() // Get the number of written bytes and percent. n := ew.Written() percent := ew.Percent() log.Printf("on EventStop: %v, %v/%v bytes written(%.2f%%)", ev.Err(), n, total, percent) case *iocopy.EventError: // an error occured. // Get the error. log.Printf("on EventError: %v", ev.Err()) case *iocopy.EventOK: // IO copy succeeded. // Get EventWritten from EventOK. ew := ev.EventWritten() // Get the number of written bytes and percent. n := ew.Written() percent := ew.Percent() log.Printf("on EventOK: %v/%v bytes written(%.2f%%)", n, total, percent) // Get the final SHA-256 checksum of the remote file. checksum := hash.Sum(nil) fmt.Printf("SHA-256:\n%x", checksum) } } // The event channel will be closed after: // (1). iocopy.EventError received. // (2). iocopy.EventStop received. // (3). iocopy.EventOK received. // The for-range loop exits when the channel is closed. log.Printf("IO copy gouroutine exited and the event channel is closed") }
Output: SHA-256: 9e2f2a4031b215922aa21a3695e30bbfa1f7707597834287415dbc862c6a3251
Types ¶
type Event ¶
type Event interface { // stringer String() string }
Event is the interface that wraps String method. When Start is called, it'll return a channel for the caller to receive IO copy related events. Currently, there're 4 types of events: (1). EventWritten - n bytes have been written successfully. (2). EventError - an error occurs and the goroutine exits. (3). EventStop - IO copy stopped. (4). EventOK - IO copy succeeded.
type EventError ¶
type EventError struct {
// contains filtered or unexported fields
}
EventError is the event that an error occurs.
func (*EventError) Err ¶
func (e *EventError) Err() error
Err returns the error occured during IO copy.
func (*EventError) String ¶
func (e *EventError) String() string
String implements the stringer interface.
type EventOK ¶
type EventOK struct {
// contains filtered or unexported fields
}
EventOK is the event that IO copy succeeded.
func (*EventOK) EventWritten ¶ added in v1.6.0
func (e *EventOK) EventWritten() *EventWritten
EventWritten returns the contained EventWritten event, which can be used to call Written, Total, Percent method on it.
type EventStop ¶ added in v1.1.0
type EventStop struct {
// contains filtered or unexported fields
}
EventOK is the event that IO copy stopped.
func (*EventStop) Err ¶ added in v1.1.0
Err returns the the context error that explains why IO copying is stopped. It can be context.Canceled or context.DeadlineExceeded.
func (*EventStop) EventWritten ¶ added in v1.6.0
func (e *EventStop) EventWritten() *EventWritten
EventWritten returns the contained EventWritten event, which can be used to call Written, Total, Percent method on it.
type EventWritten ¶
type EventWritten struct {
// contains filtered or unexported fields
}
EventWritten is the event that n bytes have been written successfully.
func (*EventWritten) Percent ¶ added in v1.6.0
func (e *EventWritten) Percent() float32
Percent returns the percentage of the progress. It's always 0 when total is 0.
func (*EventWritten) String ¶
func (e *EventWritten) String() string
String implements the stringer interface.
func (*EventWritten) Total ¶ added in v1.6.0
func (e *EventWritten) Total() uint64
Total returns the total number of bytes to copy. It's the same as total argument of Start.
func (*EventWritten) Written ¶
func (e *EventWritten) Written() uint64
Written returns the number of bytes written successfuly.