annotate src/clojure/contrib/io.clj @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 ;;; io.clj -- duck-typed I/O streams for Clojure
rlm@10 2
rlm@10 3 ;; by Stuart Sierra, http://stuartsierra.com/
rlm@10 4 ;; May 13, 2009
rlm@10 5
rlm@10 6 ;; Copyright (c) Stuart Sierra, 2009. All rights reserved. The use
rlm@10 7 ;; and distribution terms for this software are covered by the Eclipse
rlm@10 8 ;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 9 ;; which can be found in the file epl-v10.html at the root of this
rlm@10 10 ;; distribution. By using this software in any fashion, you are
rlm@10 11 ;; agreeing to be bound by the terms of this license. You must not
rlm@10 12 ;; remove this notice, or any other, from this software.
rlm@10 13
rlm@10 14
rlm@10 15 ;; This file defines "duck-typed" I/O utility functions for Clojure.
rlm@10 16 ;; The 'reader' and 'writer' functions will open and return an
rlm@10 17 ;; instance of java.io.BufferedReader and java.io.BufferedWriter,
rlm@10 18 ;; respectively, for a variety of argument types -- filenames as
rlm@10 19 ;; strings, URLs, java.io.File's, etc. 'reader' even works on http
rlm@10 20 ;; URLs.
rlm@10 21 ;;
rlm@10 22 ;; Note: this is not really "duck typing" as implemented in languages
rlm@10 23 ;; like Ruby. A better name would have been "do-what-I-mean-streams"
rlm@10 24 ;; or "just-give-me-a-stream", but ducks are funnier.
rlm@10 25
rlm@10 26
rlm@10 27 ;; CHANGE LOG
rlm@10 28 ;;
rlm@10 29 ;; July 23, 2010: Most functions here are deprecated. Use
rlm@10 30 ;; clojure.java.io
rlm@10 31 ;;
rlm@10 32 ;; May 13, 2009: added functions to open writers for appending
rlm@10 33 ;;
rlm@10 34 ;; May 3, 2009: renamed file to file-str, for compatibility with
rlm@10 35 ;; clojure.contrib.java. reader/writer no longer use this
rlm@10 36 ;; function.
rlm@10 37 ;;
rlm@10 38 ;; February 16, 2009: (lazy branch) fixed read-lines to work with lazy
rlm@10 39 ;; Clojure.
rlm@10 40 ;;
rlm@10 41 ;; January 10, 2009: added *default-encoding*, so streams are always
rlm@10 42 ;; opened as UTF-8.
rlm@10 43 ;;
rlm@10 44 ;; December 19, 2008: rewrote reader and writer as multimethods; added
rlm@10 45 ;; slurp*, file, and read-lines
rlm@10 46 ;;
rlm@10 47 ;; April 8, 2008: first version
rlm@10 48
rlm@10 49
rlm@10 50
rlm@10 51 (ns
rlm@10 52 ^{:author "Stuart Sierra",
rlm@10 53 :doc "This file defines polymorphic I/O utility functions for Clojure.
rlm@10 54
rlm@10 55 The Streams protocol defines reader, writer, input-stream and
rlm@10 56 output-stream methods that return BufferedReader, BufferedWriter,
rlm@10 57 BufferedInputStream and BufferedOutputStream instances (respectively),
rlm@10 58 with default implementations extended to a variety of argument
rlm@10 59 types: URLs or filenames as strings, java.io.File's, Sockets, etc."}
rlm@10 60 clojure.contrib.io
rlm@10 61 (:refer-clojure :exclude (spit))
rlm@10 62 (:import
rlm@10 63 (java.io Reader InputStream InputStreamReader PushbackReader
rlm@10 64 BufferedReader File OutputStream
rlm@10 65 OutputStreamWriter BufferedWriter Writer
rlm@10 66 FileInputStream FileOutputStream ByteArrayOutputStream
rlm@10 67 StringReader ByteArrayInputStream
rlm@10 68 BufferedInputStream BufferedOutputStream
rlm@10 69 CharArrayReader)
rlm@10 70 (java.net URI URL MalformedURLException Socket)))
rlm@10 71
rlm@10 72
rlm@10 73 (def
rlm@10 74 ^{:doc "Name of the default encoding to use when reading & writing.
rlm@10 75 Default is UTF-8."
rlm@10 76 :tag "java.lang.String"}
rlm@10 77 *default-encoding* "UTF-8")
rlm@10 78
rlm@10 79 (def
rlm@10 80 ^{:doc "Size, in bytes or characters, of the buffer used when
rlm@10 81 copying streams."}
rlm@10 82 *buffer-size* 1024)
rlm@10 83
rlm@10 84 (def
rlm@10 85 ^{:doc "Type object for a Java primitive byte array."}
rlm@10 86 *byte-array-type* (class (make-array Byte/TYPE 0)))
rlm@10 87
rlm@10 88 (def
rlm@10 89 ^{:doc "Type object for a Java primitive char array."}
rlm@10 90 *char-array-type* (class (make-array Character/TYPE 0)))
rlm@10 91
rlm@10 92
rlm@10 93 (defn ^File file-str
rlm@10 94 "Concatenates args as strings and returns a java.io.File. Replaces
rlm@10 95 all / and \\ with File/separatorChar. Replaces ~ at the start of
rlm@10 96 the path with the user.home system property."
rlm@10 97 [& args]
rlm@10 98 (let [^String s (apply str args)
rlm@10 99 s (.replace s \\ File/separatorChar)
rlm@10 100 s (.replace s \/ File/separatorChar)
rlm@10 101 s (if (.startsWith s "~")
rlm@10 102 (str (System/getProperty "user.home")
rlm@10 103 File/separator (subs s 1))
rlm@10 104 s)]
rlm@10 105 (File. s)))
rlm@10 106
rlm@10 107 (def
rlm@10 108 ^{:doc "If true, writer, output-stream and spit will open files in append mode.
rlm@10 109 Defaults to false. Instead of binding this var directly, use append-writer,
rlm@10 110 append-output-stream or append-spit."
rlm@10 111 :tag "java.lang.Boolean"}
rlm@10 112 *append* false)
rlm@10 113
rlm@10 114 (defn- assert-not-appending []
rlm@10 115 (when *append*
rlm@10 116 (throw (Exception. "Cannot change an open stream to append mode."))))
rlm@10 117
rlm@10 118 ;; @todo -- Both simple and elaborate methods for controlling buffering of
rlm@10 119 ;; in the Streams protocol were implemented, considered, and postponed
rlm@10 120 ;; see http://groups.google.com/group/clojure-dev/browse_frm/thread/3e39e9b3982f542b
rlm@10 121 (defprotocol Streams
rlm@10 122 (reader [x]
rlm@10 123 "Attempts to coerce its argument into an open java.io.Reader.
rlm@10 124 The default implementations of this protocol always return a
rlm@10 125 java.io.BufferedReader.
rlm@10 126
rlm@10 127 Default implementations are provided for Reader, BufferedReader,
rlm@10 128 InputStream, File, URI, URL, Socket, byte arrays, character arrays,
rlm@10 129 and String.
rlm@10 130
rlm@10 131 If argument is a String, it tries to resolve it first as a URI, then
rlm@10 132 as a local file name. URIs with a 'file' protocol are converted to
rlm@10 133 local file names. If this fails, a final attempt is made to resolve
rlm@10 134 the string as a resource on the CLASSPATH.
rlm@10 135
rlm@10 136 Uses *default-encoding* as the text encoding.
rlm@10 137
rlm@10 138 Should be used inside with-open to ensure the Reader is properly
rlm@10 139 closed.")
rlm@10 140 (writer [x]
rlm@10 141 "Attempts to coerce its argument into an open java.io.Writer.
rlm@10 142 The default implementations of this protocol always return a
rlm@10 143 java.io.BufferedWriter.
rlm@10 144
rlm@10 145 Default implementations are provided for Writer, BufferedWriter,
rlm@10 146 OutputStream, File, URI, URL, Socket, and String.
rlm@10 147
rlm@10 148 If the argument is a String, it tries to resolve it first as a URI, then
rlm@10 149 as a local file name. URIs with a 'file' protocol are converted to
rlm@10 150 local file names.
rlm@10 151
rlm@10 152 Should be used inside with-open to ensure the Writer is properly
rlm@10 153 closed.")
rlm@10 154 (input-stream [x]
rlm@10 155 "Attempts to coerce its argument into an open java.io.InputStream.
rlm@10 156 The default implementations of this protocol always return a
rlm@10 157 java.io.BufferedInputStream.
rlm@10 158
rlm@10 159 Default implementations are defined for OutputStream, File, URI, URL,
rlm@10 160 Socket, byte array, and String arguments.
rlm@10 161
rlm@10 162 If the argument is a String, it tries to resolve it first as a URI, then
rlm@10 163 as a local file name. URIs with a 'file' protocol are converted to
rlm@10 164 local file names.
rlm@10 165
rlm@10 166 Should be used inside with-open to ensure the InputStream is properly
rlm@10 167 closed.")
rlm@10 168 (output-stream [x]
rlm@10 169 "Attempts to coerce its argument into an open java.io.OutputStream.
rlm@10 170 The default implementations of this protocol always return a
rlm@10 171 java.io.BufferedOutputStream.
rlm@10 172
rlm@10 173 Default implementations are defined for OutputStream, File, URI, URL,
rlm@10 174 Socket, and String arguments.
rlm@10 175
rlm@10 176 If the argument is a String, it tries to resolve it first as a URI, then
rlm@10 177 as a local file name. URIs with a 'file' protocol are converted to
rlm@10 178 local file names.
rlm@10 179
rlm@10 180 Should be used inside with-open to ensure the OutputStream is
rlm@10 181 properly closed."))
rlm@10 182
rlm@10 183 (def default-streams-impl
rlm@10 184 {:reader #(reader (input-stream %))
rlm@10 185 :writer #(writer (output-stream %))
rlm@10 186 :input-stream #(throw (Exception. (str "Cannot open <" (pr-str %) "> as an InputStream.")))
rlm@10 187 :output-stream #(throw (Exception. (str "Cannot open <" (pr-str %) "> as an OutputStream.")))})
rlm@10 188
rlm@10 189 (extend File
rlm@10 190 Streams
rlm@10 191 (assoc default-streams-impl
rlm@10 192 :input-stream #(input-stream (FileInputStream. ^File %))
rlm@10 193 :output-stream #(let [stream (FileOutputStream. ^File % *append*)]
rlm@10 194 (binding [*append* false]
rlm@10 195 (output-stream stream)))))
rlm@10 196 (extend URL
rlm@10 197 Streams
rlm@10 198 (assoc default-streams-impl
rlm@10 199 :input-stream (fn [^URL x]
rlm@10 200 (input-stream (if (= "file" (.getProtocol x))
rlm@10 201 (FileInputStream. (.getPath x))
rlm@10 202 (.openStream x))))
rlm@10 203 :output-stream (fn [^URL x]
rlm@10 204 (if (= "file" (.getProtocol x))
rlm@10 205 (output-stream (File. (.getPath x)))
rlm@10 206 (throw (Exception. (str "Can not write to non-file URL <" x ">")))))))
rlm@10 207 (extend URI
rlm@10 208 Streams
rlm@10 209 (assoc default-streams-impl
rlm@10 210 :input-stream #(input-stream (.toURL ^URI %))
rlm@10 211 :output-stream #(output-stream (.toURL ^URI %))))
rlm@10 212 (extend String
rlm@10 213 Streams
rlm@10 214 (assoc default-streams-impl
rlm@10 215 :input-stream #(try
rlm@10 216 (input-stream (URL. %))
rlm@10 217 (catch MalformedURLException e
rlm@10 218 (input-stream (File. ^String %))))
rlm@10 219 :output-stream #(try
rlm@10 220 (output-stream (URL. %))
rlm@10 221 (catch MalformedURLException err
rlm@10 222 (output-stream (File. ^String %))))))
rlm@10 223 (extend Socket
rlm@10 224 Streams
rlm@10 225 (assoc default-streams-impl
rlm@10 226 :input-stream #(.getInputStream ^Socket %)
rlm@10 227 :output-stream #(output-stream (.getOutputStream ^Socket %))))
rlm@10 228 (extend *byte-array-type*
rlm@10 229 Streams
rlm@10 230 (assoc default-streams-impl :input-stream #(input-stream (ByteArrayInputStream. %))))
rlm@10 231 (extend *char-array-type*
rlm@10 232 Streams
rlm@10 233 (assoc default-streams-impl :reader #(reader (CharArrayReader. %))))
rlm@10 234 (extend Object
rlm@10 235 Streams
rlm@10 236 default-streams-impl)
rlm@10 237
rlm@10 238 (extend Reader
rlm@10 239 Streams
rlm@10 240 (assoc default-streams-impl :reader #(BufferedReader. %)))
rlm@10 241 (extend BufferedReader
rlm@10 242 Streams
rlm@10 243 (assoc default-streams-impl :reader identity))
rlm@10 244 (defn- inputstream->reader
rlm@10 245 [^InputStream is]
rlm@10 246 (reader (InputStreamReader. is *default-encoding*)))
rlm@10 247 (extend InputStream
rlm@10 248 Streams
rlm@10 249 (assoc default-streams-impl :input-stream #(BufferedInputStream. %)
rlm@10 250 :reader inputstream->reader))
rlm@10 251 (extend BufferedInputStream
rlm@10 252 Streams
rlm@10 253 (assoc default-streams-impl
rlm@10 254 :input-stream identity
rlm@10 255 :reader inputstream->reader))
rlm@10 256
rlm@10 257 (extend Writer
rlm@10 258 Streams
rlm@10 259 (assoc default-streams-impl :writer #(do (assert-not-appending)
rlm@10 260 (BufferedWriter. %))))
rlm@10 261 (extend BufferedWriter
rlm@10 262 Streams
rlm@10 263 (assoc default-streams-impl :writer #(do (assert-not-appending) %)))
rlm@10 264 (defn- outputstream->writer
rlm@10 265 [^OutputStream os]
rlm@10 266 (assert-not-appending)
rlm@10 267 (writer (OutputStreamWriter. os *default-encoding*)))
rlm@10 268 (extend OutputStream
rlm@10 269 Streams
rlm@10 270 (assoc default-streams-impl
rlm@10 271 :output-stream #(do (assert-not-appending)
rlm@10 272 (BufferedOutputStream. %))
rlm@10 273 :writer outputstream->writer))
rlm@10 274 (extend BufferedOutputStream
rlm@10 275 Streams
rlm@10 276 (assoc default-streams-impl
rlm@10 277 :output-stream #(do (assert-not-appending) %)
rlm@10 278 :writer outputstream->writer))
rlm@10 279
rlm@10 280 (defn append-output-stream
rlm@10 281 "Like output-stream but opens file for appending. Does not work on streams
rlm@10 282 that are already open."
rlm@10 283 {:deprecated "1.2"}
rlm@10 284 [x]
rlm@10 285 (binding [*append* true]
rlm@10 286 (output-stream x)))
rlm@10 287
rlm@10 288 (defn append-writer
rlm@10 289 "Like writer but opens file for appending. Does not work on streams
rlm@10 290 that are already open."
rlm@10 291 {:deprecated "1.2"}
rlm@10 292 [x]
rlm@10 293 (binding [*append* true]
rlm@10 294 (writer x)))
rlm@10 295
rlm@10 296 (defn write-lines
rlm@10 297 "Writes lines (a seq) to f, separated by newlines. f is opened with
rlm@10 298 writer, and automatically closed at the end of the sequence."
rlm@10 299 [f lines]
rlm@10 300 (with-open [^BufferedWriter writer (writer f)]
rlm@10 301 (loop [lines lines]
rlm@10 302 (when-let [line (first lines)]
rlm@10 303 (.write writer (str line))
rlm@10 304 (.newLine writer)
rlm@10 305 (recur (rest lines))))))
rlm@10 306
rlm@10 307 (defn read-lines
rlm@10 308 "Like clojure.core/line-seq but opens f with reader. Automatically
rlm@10 309 closes the reader AFTER YOU CONSUME THE ENTIRE SEQUENCE."
rlm@10 310 [f]
rlm@10 311 (let [read-line (fn this [^BufferedReader rdr]
rlm@10 312 (lazy-seq
rlm@10 313 (if-let [line (.readLine rdr)]
rlm@10 314 (cons line (this rdr))
rlm@10 315 (.close rdr))))]
rlm@10 316 (read-line (reader f))))
rlm@10 317
rlm@10 318 (defn ^String slurp*
rlm@10 319 "Like clojure.core/slurp but opens f with reader."
rlm@10 320 {:deprecated "1.2"}
rlm@10 321 [f]
rlm@10 322 (with-open [^BufferedReader r (reader f)]
rlm@10 323 (let [sb (StringBuilder.)]
rlm@10 324 (loop [c (.read r)]
rlm@10 325 (if (neg? c)
rlm@10 326 (str sb)
rlm@10 327 (do (.append sb (char c))
rlm@10 328 (recur (.read r))))))))
rlm@10 329
rlm@10 330 (defn spit
rlm@10 331 "Opposite of slurp. Opens f with writer, writes content, then
rlm@10 332 closes f."
rlm@10 333 {:deprecated "1.2"}
rlm@10 334 [f content]
rlm@10 335 (with-open [^Writer w (writer f)]
rlm@10 336 (.write w content)))
rlm@10 337
rlm@10 338 (defn append-spit
rlm@10 339 "Like spit but appends to file."
rlm@10 340 {:deprecated "1.2"}
rlm@10 341 [f content]
rlm@10 342 (with-open [^Writer w (append-writer f)]
rlm@10 343 (.write w content)))
rlm@10 344
rlm@10 345 (defn pwd
rlm@10 346 "Returns current working directory as a String. (Like UNIX 'pwd'.)
rlm@10 347 Note: In Java, you cannot change the current working directory."
rlm@10 348 {:deprecated "1.2"}
rlm@10 349 []
rlm@10 350 (System/getProperty "user.dir"))
rlm@10 351
rlm@10 352 (defmacro with-out-writer
rlm@10 353 "Opens a writer on f, binds it to *out*, and evalutes body.
rlm@10 354 Anything printed within body will be written to f."
rlm@10 355 [f & body]
rlm@10 356 `(with-open [stream# (writer ~f)]
rlm@10 357 (binding [*out* stream#]
rlm@10 358 ~@body)))
rlm@10 359
rlm@10 360 (defmacro with-out-append-writer
rlm@10 361 "Like with-out-writer but appends to file."
rlm@10 362 {:deprecated "1.2"}
rlm@10 363 [f & body]
rlm@10 364 `(with-open [stream# (append-writer ~f)]
rlm@10 365 (binding [*out* stream#]
rlm@10 366 ~@body)))
rlm@10 367
rlm@10 368 (defmacro with-in-reader
rlm@10 369 "Opens a PushbackReader on f, binds it to *in*, and evaluates body."
rlm@10 370 [f & body]
rlm@10 371 `(with-open [stream# (PushbackReader. (reader ~f))]
rlm@10 372 (binding [*in* stream#]
rlm@10 373 ~@body)))
rlm@10 374
rlm@10 375 (defmulti
rlm@10 376 ^{:deprecated "1.2"
rlm@10 377 :doc "Copies input to output. Returns nil.
rlm@10 378 Input may be an InputStream, Reader, File, byte[], or String.
rlm@10 379 Output may be an OutputStream, Writer, or File.
rlm@10 380
rlm@10 381 Does not close any streams except those it opens itself
rlm@10 382 (on a File).
rlm@10 383
rlm@10 384 Writing a File fails if the parent directory does not exist."
rlm@10 385 :arglists '([input output])}
rlm@10 386 copy
rlm@10 387 (fn [input output] [(type input) (type output)]))
rlm@10 388
rlm@10 389 (defmethod copy [InputStream OutputStream] [^InputStream input ^OutputStream output]
rlm@10 390 (let [buffer (make-array Byte/TYPE *buffer-size*)]
rlm@10 391 (loop []
rlm@10 392 (let [size (.read input buffer)]
rlm@10 393 (when (pos? size)
rlm@10 394 (do (.write output buffer 0 size)
rlm@10 395 (recur)))))))
rlm@10 396
rlm@10 397 (defmethod copy [InputStream Writer] [^InputStream input ^Writer output]
rlm@10 398 (let [^"[B" buffer (make-array Byte/TYPE *buffer-size*)]
rlm@10 399 (loop []
rlm@10 400 (let [size (.read input buffer)]
rlm@10 401 (when (pos? size)
rlm@10 402 (let [chars (.toCharArray (String. buffer 0 size *default-encoding*))]
rlm@10 403 (do (.write output chars)
rlm@10 404 (recur))))))))
rlm@10 405
rlm@10 406 (defmethod copy [InputStream File] [^InputStream input ^File output]
rlm@10 407 (with-open [out (FileOutputStream. output)]
rlm@10 408 (copy input out)))
rlm@10 409
rlm@10 410 (defmethod copy [Reader OutputStream] [^Reader input ^OutputStream output]
rlm@10 411 (let [^"[C" buffer (make-array Character/TYPE *buffer-size*)]
rlm@10 412 (loop []
rlm@10 413 (let [size (.read input buffer)]
rlm@10 414 (when (pos? size)
rlm@10 415 (let [bytes (.getBytes (String. buffer 0 size) *default-encoding*)]
rlm@10 416 (do (.write output bytes)
rlm@10 417 (recur))))))))
rlm@10 418
rlm@10 419 (defmethod copy [Reader Writer] [^Reader input ^Writer output]
rlm@10 420 (let [^"[C" buffer (make-array Character/TYPE *buffer-size*)]
rlm@10 421 (loop []
rlm@10 422 (let [size (.read input buffer)]
rlm@10 423 (when (pos? size)
rlm@10 424 (do (.write output buffer 0 size)
rlm@10 425 (recur)))))))
rlm@10 426
rlm@10 427 (defmethod copy [Reader File] [^Reader input ^File output]
rlm@10 428 (with-open [out (FileOutputStream. output)]
rlm@10 429 (copy input out)))
rlm@10 430
rlm@10 431 (defmethod copy [File OutputStream] [^File input ^OutputStream output]
rlm@10 432 (with-open [in (FileInputStream. input)]
rlm@10 433 (copy in output)))
rlm@10 434
rlm@10 435 (defmethod copy [File Writer] [^File input ^Writer output]
rlm@10 436 (with-open [in (FileInputStream. input)]
rlm@10 437 (copy in output)))
rlm@10 438
rlm@10 439 (defmethod copy [File File] [^File input ^File output]
rlm@10 440 (with-open [in (FileInputStream. input)
rlm@10 441 out (FileOutputStream. output)]
rlm@10 442 (copy in out)))
rlm@10 443
rlm@10 444 (defmethod copy [String OutputStream] [^String input ^OutputStream output]
rlm@10 445 (copy (StringReader. input) output))
rlm@10 446
rlm@10 447 (defmethod copy [String Writer] [^String input ^Writer output]
rlm@10 448 (copy (StringReader. input) output))
rlm@10 449
rlm@10 450 (defmethod copy [String File] [^String input ^File output]
rlm@10 451 (copy (StringReader. input) output))
rlm@10 452
rlm@10 453 (defmethod copy [*char-array-type* OutputStream] [input ^OutputStream output]
rlm@10 454 (copy (CharArrayReader. input) output))
rlm@10 455
rlm@10 456 (defmethod copy [*char-array-type* Writer] [input ^Writer output]
rlm@10 457 (copy (CharArrayReader. input) output))
rlm@10 458
rlm@10 459 (defmethod copy [*char-array-type* File] [input ^File output]
rlm@10 460 (copy (CharArrayReader. input) output))
rlm@10 461
rlm@10 462 (defmethod copy [*byte-array-type* OutputStream] [^"[B" input ^OutputStream output]
rlm@10 463 (copy (ByteArrayInputStream. input) output))
rlm@10 464
rlm@10 465 (defmethod copy [*byte-array-type* Writer] [^"[B" input ^Writer output]
rlm@10 466 (copy (ByteArrayInputStream. input) output))
rlm@10 467
rlm@10 468 (defmethod copy [*byte-array-type* File] [^"[B" input ^Writer output]
rlm@10 469 (copy (ByteArrayInputStream. input) output))
rlm@10 470
rlm@10 471 (defn make-parents
rlm@10 472 "Creates all parent directories of file."
rlm@10 473 [^File file]
rlm@10 474 (.mkdirs (.getParentFile file)))
rlm@10 475
rlm@10 476 (defmulti
rlm@10 477 ^{:doc "Converts argument into a Java byte array. Argument may be
rlm@10 478 a String, File, InputStream, or Reader. If the argument is already
rlm@10 479 a byte array, returns it."
rlm@10 480 :arglists '([arg])}
rlm@10 481 to-byte-array type)
rlm@10 482
rlm@10 483 (defmethod to-byte-array *byte-array-type* [x] x)
rlm@10 484
rlm@10 485 (defmethod to-byte-array String [^String x]
rlm@10 486 (.getBytes x *default-encoding*))
rlm@10 487
rlm@10 488 (defmethod to-byte-array File [^File x]
rlm@10 489 (with-open [input (FileInputStream. x)
rlm@10 490 buffer (ByteArrayOutputStream.)]
rlm@10 491 (copy input buffer)
rlm@10 492 (.toByteArray buffer)))
rlm@10 493
rlm@10 494 (defmethod to-byte-array InputStream [^InputStream x]
rlm@10 495 (let [buffer (ByteArrayOutputStream.)]
rlm@10 496 (copy x buffer)
rlm@10 497 (.toByteArray buffer)))
rlm@10 498
rlm@10 499 (defmethod to-byte-array Reader [^Reader x]
rlm@10 500 (.getBytes (slurp* x) *default-encoding*))
rlm@10 501
rlm@10 502 (defmulti relative-path-string
rlm@10 503 "Interpret a String or java.io.File as a relative path string.
rlm@10 504 Building block for clojure.contrib.java/file."
rlm@10 505 {:deprecated "1.2"}
rlm@10 506 class)
rlm@10 507
rlm@10 508 (defmethod relative-path-string String [^String s]
rlm@10 509 (relative-path-string (File. s)))
rlm@10 510
rlm@10 511 (defmethod relative-path-string File [^File f]
rlm@10 512 (if (.isAbsolute f)
rlm@10 513 (throw (IllegalArgumentException. (str f " is not a relative path")))
rlm@10 514 (.getPath f)))
rlm@10 515
rlm@10 516 (defmulti ^File as-file
rlm@10 517 "Interpret a String or a java.io.File as a File. Building block
rlm@10 518 for clojure.contrib.java/file, which you should prefer
rlm@10 519 in most cases."
rlm@10 520 {:deprecated "1.2"}
rlm@10 521 class)
rlm@10 522 (defmethod as-file String [^String s] (File. s))
rlm@10 523 (defmethod as-file File [f] f)
rlm@10 524
rlm@10 525 (defn ^File file
rlm@10 526 "Returns a java.io.File from string or file args."
rlm@10 527 {:deprecated "1.2"}
rlm@10 528 ([arg]
rlm@10 529 (as-file arg))
rlm@10 530 ([parent child]
rlm@10 531 (File. ^File (as-file parent) ^String (relative-path-string child)))
rlm@10 532 ([parent child & more]
rlm@10 533 (reduce file (file parent child) more)))
rlm@10 534
rlm@10 535 (defn delete-file
rlm@10 536 "Delete file f. Raise an exception if it fails unless silently is true."
rlm@10 537 [f & [silently]]
rlm@10 538 (or (.delete (file f))
rlm@10 539 silently
rlm@10 540 (throw (java.io.IOException. (str "Couldn't delete " f)))))
rlm@10 541
rlm@10 542 (defn delete-file-recursively
rlm@10 543 "Delete file f. If it's a directory, recursively delete all its contents.
rlm@10 544 Raise an exception if any deletion fails unless silently is true."
rlm@10 545 [f & [silently]]
rlm@10 546 (let [f (file f)]
rlm@10 547 (if (.isDirectory f)
rlm@10 548 (doseq [child (.listFiles f)]
rlm@10 549 (delete-file-recursively child silently)))
rlm@10 550 (delete-file f silently)))
rlm@10 551
rlm@10 552 (defmulti
rlm@10 553 ^{:deprecated "1.2"
rlm@10 554 :doc "Coerces argument (URL, URI, or String) to a java.net.URL."
rlm@10 555 :arglists '([arg])}
rlm@10 556 as-url type)
rlm@10 557
rlm@10 558 (defmethod as-url URL [x] x)
rlm@10 559
rlm@10 560 (defmethod as-url URI [^URI x] (.toURL x))
rlm@10 561
rlm@10 562 (defmethod as-url String [^String x] (URL. x))
rlm@10 563
rlm@10 564 (defmethod as-url File [^File x] (.toURL x))