编码
json是go标准库里自带的序列化工具,使用了反射,效率比较低。
easyjson只针对预先定义好的json结构体对输入的json字符串进行纯字符串的截取,并将对应的json字段赋值给结构体。easyjson -all xxx.go 生成go文件中定义的结构体对应的解析,xxx.go所在的package不能是main。
func easyjson.Marshal(v easyjson.Marshaler) ([]byte, error)
func easyjson.Unmarshal(data []byte, v easyjson.Unmarshaler) error
sonic是字节跳动开源的json序列化工具包,号称性能强过easyjson、jsoniter,使用起来非常方便。
import "github.com/bytedance/sonic"
// Marshal
output, err := sonic.Marshal(&data)
// Unmarshal
err := sonic.Unmarshal(input, &data)
base64经常在http环境下用来传输较长的信息。任意byte数组都可以采用base64编码转为字符串,并且可以反解回byte数组。编码和解码的方法是公开、确定的, base64不属于加密算法。
func (*base64.Encoding).EncodeToString(src []byte) string
func (*base64.Encoding).DecodeString(s string) ([]byte, error)
compress包下实现了zlib、bzip、gip、lzw等压缩算法。
writer := zlib.NewWriter(fout)//压缩
writer.Write(bytes)
reader, err := zlib.NewReader(fin) //解压
io.Copy(os.Stdout, reader) //把reader流里的内容拷贝给标准输出流,即文件解压后的内容打印到控制台
func compressDemo() error {
fin, err := os.Open("aa.go")
if err != nil {
return err
}
defer fin.Close()
stat, _ := fin.Stat()
fmt.Printf("压缩前文件的大小 %d B\n", stat.Size())
fout, err := os.OpenFile("go.zlib", os.O_CREATE|os.O_WRONLY, 0777)
if err != nil {
return err
}
defer fout.Close()
bs := make([]byte, 1024)
writer := zlib.NewWriter(fout)
for {
n, err := fin.Read(bs)
if err == nil {
writer.Write(bs[:n])
} else {
if err == io.EOF {
break
} else {
fmt.Println(err)
break
}
}
}
writer.Close()
fin, err = os.Open("go.zlib")
if err != nil {
return err
}
defer fin.Close()
stat, _ = fin.Stat()
fmt.Printf("压缩后文件的大小 %d B\n", stat.Size())
reader, err := zlib.NewReader(fin)
if err != nil {
return err
}
io.Copy(os.Stdout, reader)
reader.Close()
fin.Close()
return nil
}
homework
1. 把字符串1998-10-01 08:10:00解析成time.Time,再格式化成字符串199810010810
2. 我们是每周六上课,输出我们未来4次课的上课日期(不考虑法定假日)
3. 把一个目录下的所有.txt文件合一个大的.txt文件,再对这个大文件进行压缩
4. 自己实现一个BufferedFileWriter
format1 := "2006-01-02 15:04:05"
format2 := "20060102150405"
s := "1998-10-01 08:10:00"
loc, _ := time.LoadLocation("Asia/Shanghai")
t, _ := time.ParseInLocation(format1, s, loc)
fmt.Println(t)
t2 := t.Format(format2)
fmt.Println(t2)
2. 我们是每周六上课,输出我们未来4次课的上课日期(不考虑法定假日)
func getDay() {
now := time.Now()
sub := 6 - int(now.Weekday())
interval := sub
if sub == 0 {
interval = 7
}
Satuday := now.Add(24 * time.Duration(interval) * time.Hour)
fmt.Println(Satuday.Format("2006-01-02"))
for i := 0; i < 3; i++ {
Satuday = Satuday.Add(24 * 7 * time.Hour)
fmt.Println(Satuday.Format("2006-01-02"))
}
}
3. 把一个目录下的所有.txt文件合一个大的.txt文件,再对这个大文件进行压缩
func readFile(inPath string, writer *bufio.Writer, writer2 *zlib.Writer) {
if fin, err := os.Open(inPath); err != nil {
fmt.Println(err)
return
} else {
defer fin.Close()
reader := bufio.NewReader(fin)
for {
if line, err := reader.ReadString('\n'); err != nil {
if err == io.EOF {
if len(line) > 0 {
//文件最后一行末尾没有换行符
writer.WriteString(line)
writer.WriteString("\n")
writer2.Write([]byte(line))
writer2.Write([]byte{
'\n'})
}
}
break
} else {
writer.WriteString(line)
writer2.Write([]byte(line))
}
}
}
}
func mergeFile(dir string) {
fout, err := os.OpenFile("big.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
if err != nil {
fmt.Println(err)
return
}
defer fout.Close()
writer := bufio.NewWriter(fout)
fout2, err := os.OpenFile("big.zlib", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
if err != nil {
fmt.Println(err)
return
}
defer fout2.Close()
writer2 := zlib.NewWriter(fout2) //需要切片,先转成切片在压缩
if files, err := ioutil.ReadDir(dir); err != nil {
//ReadDir只能读一级子目录
fmt.Println(err)
return
} else {
for _, file := range files {
if file.IsDir() {
continue
}
baseName := file.Name()
if strings.HasSuffix(baseName, ".txt") {
inPath := filepath.Join(dir, baseName)
readFile(inPath, writer, writer2)
}
}
}
writer.Flush()
writer2.Flush()
}
4. 自己实现一个BufferedFileWriter
type BufferedFileWriter struct {
buffer [1024]byte
endPos int // 当前写到buffer的什么位置了,切片的len是固定的,所以没法用len来求出写到什么位置
fileHandler *os.File
}
func NewBufferedFileWriter(fd *os.File) *BufferedFileWriter {
return &BufferedFileWriter{
fileHandler: fd,
}
}
func (writer *BufferedFileWriter) Flush() {
if writer.endPos > 0 {
writer.fileHandler.Write(writer.buffer[:writer.endPos])
writer.endPos = 0
}
}
func (writer *BufferedFileWriter) Write(content []byte) {
if len(content) >= 1024 {
writer.Flush()
writer.fileHandler.Write(content)
} else {
if writer.endPos+len(content) >= 1024 {
writer.Flush()
writer.Write(content)
} else {
copy(writer.buffer[writer.endPos:], content)
writer.endPos += len(content)
}
}
}
func (writer *BufferedFileWriter) WriterString(content string) {
writer.Write([]byte(content))
}
func testBufferWriter() {
fout, err := os.OpenFile("shiyi.txt", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, os.ModePerm)
if err != nil {
fmt.Println(err)
return
}
defer fout.Close()
writer := NewBufferedFileWriter(fout)
for i := 0; i < 5; i++ {
writer.WriterString("1666\n")
}
writer.Flush()
}