I've been trying to do something simple like this, but I'm not interested in following symlinks.  Here I just am interested in summing all subdirectories from my start directory.  But I'm not geting consistent sums, especially if I start from my home directory.

I guess I'm not handling errors, but I don't know how to handle them in a way that allows continuing w/ all directories until all non-error-producing directories are walked and summed.

I don't want to follow symlinks.

I use this on Ubuntu amd64 16.04, 18.04 and Win10.

Compiled w/ 1.11.1 (and earlier, but that doesn't matter now).

I don't know how to post code without bombing this list.

package main

import (
    "bufio"
    "fmt"
    "os"
    "path/filepath"
    "sort"
    "strconv"
)

const LastAltered = "5 Oct 2018"

type directory struct {
    name     string
    subtotal int64
}

type dirslice []directory

func (ds dirslice) Less(i, j int) bool {
    return ds[i].subtotal > ds[j].subtotal // I want a reverse sort, largest first
}

func (ds dirslice) Swap(i, j int) {
    ds[i], ds[j] = ds[j], ds[i]
}

func (ds dirslice) Len() int {
    return len(ds)
}

func main() {
    var GrandTotalSize, TotalOfFiles int64
    var startDirectory string
    var dirList dirslice

    fmt.Println()
    fmt.Println(" dirmap sums the directories it walks.  Written in Go.  Last altered ", LastAltered)

    if len(os.Args) < 2 {
        startDirectory, _ = os.Getwd()
    } else {
        startDirectory = os.Args[1]
    }
    start, err := os.Stat(startDirectory)
    if err != nil || !start.IsDir() {
        fmt.Println(" usage: diskwalk <directoryname>")
        os.Exit(1)
    }

    dirList = make(dirslice, 0, 500)
    DirMap := make(map[string]int64, 500)
    DirAlreadyWalked := make(map[string]bool, 500)

    // walkfunc closure
    filepathwalkfunc := func(fpath string, fi os.FileInfo, err error) error {
        if err != nil {
            fmt.Printf(" Error from walk.  Grand total size is %d in %d number of files, error is %v. \n ", GrandTotalSize, TotalOfFiles, err)
            return filepath.SkipDir
        }

        if !fi.Mode().IsRegular() {
            if fi.IsDir() {
                if DirAlreadyWalked[fi.Name()] {
                    return filepath.SkipDir
                } else {
                    DirAlreadyWalked[fi.Name()] = true
                }
            } else {
                return filepath.SkipDir
            }
        }

        //  Now have a regular file.
        TotalOfFiles++
        GrandTotalSize += fi.Size()
        DirMap[filepath.Dir(fpath)] += fi.Size()

        return nil
    }

    filepath.Walk(startDirectory, filepathwalkfunc)

    // Prepare for output.
    s2 := ""
    var i int64 = GrandTotalSize
    switch {
    case GrandTotalSize > 1e12: // 1 trillion, or TB
        i = GrandTotalSize / 1e12       // I'm forcing an integer division.
        if GrandTotalSize%1e12 > 5e11 { // rounding up
            i++
        }
        s2 = fmt.Sprintf("%d TB", i)
    case GrandTotalSize > 1e9: // 1 billion, or GB
        i = GrandTotalSize / 1e9
        if GrandTotalSize%1e9 > 5e8 { // rounding up
            i++
        }
        s2 = fmt.Sprintf("%d GB", i)
    case GrandTotalSize > 1000000: // 1 million, or MB
        i = GrandTotalSize / 1000000
        if GrandTotalSize%1000000 > 500000 {
            i++
        }
        s2 = fmt.Sprintf("%d MB", i)
    case GrandTotalSize > 1000: // KB
        i = GrandTotalSize / 1000
        if GrandTotalSize%1000 > 500 {
            i++
        }
        s2 = fmt.Sprintf("%d KB", i)
    default:
        s2 = fmt.Sprintf("%d", i)
    }

    GrandTotalString := strconv.FormatInt(GrandTotalSize, 10)
    GrandTotalString = AddCommas(GrandTotalString)
    fmt.Print(" start dir is ", startDirectory, "; found ", TotalOfFiles, " files in this tree. ")     fmt.Println(" Total Size of walked tree is", GrandTotalString, "or", s2, ", and len of DirMap is", len(DirMap))

    // Output map
    for n, m := range DirMap { // n is name as a string, m is map as a directory subtotal
        d := directory{} // this is a structured constant
        d.name = n
        d.subtotal = m
        dirList = append(dirList, d)
    }
    fmt.Println(" Length of sorted dirList is", len(dirList), ", length of DirAlreadyWalked is", len(DirAlreadyWalked))
    sort.Sort(dirList)

    datestr := MakeDateStr()
    outfilename := filepath.Base(startDirectory) + datestr + ".txt"
    outfile, err := os.Create(outfilename)
    defer outfile.Close()
    outputfile := bufio.NewWriter(outfile)
    defer outputfile.Flush()

    if err != nil {
        fmt.Println(" Cannot open outputfile ", outfilename, " with error ", err)         // I'm going to assume this branch does not occur in the code below.  Else I would need a
        // stop flag of some kind to write to screen.
    }

    if len(dirList) < 30 {
        for _, d := range dirList {
            str := strconv.FormatInt(d.subtotal, 10)
            str = AddCommas(str)
            s := fmt.Sprintf("%s size is %s", d.name, str)
            fmt.Println(s)
        }
        fmt.Println()
    } else { // write output to a file.  First, build filename
        s0 := fmt.Sprintf("start dir is %s, found %d files in this tree.  GrandTotal is %s, or %s, and number of directories is %d\n", startDirectory, TotalOfFiles, GrandTotalString, s2, len(DirMap))
        outputfile.WriteString(s0)
        outputfile.WriteString("\n")
        for _, d := range dirList {
            str := strconv.FormatInt(d.subtotal, 10)
            str = AddCommas(str)
            s1 := fmt.Sprintf("%s size is %s\n", d.name, str)
            outputfile.WriteString(s1)
        }
        outputfile.WriteString("\n")
        outputfile.WriteString("\n")
        outputfile.Flush()
        outfile.Close()
        fmt.Println(" List of subdirectories written to", outfilename)
    }
    fmt.Println()
    fmt.Println()
} // main

//-------------------------------------------------------------------- InsertByteSlice
func InsertIntoByteSlice(slice, insertion []byte, index int) []byte {
    return append(slice[:index], append(insertion, slice[index:]...)...)
}

//---------------------------------------------------------------------- AddCommas
func AddCommas(instr string) string {
    var Comma []byte = []byte{','}

    BS := make([]byte, 0, 15)
    BS = append(BS, instr...)

    i := len(BS)

    for NumberOfCommas := i / 3; (NumberOfCommas > 0) && (i > 3); NumberOfCommas-- {
        i -= 3
        BS = InsertIntoByteSlice(BS, Comma, i)
    }
    return string(BS)
} // AddCommas

func min(i, j int) int {
    if i < j {
        return i
    } else {
        return j
    }
} // min

// ------------------------------------------- MakeDateStr ---------------------------------------------
func MakeDateStr() string {
// in my code I use a more complex function here, but that is not needed for demo

    datestr = "dirmap_Oct-5-2018.txt"
    return datestr
}

--
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to