对于语言设计之争, 唯一需要牢记的一句话是: 如果把 C 变成 C++, 那么 C 就消失了。
Go 是一个轻量级的简洁的支持并发的语言, 可以用于探索性个人项目, 这是我想学这门语言的主要原因。 对于有一定编程经验的人来说, 学习一种新语言的方式是, 先概览下语言特性, 然后编写一个中等规模的程序, 尽可能地运用到大部分重要特性。
下面的程序用于计算一个目录下所有文件或目录的大小。
package main
import (
"fmt"
"time"
"os"
"log"
)
type ShortFileInfo struct {
fileName string
size int64
}
func (fileInfo *ShortFileInfo) Desc() string {
return fmt.Sprintf("{%s:%d}", fileInfo.fileName, fileInfo.size)
}
func produceFiles(dirName string) []os.FileInfo {
path, err := os.Open(dirName)
if err != nil {
log.Fatal(err)
}
defer path.Close()
fileInfos, err := path.Readdir(0);
if err != nil {
log.Fatal(err)
}
return fileInfos;
}
func procFile(fileInfo os.FileInfo, baseDirName string, channelBuffer chan ShortFileInfo) {
var filesize int64
fileName := fileInfo.Name()
if fileInfo.IsDir() {
filesize = totalFilesizeInDir(fileInfo, baseDirName)
} else {
filesize = fileInfo.Size()
}
shortFileInfo := ShortFileInfo{fileName, filesize};
fmt.Println(time.Now().String() + " store: " + shortFileInfo.Desc())
channelBuffer <- shortFileInfo
}
func totalFilesizeInDir(fileInfo os.FileInfo, baseDirName string) int64 {
var filesize int64 = 0
fileInfos := produceFiles(baseDirName + "\\" + fileInfo.Name())
for _, subfileInfo := range fileInfos {
if subfileInfo.IsDir() {
filesize += totalFilesizeInDir(subfileInfo, baseDirName + "\\" + fileInfo.Name())
} else {
filesize += subfileInfo.Size()
}
}
return filesize
}
func sleep(ns int) {
time.Sleep(time.Duration(time.Second)*time.Duration(ns))
}
const (
B int64 = 1
KB int64 = 1024
MB int64 = 1024*1024
GB int64 = 1024*1024*1024
TB int64 = 1024*1024*1024*1024
)
const formatF string = "%8.4f"
func readableSize(sizeInBytes int64) string {
switch {
case B <= sizeInBytes && sizeInBytes < KB:
return fmt.Sprintf("%dB", sizeInBytes)
case KB <= sizeInBytes && sizeInBytes < MB:
return fmt.Sprintf(formatF+"KB", float64(sizeInBytes)/float64(KB))
case MB <= sizeInBytes && sizeInBytes < GB:
return fmt.Sprintf(formatF+"MB", float64(sizeInBytes)/float64(MB))
case GB <= sizeInBytes && sizeInBytes < TB:
return fmt.Sprintf(formatF+"GB", float64(sizeInBytes)/float64(GB))
case TB <= sizeInBytes:
return fmt.Sprintf(formatF+"TB", float64(sizeInBytes)/float64(TB))
default:
return "0"
}
}
func main() {
baseDirName := "C:\\Users\\qin.shuq\\Desktop"
fileList := produceFiles(baseDirName)
fileNumber := len(fileList)
channelBuffer := make(chan ShortFileInfo, fileNumber)
fileInfoMap := make(map[string] int64, fileNumber)
for _, fileInfo := range fileList {
go procFile(fileInfo, baseDirName, channelBuffer)
}
for count := 0 ; count <= fileNumber ; {
select {
case fileInfo := <- channelBuffer:
fmt.Println(time.Now().String() + " fetch: " + fileInfo.Desc())
fileInfoMap[fileInfo.fileName] = fileInfo.size
count++
default:
if count == fileNumber {
close(channelBuffer)
}
fmt.Println("Waiting for data ...")
sleep(2)
}
}
var totalSize int64
totalSize = 0
for _ , filesize := range fileInfoMap {
totalSize += filesize
}
fmt.Printf("Total size in %s:%dB %s", baseDirName , totalSize, readableSize(totalSize));
}