[I've set reply-to to include you (per your reply-to) but to exclude me; I
prefer to read my list mail on the list rather than in my personal inbox.]

* rob solomon <drrob...@verizon.net> [181006 15:17]:
> 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.

This list likes to use The Go Playground at https://play.golang.org to
share code that is not exceedingly large.  I have taken your program,
repaired line breaks added by the email handling programs, fixed a typo,
run gofmt, and pasted it into play.golang.org.  Clicking on the "Share"
button gives the following link:
<https://play.golang.org/p/XnmzUnbnhQQ>.

Many simple programs run on the Playground, but when I attempted to run
yours, I discovered that the playground passes an empty first command
line argument (os.Args[1] == ""), so your program just gives the usage
message.  I'm not sure whether or not this Playground behavior is
intentional.

Note that programs that are already running and which modify the
directory being scanned (e.g.  Firefox may be frequently updating a
cache subdirectory of your home directory) may cause the program to give
different results for each run.  However, I think your problems lie
elsewhere.

One problem is that you use fi.Name() in DirAlreadyWalked, but fi.Name()
is only the file name without the directory (e.g. filepath.Base(fpath)).
You want to use fpath.

The filepath.Walk function does not follow symlinks, and a normal file
system will not have any cycles, so you do not need any of the logic
associated with DirAlreadyWalked.  This would remove your problem with
fi.Name as well.

The documentation for WalkFunc is not clear on what errors might be
passed in as the err argument, but I suspect things like errors from the
underlying syscalls for stat or lstat.  However, it is clear that if err
is not nil on entry, the Walk function will already skip that directory
without you needing to return SkipDir.  You should return nil in this
case unless you want to abort the walk completely.

Also in your WalkFunc, you return SkipDir for non-regular files that are
not directories (e.g. device or pipe).  You probably want to return nil
in this case as well.

When I first started writing this, I took "not getting consistent sums"
to mean that you were getting different results from successive runs.
Now I realize you may mean results that are not close to the output of
du.  Being more specific about what your program produced and what you
expected it to produce would help here.

The *nix program du specifically gives you space taken on disk, unless
you pass an appropriate option to return the sum of apparent file sizes.
Your program sums file sizes, not disk space used.  It also ignores
sizes of directories (which can be large for directories with many files
and subdirectories).

When you start producing output, you create an output file on disk, and
then write to Stdout if dirList is small, leaving the empty disk file,
or write to the disk file otherwise.  It would be better to do something
like this:

    var isFileOutput = len(dirList) >= 30
    var w io.Writer
    if !isFileOutput {
        w = os.Stdout
    } else {
        var outfile, err = os.Create(outfilename)
        if err != nil {
            // print a message to os.Stderr and exit
            ...
        }
        defer outfile.Close()
        var bufoutfile = bufio.NewWriter(outfile)
        defer bufoutfile.Flush()
        w = bufoutfile
    }

I would put this code after filepath.Walk, but before any output.  You
can then use isFileOutput to ensure that the summary info is written to
both Stdout and the output file, but only have to generate it once.

    var b0 = []byte(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)))
    if isFileOutput {
        // Display summary info to Stdout as well.
        os.Stdout.Write(b0)
    }
    _, err = w.Write(b0)
    if err != nil {
        // print a message to os.Stderr and exit
        ...
    }

And then your main output loop would look like this:

    for _, d := range dirList {
        var str = strconv.FormatInt(d.subtotal, 10)
        str = AddCommas(str)
        var _, err = fmt.Fprintf(w, "%s size is %s", d.name, str)
        if err != nil {
            // print a message to os.Stderr and exit
            ...
        }
    }

I hope these comments help.

...Marvin

-- 
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