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.