func (s *AzBlockBlob) Write(p []byte) (n int, err error) {
	if s.blockBlobURL == nil {
		return 0, errWriteNotOpened
	}
	bytesWritten, writeError := s.pipeWriter.Write(p)
	if writeError != nil {
		s.pipeWriter.CloseWithError(err)
		return 0, writeError
	}
	return bytesWritten, nil
}
Write len(p) bytes from p
package azblob
import (
	"context"
	"errors"
	"io"
	"net/url"
	"github.com/Azure/azure-pipeline-go/pipeline"
	"github.com/Azure/azure-storage-blob-go/azblob"
	"github.com/xitongsys/parquet-go/source"
)
type AzBlockBlob struct {
	ctx          context.Context
	URL          *url.URL
	credential   azblob.Credential
	blockBlobURL *azblob.BlockBlobURL
	writeDone     chan error
	pipeReader    *io.PipeReader
	pipeWriter    *io.PipeWriter
	writerOptions WriterOptions
	fileSize      int64
	offset        int64
	readerOptions ReaderOptions
}
var (
	errWhence         = errors.New("Seek: invalid whence")
	errInvalidOffset  = errors.New("Seek: invalid offset")
	errReadNotOpened  = errors.New("Read: url not opened")
	errWriteNotOpened = errors.New("Write url not opened")
)
type ReaderOptions struct {
	HTTPSender pipeline.Factory
	RetryOptions azblob.RetryOptions
	Log pipeline.LogOptions
}
type WriterOptions struct {
	HTTPSender pipeline.Factory
	RetryOptions azblob.RetryOptions
	Log pipeline.LogOptions
	Parallelism int
}
func NewAzBlobFileWriter(ctx context.Context, URL string, credential azblob.Credential, options WriterOptions) (source.ParquetFile, error) {
	file := &AzBlockBlob{
		ctx:           ctx,
		credential:    credential,
		writerOptions: options,
	}
	return file.Create(URL)
}
func NewAzBlobFileReader(ctx context.Context, URL string, credential azblob.Credential, options ReaderOptions) (source.ParquetFile, error) {
	file := &AzBlockBlob{
		ctx:           ctx,
		credential:    credential,
		readerOptions: options,
	}
	return file.Open(URL)
}
func (s *AzBlockBlob) Seek(offset int64, whence int) (int64, error) {
	if whence < io.SeekStart || whence > io.SeekEnd {
		return 0, errWhence
	}
	switch whence {
	case io.SeekStart:
		offset = offset
	case io.SeekCurrent:
		offset = s.offset + offset
	case io.SeekEnd:
		offset = s.fileSize + offset
	}
	if offset < 0 || offset > s.fileSize {
		return 0, errInvalidOffset
	}
	s.offset = offset
	return s.offset, nil
}
func (s *AzBlockBlob) Read(p []byte) (n int, err error) {
	if s.blockBlobURL == nil {
		return 0, errReadNotOpened
	}
	if s.fileSize > 0 && s.offset >= s.fileSize {
		return 0, io.EOF
	}
	count := int64(len(p))
	resp, err := s.blockBlobURL.Download(s.ctx, s.offset, count, azblob.BlobAccessConditions{}, false, azblob.ClientProvidedKeyOptions{})
	if err != nil {
		return 0, err
	}
	if s.fileSize < 0 {
		s.fileSize = resp.ContentLength()
	}
	toRead := s.fileSize - s.offset
	if toRead > count {
		toRead = count
	}
	body := resp.Body(azblob.RetryReaderOptions{})
	bytesRead, err := io.ReadFull(body, p[:toRead])
	if err != nil {
		return 0, err
	}
	s.offset += int64(bytesRead)
	return bytesRead, nil
}