File Copy

17 views
Skip to first unread message

Parth Malwankar

unread,
Nov 23, 2008, 1:35:18 PM11/23/08
to Clojure
Hello,

I am trying to translate the following Java
snippet into a file copy routine in Clojure.

public static void copy(InputStream in, OutputStream out) throws
IOException {
byte[] buffer = new byte[1024];
while (true) {
int bytesRead = in.read(buffer);
if (bytesRead == -1) break;
out.write(buffer, 0, bytesRead);
}
}

I was barely able to start:

(defn copy [iname oname]
(let [in (new FileInputStream iname)
out (new FileOutputStream oname)]
nil))

But now I am totally lost at the "nil". I am not sure how to translate
the "while" loop.

I would appreciate any pointers on how to do this (or maybe a more
ideomatic
way).

Thanks.
Parth

James Reeves

unread,
Nov 23, 2008, 1:55:58 PM11/23/08
to Clojure


On Nov 23, 6:35 pm, Parth Malwankar <parth.malwan...@gmail.com> wrote:
> I am trying to translate the following Java
> snippet into a file copy routine in Clojure.
>
>   public static void copy(InputStream in, OutputStream out)    throws
> IOException {
>     byte[] buffer = new byte[1024];
>     while (true) {
>       int bytesRead = in.read(buffer);
>       if (bytesRead == -1) break;
>       out.write(buffer, 0, bytesRead);
>     }
>   }

I wrote a stream copying function for my web framework, Compojure.
Here's my version:

(defn pipe-stream
"Pipe the contents of an InputStream into an OutputStream."
([in out]
(pipe-stream in out 4096))
([#^InputStream in #^OutputStream out bufsize]
(let [buffer (make-array (. Byte TYPE) bufsize)]
(loop [len (. in (read buffer))]
(when (pos? len)
(. out (write buffer 0 len))
(recur (. in (read buffer))))))))

It uses a loop/recur to replace the while loop. Actually, looking at
that code now, it seems a little old. You could probably cut down on a
few parethesis by replacing (. Byte TYPE) for Byte/TYPE and (. in
(read buffer)) to (.read in buffer). However, aside from minor syntax
improvements, that should do the job.

- James

Stuart Sierra

unread,
Nov 23, 2008, 2:34:46 PM11/23/08
to Clojure
Honestly, for this kind of low-level stuff I always use the Apache
Commons libraries, <http://commons.apache.org/>, esp. the Lang and IO
components. They've got every imaginable stream function, all
carefully and efficiently implemented. But if you're determined to do
it in Clojure, loop/recur is the way, as James demonstrated.
-Stuart Sierra

Parth Malwankar

unread,
Nov 23, 2008, 2:50:21 PM11/23/08
to Clojure


On Nov 24, 12:34 am, Stuart Sierra <the.stuart.sie...@gmail.com>
wrote:
> Honestly, for this kind of low-level stuff I always use the Apache
> Commons libraries, <http://commons.apache.org/>, esp. the Lang and IO
> components.  They've got every imaginable stream function, all
> carefully and efficiently implemented.  But if you're determined to do
> it in Clojure, loop/recur is the way, as James demonstrated.
> -Stuart Sierra

Yes. commons.io.FileUtils.copyFile is definitely a nicer way :)
I am still learning Java (as an when I need it for Clojure). Thanks
for the pointer.

Thanks James for the pipe-stream.
Here is the copy:

(defn copy [iname oname]
(let [in (new FileInputStream iname)
out (new FileOutputStream oname)
buffer (make-array Byte/TYPE 1024)]
(loop [len (.read in buffer)]
(when (pos? len)
(.write out buffer 0 len)
(recur (.read in buffer))))))

Parth

James G. Sack (jim)

unread,
Nov 24, 2008, 2:26:30 AM11/24/08
to clo...@googlegroups.com
Parth Malwankar wrote:
>
>
> On Nov 24, 12:34 am, Stuart Sierra <the.stuart.sie...@gmail.com>
> wrote:
>> Honestly, for this kind of low-level stuff I always use the Apache
>> Commons libraries, <http://commons.apache.org/>, esp. the Lang and IO
>> components. They've got every imaginable stream function, all
>> carefully and efficiently implemented. But if you're determined to do
>> it in Clojure, loop/recur is the way, as James demonstrated.
>> -Stuart Sierra
>
> Yes. commons.io.FileUtils.copyFile is definitely a nicer way :)
> I am still learning Java (as an when I need it for Clojure). Thanks
> for the pointer.
>

From another learner --really a java-ignoramus-extremus:
Would someone take pity and give a clojure recipe for using
commons.io.FileUtils.copyFile to copy "fileA" to "fileB" (say).

I have found and installed commons.io via package manager and it ended
up in /usr/share/java/commons-io.jar. Was that the right thing to do?

The rest of java seems to live under /usr/java/jdk1.6.0_10/

I am starting REPL via the rlwrap script posted on the wiki.

My first stumbling block seems to be how to do the import! :-(

TIA,
..jim

Stuart Sierra

unread,
Nov 24, 2008, 9:43:22 AM11/24/08
to Clojure
Ok, first you need to add the commons-io.jar to the Java classpath.
You can do this by editing the Clojure startup script. The argument
to "-cp" is a colon-separated list of directories and/or JAR files to
go on the classpath. So if the command line was this:

java -cp /path/to/clojure.jar clojure.lang.Repl

Now it will be:

java -cp /usr/share/java/commons-io.jar:/path/to/clojure.jar
clojure.lang.Repl

(Note: this may also be possible with the add-classpath function in
Clojure, but I'm not sure if that still exists/works.)

Once you've done this, restart Clojure and you should be able to
(import '(org.apache.commons.io FileUtils))

Then call (FileUtils/copyFile fileA fileB)
fileA and fileB should be instances of java.io.File.

Hope this gets you where you need to be. :)

-Stuart Sierra

James G. Sack (jim)

unread,
Nov 24, 2008, 3:34:42 PM11/24/08
to clo...@googlegroups.com
Stuart Sierra wrote:
> Ok, first you need to add the commons-io.jar to the Java classpath.
> You can do this by editing the Clojure startup script. The argument
> to "-cp" is a colon-separated list of directories and/or JAR files to
> go on the classpath. So if the command line was this:
>
> java -cp /path/to/clojure.jar clojure.lang.Repl
>
> Now it will be:
>
> java -cp /usr/share/java/commons-io.jar:/path/to/clojure.jar
> clojure.lang.Repl
>
> (Note: this may also be possible with the add-classpath function in
> Clojure, but I'm not sure if that still exists/works.)
>
> Once you've done this, restart Clojure and you should be able to
> (import '(org.apache.commons.io FileUtils))
>
> Then call (FileUtils/copyFile fileA fileB)
> fileA and fileB should be instances of java.io.File.
>
> Hope this gets you where you need to be. :)

Yes, thanks very much Stuart. I had tried just about everything you said
except I wasn't prepending the "org.apache." in the import. <sigh>

==> FYI add_classpath works fine.
As a curiosity, I notice that (System/getProperty "java.class.path")
does not reflect any change after add-classpath.
==> I wonder if this is as it should be? And if so, I am left wondering
how to determine the "real" value of the current classpath.


For possible benefit to other newbies, this is what I came up with for
inclusion in (say) user.clj. (criticism welcome)

- - -
;;Copy file (using pathnames) using the Apache.org commons library
(add-classpath "file:///usr/share/java/commons-io.jar")
(import '(org.apache.commons.io FileUtils))
(defn copyfile-byname [src cpy]
(FileUtils/copyFile (java.io.File. src) (java.io.File. cpy)))
- - -

Regards,
..jim

Michael Wood

unread,
Nov 24, 2008, 4:03:51 PM11/24/08
to clo...@googlegroups.com
On Mon, Nov 24, 2008 at 10:34 PM, James G. Sack (jim) <jgs...@san.rr.com> wrote:
[...]

> ==> FYI add_classpath works fine.
> As a curiosity, I notice that (System/getProperty "java.class.path")
> does not reflect any change after add-classpath.
> ==> I wonder if this is as it should be? And if so, I am left wondering
> how to determine the "real" value of the current classpath.
>
>
> For possible benefit to other newbies, this is what I came up with for
> inclusion in (say) user.clj. (criticism welcome)

Apparently "such use of add-classpath is discouraged":

http://groups.google.com/group/clojure/browse_thread/thread/87f40ee8788d54dd/11d4e82c3da1beb7?lnk=gst&q=%22Such+use+of+add-classpath+is+discouraged%22#11d4e82c3da1beb7

--
Michael Wood <esio...@gmail.com>

James G. Sack (jim)

unread,
Nov 24, 2008, 5:13:05 PM11/24/08
to clo...@googlegroups.com

ok... thanks.

I /am/ left believing I'll remain confused about this part of java for a
while longer. :-(

I was hoping that I could somehow tell java to look in (eg) the
/usr/share/java tree when trying to resolve imports.

If someone can direct me where I can educate myself about this aspect of
java, libs, and jar-files a bit more, that would be appreciated.
Otherwise I don't mean to hijack this list for general java questions.

Regards,
..jim

Reply all
Reply to author
Forward
0 new messages