go 代码练习

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
}
posted @ 2022-05-14 20:09  liwenchao1995  阅读(100)  评论(0编辑  收藏  举报