go 代码练习
1.1 把一个int32的数换算成二进制
//作业1,把一个int32的数换算成二进制
package main
import (
"fmt"
"math"
"strings"
)
func main() {
fmt.Println(BinaryFormat(0))
fmt.Println(BinaryFormat(-1))
fmt.Println(BinaryFormat(1))
fmt.Println(BinaryFormat(260))
fmt.Println(BinaryFormat(-260))
}
//输出一个int32对应的二进制表示
func BinaryFormat(n int32) string {
a := uint32(n) //将int32类型的数值转换成无符号的uint32类型
sb := strings.Builder{} //拼接字符串的函数
c := uint32(math.Pow(2, 31)) //二进制为:10000000 00000000 00000000 00000000
for i := 0; i < 32; i++ {
if a&c > 0 {
sb.WriteString("1")
} else {
sb.WriteString("0")
}
c >>= 1 //每次右偏移量1和n的二进制进行比对
//fmt.Printf("当前二进制是%b<<<<<<<<<<\n",c)
}
//fmt.Printf("%d的二进制是%b,%d的十进制是%d\n", n, a, n, n)
//fmt.Printf("2的31次方的二进制是%b,十进制是%d\n", c, c)
return sb.String()
}
2.1 把字符串1998-10-01 08:10:00解析成time.Time,再格式化成字符串199810010810
//1. 把字符串1998-10-01 08:10:00解析成time.Time,再格式化成字符串199810010810
func timeshow() {
format1 := "2006-05-16 09:53:03" //第一种时间格式模板
format2 := "20060116095303" //第一种时间格式模板
dt := "1998-10-01 08:10:00"
loc,_ := time.LoadLocation("Asia/Shanghai")
t,_ := time.ParseInLocation(format1, dt,loc) //解析成time.Time根据时区
t1 := t.Format(format2) //格式化时间
fmt.Println(t1)
}
func main() {
timeshow()
}
3.1 我们是每周六上课,输出我们未来4次课的上课日期(不考虑法定假日)
//1.我们是每周六上课,输出我们未来4次课的上课日期(不考虑法定假日)
func workday() {
now := time.Now()
days := int(time.Saturday - now.Weekday())
fmt.Println(days)
if days == 0 {
days = 7
}
workday1 := now.Add(24 * time.Hour * time.Duration(days)) //time.Hour的类型是Duration,所以需要把days也转换成这种类型
fmt.Println(workday1)
for i := 1;i < 3;i ++ {
workday1 = workday1.Add(24 * time.Hour * 7) //time.Hour的类型是Duration,所以需要把days也转换成这种类型
fmt.Println(workday1)
}
}
func main() {
workday()
}
4.1 并发读取多个文件夹下的内容,并发写入一个文件内,没有先后顺序
//多个文件合成一个文件,并发实现,不用考虑内容的顺序,子协程要优雅退出
var fileChan = make(chan string,10000)
//定义读结束的管道
var readChanFinsh = make(chan struct{})
//定义读结束的管道
var writeChanFinsh = make(chan struct{})
var wg sync.WaitGroup
func readFile(filename string) {
defer func() {
wg.Done()
}()
//打开文件
fin,err := os.Open(filename)
if err != nil {
fmt.Println(err.Error())
return
}
defer fin.Close()
//构建fileReader
reader := bufio.NewReader(fin)
for {
line,err := reader.ReadString('\n')
if err != nil {
//如果最后是EOF,end of file
if err == io.EOF{
//查看最后一行长度是否是空行
if len(line) >0 {
line += "\n"
fileChan <- line
fmt.Printf("write %s to fileChan\n",line)
}
break
} else {
fmt.Println(err)
break
}
}else {
fmt.Printf("write %s to fileChan\n",line)
fileChan <- line
}
}
}
func writeFile(filename string) {
defer close(writeChanFinsh) //程序退出前关闭写的管道
fout,err := os.OpenFile(filename,os.O_CREATE|os.O_TRUNC|os.O_WRONLY,os.ModePerm)
if err != nil {
fmt.Println(err)
}
defer fout.Close()
writer := bufio.NewWriter(fout) //定义writer,写入数据到filename 中
LOOP:
for {
select {
case <- readChanFinsh: //大部分时间管道是阻塞的,因为需要wg计时三次读完关闭后才会立刻返回
close (fileChan) //当读结束的管道关闭后,关闭fileChan的管道,需要遍历fileChan里面,看看有没有写操作没消化完的残留
fmt.Println(len(fileChan)) //打印写消化完后的残留长度
for line := range fileChan{ //遍历管道,读取写残留的并写入
writer.WriteString(line)
}
fmt.Println("读结束的管道已经关闭,退出循环前已经遍历管道剩余内容并写入了,管道已清零")
break LOOP
case line := <-fileChan: //如果fileChan中有数据,就写入
fmt.Printf("read %s from fileChan\n",line)
writer.WriteString(line)
}
}
writer.Flush() //写完刷新磁盘
}
func main() {
wg.Add(3)
for i := 1;i <= 3;i++ {
fileName := "C:\\Users\\丽丽小可爱\\Desktop\\代码勿删\\go\\测试\\"+strconv.Itoa(i)
go readFile(fileName) //go协程并不会像main一样打印信息,而是把信息隐藏,所以read部分并不会打印
}
wg.Wait()
go writeFile("C:\\Users\\丽丽小可爱\\Desktop\\代码勿删\\go\\测试\\merge")
close(readChanFinsh)
<-writeChanFinsh
}
例子2:
//多个文件合成一个文件,并发实现,不用考虑内容的顺序,子协程要优雅退出
var fileChan = make(chan string,10000)
//定义读结束的管道
//var readChanFinsh = make(chan struct{})
//定义读结束的管道
var writeChanFinsh = make(chan struct{})
var wg sync.WaitGroup
func readFile(filename string) {
defer func() {
wg.Done()
}()
//打开文件
fin,err := os.Open(filename)
if err != nil {
fmt.Println(err.Error())
return
}
defer fin.Close()
//构建fileReader
reader := bufio.NewReader(fin)
for {
line,err := reader.ReadString('\n')
if err != nil {
//如果最后是EOF,end of file
if err == io.EOF{
//查看最后一行长度是否是空行
if len(line) >0 {
line += "\n"
fileChan <- line
fmt.Printf("write %s to fileChan\n",line)
}
break
} else {
fmt.Println(err)
break
}
}else {
fmt.Printf("write %s to fileChan\n",line)
fileChan <- line
}
}
}
func writeFile(filename string) {
defer close(writeChanFinsh) //程序退出前关闭写的管道
fout,err := os.OpenFile(filename,os.O_CREATE|os.O_TRUNC|os.O_WRONLY,os.ModePerm)
if err != nil {
fmt.Println(err)
}
defer fout.Close()
writer := bufio.NewWriter(fout) //定义writer,写入数据到filename 中
//LOOP:
// for {
// select {
// case <- readChanFinsh: //大部分时间管道是阻塞的,因为需要wg计时三次读完关闭后才会立刻返回
// close (fileChan) //当读结束的管道关闭后,关闭fileChan的管道,需要遍历fileChan里面,看看有没有写操作没消化完的残留
// fmt.Println(len(fileChan)) //打印写消化完后的残留长度
// for line := range fileChan{ //遍历管道,读取写残留的并写入
// writer.WriteString(line)
// }
// fmt.Println("读结束的管道已经关闭,退出循环前已经遍历管道剩余内容并写入了,管道已清零")
// break LOOP
// case line := <-fileChan: //如果fileChan中有数据,就写入
// fmt.Printf("read %s from fileChan\n",line)
// writer.WriteString(line)
// }
// }
for { //这一段for优化掉了上面一坨,还去掉了一个read结束的管道,代码更简洁
if line,ok := <- fileChan;ok { //判断管道中是否还有数据,有数据的话就写入
writer.WriteString(line)
} else { //如果管道中没有数据了,就break
break
}
}
writer.Flush() //写完刷新磁盘
}
func main() {
wg.Add(3)
for i := 1;i <= 3;i++ {
fileName := "C:\\Users\\丽丽小可爱\\Desktop\\代码勿删\\go\\测试\\"+strconv.Itoa(i)
go readFile(fileName) //go协程并不会像main一样打印信息,而是把信息隐藏,所以read部分并不会打印
}
wg.Wait()
go writeFile("C:\\Users\\丽丽小可爱\\Desktop\\代码勿删\\go\\测试\\merge")
//close(readChanFinsh)
<-writeChanFinsh
}