Golang-C1-7

作业classroom

语言指数

https://tiobe.com/tiobe-index/

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import "log"

var classrooms map[string]*ClassRoom

type Student struct {
	Name string
	Id int
}

type ClassRoom struct {
	students map[string]*Student
}

func (c *ClassRoom) List() {

}

func (c *ClassRoom) Add(name string, id int) err {
	return nil
}

func save() error {
	string(classrooms)
	return nil
}

func main() {
	classrooms = make(map[string]*ClassRoom)
	classroom1 := &ClassRoom{
		students: make(map[string]*Student),
	}
	classroom1.Add("lchen", 1)
	
	classrooms["mulinux"] = classroom1
	
	if err := save(); err != nil {
		log.Fatal(err)
	}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import "log"

var classrooms map[string]*ClassRoom

type Student struct {
	Name string
	Id int
}

type ClassRoom struct {
	students map[string]*Student
}

func (c *ClassRoom) List() {

}

func (c *ClassRoom) Add(name string, id int) err {
	return nil
}

func save() error {
	//buf, err := json.Marshal()
	return nil
}

func main() {
	classrooms = make(map[string]*ClassRoom)
	classroom1 := &ClassRoom{
		students: make(map[string]*Student),
	}
	classroom1.Add("lchen", 1)
	classroom1.List()
	
	classrooms["mulinux"] = classroom1
	
	if err := save(); err != nil {
		log.Fatal(err)
	}
}

classroom.go

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

var classrooms map[string]*ClassRoom
var currentClassRoom *ClassRoom

type Student struct {
	Name string
	Id   int
}

type ClassRoom struct {
	teacher  string
	students map[string]*Student
}

func (c *ClassRoom) MarshalJSON() ([]byte, error) {
	m := make(map[string]interface{})
	m["teacher"] = c.teacher
	m["students"] = c.students
	return json.Marshal(m)
}

func (c *ClassRoom) UnmarshalJSON(buf []byte) error {
	return json.Unmarshal(buf, &c.students)
}

func (c *ClassRoom) List() {
	for _, stu := range c.students {
		fmt.Println(stu.Name, stu.Id)
	}
}

func (c *ClassRoom) Add(name string, id int) error {
	c.students[name] = &Student{
		Name: name,
		Id:   id,
	}
	return nil
}

func (c *ClassRoom) Update(name string, id int) error {
	if stu, ok := c.students[name]; ok {
		c.students[name] = &Student{
			Name: name,
			Id:   id,
		}

		c.students[name].Id = id
		stu.Id = id
	} else {
		///
	}
	return nil
}

func save() error {
	buf, err := json.Marshal(classrooms)
	if err != nil {
		return err
	}
	fmt.Println(string(buf))
	return nil
}

func choose(args []string) error {
	name := args[0]
	if classroom, ok := classrooms[name]; ok {
		currentClassRoom = classroom
	} else {
		//
	}
}

func add(args []string) error {
	name := "" //
	id := 0    //
	currentClassRoom.Add(name, id)
}

func main() {
	classrooms = make(map[string]*ClassRoom)

	classroom1 := &ClassRoom{
		students: make(map[string]*Student),
	}
	classroom1.Add("binggan", 1)
	fmt.Println("students of classroom 51reboot")
	classroom1.List()

	classroom2 := &ClassRoom{
		students: make(map[string]*Student),
	}
	classroom2.Add("binggan", 2)
	fmt.Println("students of classroom golang")
	classroom2.List()

	classrooms["51reboot"] = classroom1
	classrooms["golang"] = classroom2

	if err := save(); err != nil {
		log.Fatal(err)
	}
}

tar.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package main

import (
	"archive/tar"
	"io"
	"log"
	"os"
	"path/filepath"
)

func maketar(dir string, w io.Writer) error {
	base := filepath.Base(dir)
	tr := tar.NewWriter(w)
	defer tr.Close()
	return filepath.Walk(dir, func(name string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		f, err := os.Open(name)
		if err != nil {
			return err
		}
		defer f.Close()

		h, err := tar.FileInfoHeader(info, "")
		if err != nil {
			return err
		}
		p, _ := filepath.Rel(dir, name)
		h.Name = filepath.Join(base, p)
		if err = tr.WriteHeader(h); err != nil {
			return err
		}

		if info.Mode().IsRegular() {
			io.Copy(tr, f)
		}
		return nil
	})
}

func main() {
	err := maketar(os.Args[1], os.Stdout)
	if err != nil {
		log.Fatal(err)
	}
}

classroom序列化

参考作业

协程简介

tick.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
package main

import (
	"fmt"
	"time"
)

func main() {
	timer := time.NewTicker(time.Second)
	cnt := 0
	for _ = range timer.C {
		cnt++
		if cnt > 3 {
			timer.Stop()
			return
		}
		fmt.Println("hello")
	}
}

sleep.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
package main

import (
	"fmt"
	"time"
)

func say(s string) {
	for i := 0; i < 5; i++ {
		time.Sleep(100 * time.Millisecond)
		fmt.Println(s)
	}
}

func main() {
	go say("world")
	say("hello")
}

sleep_sort.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
package main

import (
	"fmt"
	"time"
)

func main() {
	s := []int{2, 7, 1, 6, 4, 50}
	for _, n := range s {
		go func(n int) {
			time.Sleep(time.Duration(n) * time.Second)
			fmt.Println(n)
		}(n)
	}
	time.Sleep(10 * time.Second)
}

协程和channel

default.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
	"fmt"
	"time"
)

func main() {
	tick := time.NewTicker(1000 * time.Millisecond).C
	boom := time.After(5000 * time.Millisecond)
	for {
		select {
		case <-tick:
			fmt.Println("滴答...")
		case <-boom:
			fmt.Println("嘣!!!")
			return
		default:
			fmt.Println("吃一口面")
			time.Sleep(500 * time.Millisecond)
		}
	}
}

after.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

import (
	"fmt"
	"time"
)

func main() {
	c := time.After(time.Second * 3)
	<-c
	fmt.Println("done")
}

range.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
	"fmt"
)

func fibonacci(n int, c chan int) {
	x, y := 0, 1
	for i := 0; i < n; i++ {
		c <- x
		x, y = y, x+y
	}
	close(c)
}

func main() {
	c := make(chan int, 10)
	go fibonacci(cap(c), c)
	for i := range c {
		fmt.Println(i)
	}
}

ch.go

1
2
3
4
5
package main

func main() {
	s := []string{"hello", "golang", "c++", "world"}
}

channel

channel.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import "fmt"

func sum(s []string, c chan string) {
	var sum string
	for _, v := range s {
		sum += v
	}
	c <- sum // send sum to c
}

func main() {
	s := []string{"hello", "golang", "c++", "world"}

	c1 := make(chan string)
	c2 := make(chan string)
	go sum(s[:len(s)/2], c1)
	go sum(s[len(s)/2:], c2)
	x, y := <-c1, <-c2 // receive from c

	fmt.Println(x, y, x+y)
}

channel_buf.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "fmt"

func main() {
	ch := make(chan int, 2)
	ch <- 1
	ch <- 2
	fmt.Println(<-ch)
	fmt.Println(<-ch)
}

select.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import "fmt"

func fibonacci(c, quit chan int) {
	x, y := 0, 1
	for {
		select {
		case c <- x:
			x, y = y, x+y
		case <-quit:
			fmt.Println("quit")
			return
		}
	}
}

func main() {
	c := make(chan int)
	quit := make(chan int)
	go func() {
		for i := 0; i < 10; i++ {
			fmt.Println(<-c)
		}
		quit <- 0
	}()
	fibonacci(c, quit)
}

go的http

http_client.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package main

import (
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"

	"github.com/PuerkitoBio/goquery"
)

func cleanUrls(u string, urls []string) []string {
	return nil
}

func fetch(url string) ([]string, error) {
	var urls []string
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return nil, errors.New(resp.Status)
	}
	doc, err := goquery.NewDocumentFromResponse(resp)
	if err != nil {
		return nil, err
	}
	doc.Find("img").Each(func(i int, s *goquery.Selection) {
		link, _ := s.Attr("src")
		fmt.Println(link)
	})

	return urls, nil
}

func main() {
	//url := "http://daily.zhihu.com/"
	url := os.Args[1]
	urls, err := fetch(url)
	if err != nil {
		log.Fatal(err)
	}
	for _, u := range urls {
		fmt.Println(u)
	}
}

http.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package main

import (
	"log"
	"net/http"
	"os"
)

func main() {
	http.Handle("/", http.FileServer(http.Dir(".")))
	log.Fatal(http.ListenAndServe(os.Args[1], nil))
}

mget.go

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"math"
	"net/http"
	"os"
	"path"
	"sync"

	"github.com/rakyll/pb"
)

var (
	works = flag.Int("n", 5, "works")
)

type Block struct {
	Id    int
	Begin int64
	End   int64
	Name  string
}

func GetSize(url string) (int64, error) {
	resp, err := http.Head(url)
	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()
	return resp.ContentLength, nil
}

func GenBlocks(total int64, works int) []*Block {
	var blocks []*Block
	n := int64(math.Ceil(float64(total) / float64(works)))
	for i := int64(0); i < int64(works)-1; i++ {
		block := &Block{
			Id:    int(i),
			Begin: i * n,
			End:   (i + 1) * n,
		}
		blocks = append(blocks, block)
	}
	blocks = append(blocks, &Block{
		Id:    works - 1,
		Begin: n * (int64(works) - 1),
		End:   total,
	})
	return blocks
}

func Download(url string, b *Block, bar *pb.ProgressBar) error {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return err
	}
	req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", b.Begin, b.End-1))
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	name := fmt.Sprintf("%s.%d", path.Base(url), b.Id)
	b.Name = name
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	defer f.Close()
	w := io.MultiWriter(bar, f)
	_, err = io.Copy(w, resp.Body)
	return err
}

func Merge(name string, blocks []*Block) error {
	readers := make([]io.Reader, len(blocks))
	for i, b := range blocks {
		f, err := os.Open(b.Name)
		if err != nil {
			return err
		}
		defer f.Close()
		readers[i] = f
	}
	r := io.MultiReader(readers...)
	f, err := os.Create(name)
	if err != nil {
		return err
	}
	_, err = io.Copy(f, r)
	if err != nil {
		return err
	}

	for _, b := range blocks {
		os.Remove(b.Name)
	}
	return nil
}

func main() {
	flag.Parse()
	url := flag.Arg(0)
	total, err := GetSize(url)
	if err != nil {
		log.Fatal(err)
	}

	log.Printf("total:%d", total)

	blocks := GenBlocks(total, *works)

	bar := pb.New(int(total)).SetUnits(pb.U_BYTES)
	bar.Start()

	group := new(sync.WaitGroup)
	for _, b := range blocks {
		log.Printf("%v", b)
		b := b
		group.Add(1)
		go func() {
			defer group.Done()
			err := Download(url, b, bar)
			if err != nil {
				log.Fatal(err)
			}
		}()
	}

	group.Wait()
	bar.Finish()

	log.Printf("group done")
	err = Merge(path.Base(url), blocks)
	if err != nil {
		log.Fatal(err)
	}
}

goquery

encode.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
	"encoding/json"
	"fmt"
	"log"
)

type Student struct {
	Name string
	id   int
}

func (s *Student) MarshalJSON() ([]byte, error) {
	return json.Marshal(s.id)
}

func main() {
	s := &Student{
		Name: "binggan",
		id:   1,
	}
	buf, err := json.Marshal(s)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(buf))
}

uri.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
	"fmt"
	"log"
	"net/url"
	"os"
)

func main() {
	s := os.Args[1]
	u, err := url.Parse(s)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("scheme", u.Scheme)
	fmt.Println("host", u.Host)
	fmt.Println("path", u.Path)
	fmt.Println("queryString", u.RawQuery)
	fmt.Println("user", u.User)
	fmt.Println("xx", u.Fragment)
}

spider.go

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package main

import (
	"archive/tar"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"strings"
	"sync"

	"github.com/PuerkitoBio/goquery"
)

type TaskPool struct {
	queue   chan func()
	wait    *sync.WaitGroup
	workers int
}

func NewTaskPool(workers int) *TaskPool {
	return &TaskPool{
		queue:   make(chan func()),
		wait:    new(sync.WaitGroup),
		workers: workers,
	}
}

func (t *TaskPool) work() {
	defer t.wait.Done()
	for task := range t.queue {
		task()
	}
}

func (t *TaskPool) Start() {
	for i := 0; i < t.workers; i++ {
		t.wait.Add(1)
		go t.work()
	}
}

func (t *TaskPool) Submit(task func()) {
	t.queue <- task
}

func (t *TaskPool) Stop() {
	close(t.queue)
}

func (t *TaskPool) Wait() {
	t.wait.Wait()
}

func makelink(uri *url.URL, link string) string {
	switch {
	case strings.HasPrefix(link, "https") ||
		strings.HasPrefix(link, "http"):
		return link
	case strings.HasPrefix(link, "//"):
		return uri.Scheme + ":" + link
	case strings.HasPrefix(link, "/"):
		return fmt.Sprintf("%s://%s%s", uri.Scheme, uri.Host, link)
	default:
		return fmt.Sprintf("%s://%s/%s/%s", uri.Scheme, uri.Host, uri.Path, link)
	}
}

func fetch(target string) ([]string, error) {
	uri, err := url.Parse(target)
	if err != nil {
		return nil, err
	}

	resp, err := http.Get(target)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	doc, err := goquery.NewDocumentFromResponse(resp)
	if err != nil {
		return nil, err
	}
	var urls []string
	doc.Find("img").Each(func(i int, s *goquery.Selection) {
		link, ok := s.Attr("src")
		if !ok {
			return
		}
		urls = append(urls, makelink(uri, link))
	})
	return urls, nil
}

func saveimg(dir, target string) error {
	log.Print(target)
	uri, err := url.Parse(target)
	if err != nil {
		return err
	}

	resp, err := http.Get(target)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return errors.New(resp.Status)
	}

	name := path.Base(uri.Path)
	fullpath := filepath.Join(dir, name)
	f, err := os.Create(fullpath)
	if err != nil {
		return err
	}
	defer f.Close()

	io.Copy(f, resp.Body)
	return nil
}

func saveimgs(dir string, urls []string) error {
	pool := NewTaskPool(5)
	pool.Start()
	for _, url := range urls {
		url := url
		pool.Submit(func() {
			if err := saveimg(dir, url); err != nil {
				log.Print(err)
			}
		})
	}
	pool.Stop()
	pool.Wait()
	return nil
}

func maketar(dir string, w io.Writer) error {
	base := filepath.Base(dir)
	tr := tar.NewWriter(w)
	defer tr.Close()
	return filepath.Walk(dir, func(name string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		f, err := os.Open(name)
		if err != nil {
			return err
		}
		defer f.Close()

		h, err := tar.FileInfoHeader(info, "")
		if err != nil {
			return err
		}
		p, _ := filepath.Rel(dir, name)
		h.Name = filepath.Join(base, p)
		if err = tr.WriteHeader(h); err != nil {
			return err
		}

		if info.Mode().IsRegular() {
			io.Copy(tr, f)
		}
		return nil
	})
}

func main() {
	url := os.Args[1]
	urls, err := fetch(url)
	if err != nil {
		log.Panic(err)
	}

	dir, err := ioutil.TempDir("", "img")
	if err != nil {
		log.Panic(err)
	}

	defer os.RemoveAll(dir)

	err = saveimgs(dir, urls)
	if err != nil {
		log.Panic(err)
	}

	err = maketar(dir, os.Stdout)
	if err != nil {
		log.Panic(err)
	}
}

总结

homework

完善学生管理系统

要求:

  • 以面向对象的方式

完善cleanUrls

要求:

  • 清洗不合规格的url