golang小程序试验(三)

壬癸甲乙 · · 2540 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

1. golang的log模块

golang的log模块可以很方便的创建自己的日志记录,包括日志文件路径,日志格式等都可以自己定义。先来看一个程序:

package main

import (
	"fmt"
	"log"
	"os"
)

func main() {
	logfile, err := os.OpenFile("d:\\test.log", os.O_RDWR|os.O_CREATE, 0)
	if err != nil {
		fmt.Printf("%s\r\n", err.Error())
		os.Exit(-1)
	}
	defer logfile.Close()
	logger := log.New(logfile, "\r\n", log.Ldate|log.Ltime|log.Llongfile)
	logger.Println("hello")
	logger.Println("oh....")
	logger.Fatal("test")
	logger.Fatal("test2")
}

首先创建一个log文件,然后利用log.New()创建一个Logger对象,并定义log文件内容的格式,New()定义如下:

func New(out io.Writer, prefix string, flag int) *Logger
Ldate、Ltime等被定义为常量:
const (
    // Bits or'ed together to control what's printed. There is no control over the
    // order they appear (the order listed here) or the format they present (as
    // described in the comments).  A colon appears after these items:
    //	2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
    Ldate         = 1 << iota     // the date: 2009/01/23
    Ltime                         // the time: 01:23:23
    Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
    Llongfile                     // full file name and line number: /a/b/c/d.go:23
    Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
    LstdFlags     = Ldate | Ltime // initial values for the standard logger
)

通过Print()、Println()、Printf()等函数可以向log文件中写入log记录了。然后调用Fatal()等函数记录最后一条log,并退出(Fatal()中包含了调用os.Exit(1))。

Logger给出的结论是: A Logger can be used simultaneously from multiple goroutines; it guarantees to serialize access to the Writer. 也就是说是线程安全的。

2. golang的archive/zip模块

此模块比较简单,直接用一个程序说明:

package main

import (
	"fmt"
	"os"
	"log"
	"archive/zip"
	"io"
)

const (
	LOGFILEPATH = "d:\\zip.log"
)

func main(){
	logfile,err := os.OpenFile(LOGFILEPATH,os.O_CREATE|os.O_RDWR,0);
	if err!=nil {
		fmt.Println(err.Error());
		return;
	}
	defer logfile.Close();
	logger := log.New(logfile,"\r\n",log.Ldate|log.Ltime|log.Llongfile);
	if logger==nil {
		fmt.Println("logger init error");
	}
	r,err := zip.OpenReader("d:\\新建文本文档.zip");
	if err!=nil {
		logger.Fatal(err);
	}
	defer r.Close();
	for _,f := range r.File {
		fmt.Println("FileName : ",f.Name);
		rc,err := f.Open();
		if err!=nil {
			logger.Fatal(err);
		}
		_,err = io.CopyN(os.Stdout,rc,68); //打印文件内容
		if err!=nil {
			if err!=io.EOF {
				logger.Fatal(err);
			}
		}
	}
}

3. panic与recover

第一篇文章已经介绍过,这里再来一个例子:

package main
import "fmt"

func main() {
	T()
        //recover执行后,这里会继续执行
	fmt.Println("after recover.")
}

func T() {
	defer func() {
		fmt.Println("defer func is run")
                //recover只能在defer()函数中执行
		r := recover()
		if r != nil {
			fmt.Println("recover: ", r)
		}
	}()
	fmt.Println("body")
        //panic中的文本会传给recover
	panic("panic is run")
	fmt.Println("body 2")
}

4. golang的base64加解密

package main

import (
	"encoding/base64"
	"fmt"
)

const (
	base64Table = "123QRSTUabcdVWXYZHijKLAWDCABDstEFGuvwxyzGHIJklmnopqr234560178912"
)

var coder = base64.NewEncoding(base64Table)

func base64Encode(src []byte) []byte {
	return []byte(coder.EncodeToString(src))
}

func base64Decode(src []byte) ([]byte, error) {
	return coder.DecodeString(string(src))
}

func main() {
	// encode
	hello := "hello world"
	debyte := base64Encode([]byte(hello))

	// decode
	enbyte, err := base64Decode(debyte)
	if err != nil {
		fmt.Println(err.Error())
	}

	if hello != string(enbyte) {
		fmt.Println("hello is not equal to enbyte")
	}

	fmt.Println(string(enbyte))
}

5. golang的time包

package main

import (
	"fmt"
	"time"
)

func main() {
	//时间戳
	t := time.Now().Unix()
	fmt.Println(t)

	//时间戳到具体显示的转化
	fmt.Println(time.Unix(t, 0).String())

	//带纳秒的时间戳
	t = time.Now().UnixNano()
	fmt.Println(t)
	fmt.Println("------------------")

	//基本格式化的时间表示
	fmt.Println(time.Now().String())

	fmt.Println(time.Now().Format("2006year 01month 02day"))

}
输出今天是星期几:
package main
 
import (
    "fmt"
    "time"
)
 
func main() {
    //时间戳
    t := time.Now()
    fmt.Println(t.Weekday().String())
 
}

6. golang反射举例

package main

import (
	"fmt"
	"reflect"
)

type MyStruct struct {
	name string
}

func (this *MyStruct) GetName() string {
	return this.name
}

func main() {
	fmt.Println("--------------")
	var a MyStruct
	b := new(MyStruct)
	fmt.Println(reflect.ValueOf(a))
	fmt.Println(reflect.ValueOf(b))

	fmt.Println("--------------")
	a.name = "abc"
	b.name = "def"
	val := reflect.ValueOf(a).FieldByName("name")
	fmt.Println(val)

	//val2 := reflect.ValueOf(b).FieldByName("name")
	//panic: reflect: call of reflect.Value.FieldByName on ptr Value
	//b是一个指针,指针的ValueOf返回的是指针的Type,它是没有Field的,所以也就不能使用FieldByName

	fmt.Println("--------------")
	fmt.Println(reflect.ValueOf(a).FieldByName("name").CanSet())
	fmt.Println(reflect.ValueOf(&(a.name)).Elem().CanSet())

	fmt.Println("--------------")
	var c string = "xyz"
	p := reflect.ValueOf(&c)
	fmt.Println(p.CanSet())        //false
	fmt.Println(p.Elem().CanSet()) //true
	p.Elem().SetString("newName")
	fmt.Println(c)
}

执行结果:

--------------
<main.MyStruct Value>
<*main.MyStruct Value>
--------------
abc
--------------
false
true
--------------
false
true
newName

a和b的ValueOf()返回的是不一样的值,因为b是用new()创建的,是个指针。

当前面的CanSet是一个指针的时候(p)它是不可寻址的,但是当是p.Elem()(实际上就是*p),它就是可以寻址的。


有疑问加站长微信联系(非本文作者)

本文来自:开源中国博客

感谢作者:壬癸甲乙

查看原文:golang小程序试验(三)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:701969077

2540 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传