Go言語初体験

11340 ワード

言語設計の争いに対して、唯一覚えなければならないのは、CをC++に変えると、Cは消えてしまうということだ.
Goは軽量級の簡潔な同時サポート言語で、探求的な個人プロジェクトに使用することができます.これは私がこの言語を学びたい主な原因です.プログラミングの経験がある人にとって、新しい言語を学ぶ方法は、まず言語の特性を概説し、それから中規模のプログラムを作成し、できるだけ大部分の重要な特性に運用することです. 
次のプログラムは、1つのディレクトリの下にあるすべてのファイルまたはディレクトリのサイズを計算するために使用されます. 
       
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));



}