System file copy/move

7,037 views
Skip to first unread message

Nick Sarten

unread,
Apr 5, 2011, 1:24:19 AM4/5/11
to golang-nuts
Hi all,

I was just curious as to whether there's any way to copy, move or
delete a file in Go. I had a look at the "os" package which allows you
to create/open/delete files, but I can't find any file copy/move (and
get a directory listing) commands. I could possibly attempt to use a
system shell copy command or something, but i'd rather there was a
less hacky (and more platform independent) way of coding it.

If this isn't currently implemented anywhere in go, are there any
plans to implement it?

Evan Shaw

unread,
Apr 5, 2011, 1:29:40 AM4/5/11
to Nick Sarten, golang-nuts
On Tue, Apr 5, 2011 at 5:24 PM, Nick Sarten <gen.b...@gmail.com> wrote:
> I was just curious as to whether there's any way to copy,

Not right now. You do it by opening the source, creating the
destination, and calling io.Copy(dest, src). There was a CL for adding
a Copy function to io/ioutil a while back, but it must've been
abandoned.

> move

os.Rename

> or delete a file in Go.

os.Remove

- Evan

jimmy frasche

unread,
Apr 5, 2011, 1:30:46 AM4/5/11
to Nick Sarten, golang-nuts
io.Copy and io.Copyn are general routines for copying readers to
writers, such as from one file to another. You can open a directory
with os.Open. There are several methods for reading the files in a
directory on the *File.

Nick Sarten

unread,
Apr 5, 2011, 1:37:35 AM4/5/11
to golang-nuts
Thanks Evan,

I did see Remove just after i posted, but i didn't know Rename would
move a file to a different directory.

It would be nice to just be able to get a string array with the names
of files in a directory, and a copy method to copy a file at a source
path to a destination path, but i guess i can build my own by opening
the file, creating a new one, and copying between them. Ah well.

On Apr 5, 5:29 pm, Evan Shaw <chicken...@gmail.com> wrote:

Mike Ramirez

unread,
Apr 5, 2011, 3:21:52 AM4/5/11
to golan...@googlegroups.com
On Monday, April 04, 2011 10:37:35 pm Nick Sarten wrote:
> Thanks Evan,
>
> I did see Remove just after i posted, but i didn't know Rename would
> move a file to a different directory.
>
> It would be nice to just be able to get a string array with the names
> of files in a directory, and a copy method to copy a file at a source
> path to a destination path, but i guess i can build my own by opening
> the file, creating a new one, and copying between them. Ah well.
>

(*File).Readdirnames and (*File).Readdir ... a *File and *FileInfo can be
directories or files.

Here is a simple version of Copy (for files only).

func CopyFile(src, dest) (err os.Error) {
read, written int = 0

// check source file exists.
sStat, err = os.Stat(src) {
if err != nil {
return
}

if sStat.IsDirectory() {
return os.NewError(fmt.Sprintf("%s is a directory, can't copy.", sStat.Name)
}

s, err = os.Open(file, os.O_RDONLY, 0644)
if err != nil {
return
}
buffer []bytes
_, e := os.Stat(d)
if e != nil {

d, err = os.Open(dest, os.O_CREATE|os.O_TRUNC, 0666)
if err != nile {
return
}

readsize, err = s.Read(buffer)
if err != nil {
return
}

written, err = d.Write(buffer)
if err != nil {
return
}


// makes sure that # of bytes was written/read correctly.
if written < read {
return os.NewError(fmt.Sprintf("Not enough bytes written to %s", d.Name))
}

if read < written {
return os.NewError(fmt.Sprintf("Wrote more bytes than read to %s", d.Name))
}

return
}

For directory's, just cycle on the files from Readdirs or Readdirnames,
FileInfo does have a IsDirectory method as part of it's interface you can test
against and add a touch of recursion for walking the tree. Use os.Mkdir and
os.Mkdirall to create the paths the fils needs. Checking os.Stat will work
for checking existance.

Please note this was just submitted today:
http://code.google.com/p/go/source/detail?r=6c96d1022285

That change, changes how os.Open works. (usage above coincides with
os.OpenFile)


Mike


> On Apr 5, 5:29 pm, Evan Shaw <chicken...@gmail.com> wrote:
> > On Tue, Apr 5, 2011 at 5:24 PM, Nick Sarten <gen.bat...@gmail.com> wrote:
> > > I was just curious as to whether there's any way to copy,
> >
> > Not right now. You do it by opening the source, creating the
> > destination, and calling io.Copy(dest, src). There was a CL for adding
> > a Copy function to io/ioutil a while back, but it must've been
> > abandoned.
> >
> > > move
> >
> > os.Rename
> >
> > > or delete a file in Go.
> >
> > os.Remove
> >
> > - Evan

--
There are more things in heaven and earth than any place else.

jimmy frasche

unread,
Apr 5, 2011, 3:37:35 AM4/5/11
to Mike Ramirez, golan...@googlegroups.com
That's an awful lot of code.

import "os"
import "io"

func CopyFile(src, dst string) (int64, os.Error) {
sf, err := os.Open(src, os.O_RDONLY, 0)
if err != nil {
return 0, err
}
df, err := os.Open(dst, os.O_TRUNC|os.O_CREAT, 0644)
if err != nil {
return 0, err
}
return io.Copy(df, sf)

Dmitry Chestnykh

unread,
Apr 5, 2011, 4:31:59 AM4/5/11
to golan...@googlegroups.com, Mike Ramirez
Copying files is not as trivial as it looks. That's copying file content. However, depending on your needs, you may need to handle:

* permissions
* ACLs
* extended attributes/resource forks

...making sure you handle copying files between filesystems that may support or not support these, and following platform's best practices for it; for example, on OS X, if a destination filesystem doesn't support extended attributes, put them into AppleDouble-encoded files ._filename.

Apple's copyfile (see man copyfile) is ~3400 lines of C: http://www.opensource.apple.com/source/copyfile/copyfile-66.1/copyfile.c

I wish there were a go package for this :-)

-Dmitry

>> On Apr 5, 5:29 pm, Evan Shaw <chick...@gmail.com> wrote:

peterGo

unread,
Apr 5, 2011, 5:07:58 AM4/5/11
to golang-nuts
jimmy,

The Go convention is (dst, src) e.g. io.Copy(). It's usually good to
close files. For example,

package main

import (
"fmt"
"io"
"os"
)

func CopyFile(dst, src string) (int64, os.Error) {
sf, err := os.Open(src)
if err != nil {
return 0, err
}
defer sf.Close()
df, err := os.Create(dst)
if err != nil {
return 0, err
}
defer df.Close()
return io.Copy(df, sf)
}

func main() {
fn := "copyfile.go"
n, err := CopyFile("(copy of) "+fn, fn)
if err != nil {
fmt.Println(n, err)
}
}


Peter

Mike Ramirez

unread,
Apr 5, 2011, 5:13:51 AM4/5/11
to golan...@googlegroups.com
On Tuesday, April 05, 2011 02:07:58 am peterGo wrote:

> It's usually good to close files. For example,
>

Grr, knew I forgot something.

Mike
--
I suppose one could claim that an undocumented feature has no
semantics. :-(
-- Larry Wall in <1997102900...@wall.org>

Nick Sarten

unread,
Apr 5, 2011, 6:50:17 AM4/5/11
to golan...@googlegroups.com, Nick Sarten
I just found ioutil.ReadDir(), which appears to be a sort of directory listing command. So that leaves only copy to be done really simply.

I guess in scripting languages i've used previously i've never really thought about the underlying complexity of a simple copy command. In most cases these languages have used some command exposed through the Windows API or something. Copying a file from one place to another just doesn't seem like it should be as complicated as some of the solutions above. 

That said, i'm sure i'm oversimplifying, and am spoilt rotten by too many simplistic scripting tools :-P

jimmy frasche

unread,
Apr 5, 2011, 2:12:07 PM4/5/11
to golan...@googlegroups.com, Nick Sarten
I opened my eyes this morning and thought "forgot to defer the closes"
and didn't even know what I meant till I checked back with this
thread.

Rob 'Commander' Pike

unread,
Apr 5, 2011, 2:33:38 PM4/5/11
to jimmy frasche, golan...@googlegroups.com, Nick Sarten
The whole programming world is spoiled rotten by simplistic scripting tools.

-rob

rma...@gmail.com

unread,
Apr 5, 2011, 3:28:12 PM4/5/11
to golan...@googlegroups.com, jimmy frasche, Nick Sarten
Yes but simplicity comes at a price. I can't tell you how many times I've been burned because I can't run my script on a system because that system (1) didn't have the language installed, (2) Didn't have the right version installed, (3) didn't have the plugin / extension I needed. I've been using tclkit for years just because I can create one binary that contains both script and executable. With Go I've found that I can compile it on my dev system, and from there it will run on any other Linux system without the need of any additional libraries. I've not tried this using cgo yet...

William Waites

unread,
Apr 5, 2011, 3:39:34 PM4/5/11
to golan...@googlegroups.com, jimmy frasche, Nick Sarten
* [2011-04-05 12:28:12 -0700] rma...@gmail.com <rma...@gmail.com> �crit:

] With Go I've found that I can compile it on my dev

] system, and from there it will run on any other Linux system without the
] need of any additional libraries. I've not tried this using cgo yet...

This works just fine. In fact I did exactly this the other day to
demonstrate the same point, you don't need anything else installed,
runtimes or frameworks or whatever to just run the program. Of course
if your cgo extension uses a shared library, that shared library has
to be present as well.

Cheers,
-w
--
William Waites <mailto:w...@styx.org>
http://river.styx.org/ww/ <sip:w...@styx.org>
F4B3 39BF E775 CF42 0BAB 3DF0 BE40 A6DF B06F FD45

pascal bertrand

unread,
Apr 5, 2011, 3:56:49 PM4/5/11
to William Waites, golan...@googlegroups.com, jimmy frasche, Nick Sarten
Under Linux, use CDE[http://www.stanford.edu/~pgbovine/cde.html] for  your packaging problems.

Pascal BERTRAND



On Tue, Apr 5, 2011 at 9:39 PM, William Waites <w...@styx.org> wrote:

William Waites

unread,
Apr 5, 2011, 4:02:07 PM4/5/11
to pascal bertrand, golan...@googlegroups.com, jimmy frasche, Nick Sarten
* [2011-04-05 21:56:49 +0200] pascal bertrand <pascal....@gmail.com> �crit:

] Under Linux, use CDE[http://www.stanford.edu/~pgbovine/cde.html] for your
] packaging problems.

Merci Pascal, mais je n'ai aucune problème avec la
gestion des paquets...

ron minnich

unread,
Apr 5, 2011, 4:05:18 PM4/5/11
to William Waites, golan...@googlegroups.com, jimmy frasche, Nick Sarten
On Tue, Apr 5, 2011 at 12:39 PM, William Waites <w...@styx.org> wrote:

> * [2011-04-05 12:28:12 -0700] rma...@gmail.com <rma...@gmail.com> écrit:
>
> ] With Go I've found that I can compile it on my dev
> ] system, and from there it will run on any other Linux system without the
> ] need of any additional libraries. I've not tried this using cgo yet...
>
> This works just fine. In fact I did exactly this the other day to
> demonstrate the same point, you don't need anything else installed,
> runtimes or frameworks or whatever to just run the program. Of course
> if your cgo extension uses a shared library, that shared library has
> to be present as well.

OK, this is the second discussion today that has made me think I'm on
mars. At what point did it get to be unexpected behavior to give
someone a program and have it, so to speak, "run"? :-)

ron

William Waites

unread,
Apr 5, 2011, 4:08:54 PM4/5/11
to ron minnich, golan...@googlegroups.com, jimmy frasche, Nick Sarten
* [2011-04-05 13:05:18 -0700] ron minnich <rmin...@gmail.com> �crit:

] OK, this is the second discussion today that has made me think I'm on


] mars. At what point did it get to be unexpected behavior to give
] someone a program and have it, so to speak, "run"? :-)

Greetings earthling.

There were worries expressed to me about having to install "another
runtime" and having to manage "extra dependencies" etc.. Like if I
had written something in Ruby in a Python shop the question would
have been the same. I just demonstrated for them that with Go this
wasn't a concern.

Mike Ramirez

unread,
Apr 5, 2011, 4:11:09 PM4/5/11
to golan...@googlegroups.com
On Tuesday, April 05, 2011 01:05:18 pm ron minnich wrote:
> At what point did it get to be unexpected behavior to give
> someone a program and have it, so to speak, "run"? :-)
>
> ron

When `dependency hell` became popular venacular.
--
Documentation:
Instructions translated from Swedish by Japanese for English
speaking persons.

Reply all
Reply to author
Forward
0 new messages