Golang学习之在项目中遇到的几个常用的方法
来源:互联网 发布:安卓锁屏软件 编辑:程序博客网 时间:2024/06/13 22:52
1、TempFile
TempFile 在 dir 目录中创建一个以 prefix 为前缀的临时文件,并将其以读
写模式打开。返回创建的文件对象和遇到的错误。
如果 dir 为空,则在默认的临时目录中创建文件(参见 os.TempDir),多次
调用会创建不同的临时文件,调用者可以通过 f.Name() 获取文件的完整路径。
调用本函数所创建的临时文件,应该由调用者自己删除。
func TempFile(dir, prefix string) (f *os.File, err error)
例子:
package mainimport ( "io/ioutil" "log" "os")func main() { content := []byte("temporary file's content") tmpfile, err := ioutil.TempFile("", "example") if err != nil { log.Fatal(err) } defer os.Remove(tmpfile.Name()) // clean up if _, err := tmpfile.Write(content); err != nil { log.Fatal(err) } if err := tmpfile.Close(); err != nil { log.Fatal(err) }}
2、创建一个文件夹:
os.Mkdir("test_go", 0777)
3、创建多级文件夹:
func MkdirAll(path string, perm FileMode) error
例如:
os.MkdirAll("test_go/go1/go2", 0777)
4、删除文件夹
删除就简单多了:
err := os.Remove("test_go") if err != nil { fmt.Println(err) } os.RemoveAll("test_go")
5、读取文件
可以使用os中的Open方法读取一文件:
file, err := os.Open("file.go") // For read access.if err != nil { log.Fatal(err)}
6、打开一个文件:
dat, err := ioutil.ReadFile("file.go")check(err)fmt.Print(string(dat))
7、指定文件权限和打开的方式:
f, err := os.OpenFile("file.go", os.O_RDWR|os.O_CREATE, 0755)if err != nil { log.Fatal(err)}if err := f.Close(); err != nil { log.Fatal(err)}
8、golang中defer的执行
golang的defer关键字,它可以在函数返回前执行一些操作,最常用的就是打开一个资源(例如一个文件、数据库连接等)时就用defer延迟关闭改资源,以免引起内存泄漏。例如:
func do() (ok bool) { file,_ := os.Open("c:\a.txt") defer file.Close() // doSomething return ok}
在官方的文档中看到defer的执行顺序是逆序的,也就是先进后出的顺序:
for i := 0; i < 5; i++ { defer fmt.Printf("%d ", i)}
打印结果是:4,3,2,1,0
例子:
func deferRet(x,y int) (z int){ defer z += 100 z = x + y return z + 50 // 执行顺序 z = z+50 -> (call defer)z = z+100 -> ret }func main() { i := deferRet(1,1) println(i) // print 152}
9、FormFile
func (r *Request) FormFile(key string) (multipart.File, *multipart.FileHeader, error) //对于指定格式的key,FormFile返回符合条件的第一个文件,如果有必要的话,该函数会调用ParseMultipartForm和ParseForm。
10、ParseForm
func (r *Request) ParseForm() error //解析URL中的查询字符串,并将解析结果更新到r.Form字段。对于POST或PUT请求,ParseForm还会将body当作表单解析,并将结果既更新到r.PostForm也更新到r.Form。解析结果中,POST或PUT请求主体要优先于URL查询字符串(同名变量,主体的值在查询字符串的值前面)。如果请求的主体的大小没有被MaxBytesReader函数设定限制,其大小默认限制为开头10MB。ParseMultipartForm会自动调用ParseForm。重复调用本方法是无意义的。
关于FormFile和ParseForm ,有兴趣可以去详读一下golang中net/http包用法 这篇文章
11、 HandleFunc和ListenAndServe
//第一个参数为客户端发起http请求时的接口名,第二个参数是一个func,负责处理这个请求。 http.HandleFunc("/login", loginTask) //服务器要监听的主机地址和端口号 err := http.ListenAndServe("192.168.1.27:8081", nil)
golang http的handle模块(一般也称为钩子模块),通过高级语言的匿名函数很容易实现这种内嵌功能的handle
我们一般这样使用golang的http HandleFunc来为http的server端做相应的处理
http.HandleFunc("/", xxx_FUN) err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("ListenAndServe: ", err) }
我们再深入源码仔细看看http.HandleFunc的实现
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler)}// NewServeMux allocates and returns a new ServeMux.var DefaultServeMux = NewServeMux()func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }type ServeMux struct { mu sync.RWMutex //一个读写锁 m map[string]muxEntry //一个path(patterns)的映射map hosts bool // whether any patterns contain hostnames}
再来看看ListenAndServe的具体实现
func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe()}func (srv *Server) ListenAndServe() error { addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}// Serve accepts incoming connections on the Listener l, creating a// new service goroutine for each. The service goroutines read requests and// then call srv.Handler to reply to them.func (srv *Server) Serve(l net.Listener) error { defer l.Close() var tempDelay time.Duration // how long to sleep on accept failure for { rw, e := l.Accept() if e != nil { if ne, ok := e.(net.Error); ok && ne.Temporary() { if tempDelay == 0 { tempDelay = 5 * time.Millisecond } else { tempDelay *= 2 } if max := 1 * time.Second; tempDelay > max { tempDelay = max } srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } return e } tempDelay = 0 c, err := srv.newConn(rw) if err != nil { continue } c.setState(c.rwc, StateNew) // before Serve can return go c.serve() //看来这个c.serve是处理的入口 }}
看来这个c.serve是处理的入口
// Serve a new connection.func (c *conn) serve() { origConn := c.rwc // copy it before it's set nil on Close or Hijack defer func() { if err := recover(); err != nil { const size = 64 << 10 buf := make([]byte, size) buf = buf[:runtime.Stack(buf, false)] c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf) } if !c.hijacked() { c.close() c.setState(origConn, StateClosed) } }() if tlsConn, ok := c.rwc.(*tls.Conn); ok { if d := c.server.ReadTimeout; d != 0 { c.rwc.SetReadDeadline(time.Now().Add(d)) } if d := c.server.WriteTimeout; d != 0 { c.rwc.SetWriteDeadline(time.Now().Add(d)) } if err := tlsConn.Handshake(); err != nil { c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err) return } c.tlsState = new(tls.ConnectionState) *c.tlsState = tlsConn.ConnectionState() if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) { if fn := c.server.TLSNextProto[proto]; fn != nil { h := initNPNRequest{tlsConn, serverHandler{c.server}} fn(c.server, tlsConn, h) } return } } for { w, err := c.readRequest() if c.lr.N != c.server.initialLimitedReaderSize() { // If we read any bytes off the wire, we're active. c.setState(c.rwc, StateActive) } if err != nil { if err == errTooLarge { // Their HTTP client may or may not be // able to read this if we're // responding to them and hanging up // while they're still writing their // request. Undefined behavior. io.WriteString(c.rwc, "HTTP/1.1 413 Request Entity Too Large\r\n\r\n") c.closeWriteAndWait() break } else if err == io.EOF { break // Don't reply } else if neterr, ok := err.(net.Error); ok && neterr.Timeout() { break // Don't reply } io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\n\r\n") break } // Expect 100 Continue support req := w.req if req.expectsContinue() { if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 { // Wrap the Body reader with one that replies on the connection req.Body = &expectContinueReader{readCloser: req.Body, resp: w} } req.Header.Del("Expect") } else if req.Header.get("Expect") != "" { w.sendExpectationFailed() break } // HTTP cannot have multiple simultaneous active requests.[*] // Until the server replies to this request, it can't read another, // so we might as well run the handler in this goroutine. // [*] Not strictly true: HTTP pipelining. We could let them all process // in parallel even if their responses need to be serialized. serverHandler{c.server}.ServeHTTP(w, w.req) //这个是入口 if c.hijacked() { return } w.finishRequest() if w.closeAfterReply { if w.requestBodyLimitHit { c.closeWriteAndWait() } break } c.setState(c.rwc, StateIdle) }}
Handler处理的入口就是serverHandler{c.server}.ServerHTTP(w,w.req)
,最终到HandleFunc的执行
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { if r.Method != "CONNECT" { if p := cleanPath(r.URL.Path); p != r.URL.Path { _, pattern = mux.handler(r.Host, p) //接下来处理 url := *r.URL url.Path = p return RedirectHandler(url.String(), StatusMovedPermanently), pattern } } return mux.handler(r.Host, r.URL.Path) //接下来处理}func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { mux.mu.RLock() defer mux.mu.RUnlock() // Host-specific pattern takes precedence over generic ones if mux.hosts { h, pattern = mux.match(host + path) } if h == nil { h, pattern = mux.match(path) } if h == nil { h, pattern = NotFoundHandler(), "" //如果handler对应的匿名函数为空,则返回默认的匿名函数 } return}// ServeHTTP dispatches the request to the handler whose// pattern most closely matches the request URL.func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { if r.RequestURI == "*" { if r.ProtoAtLeast(1, 1) { w.Header().Set("Connection", "close") } w.WriteHeader(StatusBadRequest) return } h, _ := mux.Handler(r) //接下来处理 h.ServeHTTP(w, r) //接下来处理}//接下来就初始时候执行的操作func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { mux.Handle(pattern, HandlerFunc(handler))}func (mux *ServeMux) Handle(pattern string, handler Handler) { //处理pattern mux.mu.Lock() defer mux.mu.Unlock() if pattern == "" { panic("http: invalid pattern " + pattern) } if handler == nil { panic("http: nil handler") } if mux.m[pattern].explicit { panic("http: multiple registrations for " + pattern) } mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern} //设置ServeMux的map if pattern[0] != '/' { mux.hosts = true } // Helpful behavior: // If pattern is /tree/, insert an implicit permanent redirect for /tree. // It can be overridden by an explicit registration. n := len(pattern) if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit { // If pattern contains a host name, strip it and use remaining // path for redirect. path := pattern if pattern[0] != '/' { // In pattern, at least the last character is a '/', so // strings.Index can't be -1. path = pattern[strings.Index(pattern, "/"):] } mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(path, StatusMovedPermanently), pattern: pattern} }}
最后再看看通过mux匹配获取对应的map的操作:
func (mux *ServeMux) match(path string) (h Handler, pattern string) { var n = 0 for k, v := range mux.m { if !pathMatch(k, path) { //匹配 continue } if h == nil || len(k) > n { n = len(k) h = v.h pattern = v.pattern } } return}
注意:语句http.HandlerFunc(handler.list)是一个转换而非一个函数调用,因为http.HandlerFunc是一个类型
12、url解析
package mainimport "fmt"import "net/url"import "strings"func main() {//我们将解析这个 URL 示例,它包含了一个 scheme,认证信息,主机名,端口,路径,查询参数和片段。 s := "postgres://user:pass@host.com:5432/path?k=v#f"//解析这个 URL 并确保解析没有出错。 u, err := url.Parse(s) if err != nil { panic(err) }//直接访问 scheme。 fmt.Println(u.Scheme)//User 包含了所有的认证信息,这里调用 Username和 Password 来获取独立值。 fmt.Println(u.User) fmt.Println(u.User.Username()) p, _ := u.User.Password() fmt.Println(p)//Host 同时包括主机名和端口信息,如过端口存在的话,使用 strings.Split() 从 Host 中手动提取端口。 fmt.Println(u.Host) h := strings.Split(u.Host, ":") fmt.Println(h[0]) fmt.Println(h[1])//这里我们提出路径和查询片段信息。 fmt.Println(u.Path) fmt.Println(u.Fragment)//要得到字符串中的 k=v 这种格式的查询参数,可以使用 RawQuery 函数。你也可以将查询参数解析为一个map。已解析的查询参数 map 以查询字符串为键,对应值字符串切片为值,所以如何只想得到一个键对应的第一个值,将索引位置设置为 [0] 就行了。 fmt.Println(u.RawQuery) m, _ := url.ParseQuery(u.RawQuery) fmt.Println(m) fmt.Println(m["k"][0])}//运行我们的 URL 解析程序,显示全部我们提取的 URL 的不同数据块。$ go run url-parsing.go postgresuser:passuserpasshost.com:5432host.com5432/pathfk=vmap[k:[v]]v
- Golang学习之在项目中遇到的几个常用的方法
- 在项目中遇到的几个异常
- 最近在项目中遇到的几个小小问题
- 在项目中遇到的 maven 插件常用的配置
- 项目中遇到的几个知识点总结
- 项目实践中遇到的几个坑
- 在学习位图中遇到的一些常用的数据类型
- 学习Java中遇到的几个基本知识
- iOS学习之——学习中遇到的一些常用的方法及一些注意事项(持续更新)
- JSP 中 request的几个常用方法
- MongoDB中Query的几个常用方法
- Android中常用的几个工具方法
- UIApplicationDelegate中常用的几个方法
- UIApplicationDelegate中常用的几个方法
- BitmapFactory中常用的几个静态方法
- java多线程中几个常用的方法
- String中几个常用的方法
- 几个常用的方法
- api gateway源码解析
- 5.Spring配置文件
- python3爬虫初探(二)之requests
- Golang
- util工具
- Golang学习之在项目中遇到的几个常用的方法
- iOS 解决按钮背景图拉伸问题
- 设计算法,把十进制整数转换为二至九进制之间的任一进制输出。
- npm无响应解决方案和nvm下载无响应
- SpringMVC——接收请求参数和页面传参
- NoSQL等于没有安全?大数据安全隐患分析
- Delphi中文件名函数-路径、名称、子目录、驱动器、扩展名
- 记录一下遇到过的问题
- POJ 1125.Stockbroker Grapevine