├── .gitignore ├── README.markdown ├── core ├── exception-handling.scala ├── integration-tests ├── peformanceTests └── src │ ├── main │ └── scala │ │ └── scalax │ │ └── io │ │ ├── AbstractLazyIteratorBasedBuilder.scala │ │ ├── ArrayBufferSeekableChannel.scala │ │ ├── AsyncLongTraversable.scala │ │ ├── ByteBlock.scala │ │ ├── CloseAction.scala │ │ ├── CloseableIterator.scala │ │ ├── Codec.scala │ │ ├── CompositeIterable.scala │ │ ├── Input.scala │ │ ├── JavaConverters.scala │ │ ├── Line.scala │ │ ├── LineTraversable.scala │ │ ├── LongTraversable.scala │ │ ├── LongTraversableLike.scala │ │ ├── LongTraversableMethods.txt │ │ ├── Output.scala │ │ ├── OutputConverter.scala │ │ ├── ReadChars.scala │ │ ├── Resource.scala │ │ ├── ResourceAdapting.scala │ │ ├── ResourceContext.scala │ │ ├── ResourceTraversable.scala │ │ ├── ScalaIOException.scala │ │ ├── Seekable.scala │ │ ├── SeekableByteChannel.scala │ │ ├── StreamIterator.scala │ │ ├── TraversableOnceOps.scala │ │ ├── WriteChars.scala │ │ ├── extractor │ │ ├── FileChannelExtractor.scala │ │ ├── ReadableByteChannelExtractor.scala │ │ └── WritableChannelExtractor.scala │ │ ├── managed │ │ ├── ByteChannelResource.scala │ │ ├── InputStreamResource.scala │ │ ├── OutputStreamResource.scala │ │ ├── ReadableByteChannelResource.scala │ │ ├── ReaderResource.scala │ │ ├── SeekableByteChannelResource.scala │ │ ├── WritableByteChannelResource.scala │ │ └── WriterResource.scala │ │ ├── nio │ │ ├── ByteBuffer.scala │ │ └── SeekableFileChannel.scala │ │ ├── open-option.scala │ │ ├── package.scala │ │ ├── processing │ │ ├── ByteProcessorAPI.scala │ │ ├── CharProcessorAPI.scala │ │ ├── OutputProcessor.scala │ │ ├── Processor.scala │ │ ├── ProcessorAPI.scala │ │ ├── ProcessorTransformer.scala │ │ ├── SeekableProcessor.scala │ │ ├── SpecializedBufferedIterator.scala │ │ ├── SpecificApiFactory.scala │ │ ├── WriteCharsProcessor.scala │ │ └── repeating.scala │ │ ├── support │ │ ├── ArrayIterator.scala │ │ ├── DeletingFileOutputStream.scala │ │ ├── FileUtils.scala │ │ ├── Misc.scala │ │ └── NioByteBufferIterator.scala │ │ ├── traversable │ │ ├── ByteResourceTraversable.scala │ │ ├── ChannelBlockLongTraversable.scala │ │ ├── ReadableByteChannelResourceTraversable.scala │ │ ├── ReaderResourceTraversable.scala │ │ └── Sliceable.scala │ │ └── unmanaged │ │ ├── ReadableByteChannelResource.scala │ │ ├── ReaderResource.scala │ │ ├── WritableByteChannelResource.scala │ │ ├── WriterResource.scala │ │ └── package.scala │ ├── samples │ └── scala │ │ ├── InputComposition.scala │ │ ├── access-segment-of-input.scala │ │ ├── asFooConverter.scala │ │ ├── async-read-write.scala │ │ ├── basic-read-write.scala │ │ ├── lines.scala │ │ ├── longTraversable-as-seq.scala │ │ ├── more-input.scala │ │ ├── more-output.scala │ │ ├── processing.scala │ │ ├── resources.scala │ │ ├── seekable.scala │ │ ├── standard-java-interop.scala │ │ └── writing-with-typeclasses.scala │ └── test │ ├── resources │ └── resources │ │ └── image.png │ └── scala │ ├── scalaio │ └── test │ │ ├── AbstractInputTests.scala │ │ ├── AbstractOutputTests.scala │ │ ├── AbstractReadCharsTests.scala │ │ ├── AbstractSeekableTests.scala │ │ ├── AbstractWriteCharsTests.scala │ │ ├── ArrayBufferSeekableTests.scala │ │ ├── CloseActionTest.scala │ │ ├── Constants.scala │ │ ├── DataIndependentongTraversableTest.scala │ │ ├── FileSeekableTest.scala │ │ ├── InputStreamResourceTest.scala │ │ ├── JavaConversionsTest.scala │ │ ├── LongTraversableTest.scala │ │ ├── LongTraversableViewTest.scala │ │ ├── OutputStreamResourceTest.scala │ │ ├── ProcessorTest.scala │ │ ├── ResourceTest.scala │ │ ├── SeekableTestUtils.scala │ │ ├── UnmanagedResourceTests.scala │ │ ├── channel │ │ ├── InputTest.scala │ │ ├── OutputTest.scala │ │ └── SeekableBackedInputTest.scala │ │ ├── processing │ │ └── ProcessorAsyncTest.scala │ │ └── stream │ │ ├── InputTest.scala │ │ ├── OutputTest.scala │ │ ├── ReadCharsTest.scala │ │ └── WriteCharsTest.scala │ └── scalax │ ├── io │ ├── ByteChannelResourceTraversableTest.scala │ ├── ReaderResourceTraversableTest.scala │ ├── ResourceTraversableTest.scala │ └── StreamIteratorTest.scala │ └── test │ └── sugar │ ├── AssertionSugar.scala │ └── IOSugar.scala ├── documentation └── src │ └── main │ ├── example_projects │ ├── example-maven-project │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── scala │ │ │ └── Main.scala │ └── example-sbt-project │ │ ├── build.sbt │ │ └── src │ │ └── main │ │ └── scala │ │ └── Main.scala │ ├── java │ └── JavaIOExample.java │ ├── resources │ ├── app │ │ ├── core │ │ │ └── index.html │ │ ├── css │ │ │ ├── img │ │ │ │ └── texture_1.png │ │ │ ├── main.css │ │ │ ├── samples.css │ │ │ ├── shCore.css │ │ │ └── shThemeDefault.css │ │ ├── favicon.ico │ │ ├── file │ │ │ └── index.html │ │ ├── getting-started │ │ │ └── index.html │ │ ├── index.html │ │ ├── js │ │ │ ├── controllers.js │ │ │ ├── keywords.js │ │ │ ├── shAutoloader.js │ │ │ ├── shBrushScala.js │ │ │ └── shCore.js │ │ ├── json │ │ │ └── nav.json │ │ ├── overview │ │ │ └── template.html │ │ ├── performance │ │ │ └── index.html │ │ ├── releaseNotes │ │ │ └── index.html │ │ └── roadmap │ │ │ └── index.html │ ├── favicon.ico │ ├── index.html │ └── version-controller.js │ └── scala │ ├── ScalaIOExample.scala │ └── ShapefileDatastore.scala ├── file ├── src │ ├── main │ │ └── scala │ │ │ └── scalax │ │ │ └── file │ │ │ ├── AccessSet.scala │ │ │ ├── Exceptions.scala │ │ │ ├── FileOps.scala │ │ │ ├── FileSystem.scala │ │ │ ├── FileSystemPlugins.scala │ │ │ ├── GlobParser.scala │ │ │ ├── ImplicitConversions.scala │ │ │ ├── ImplicitConverters.scala │ │ │ ├── Path.scala │ │ │ ├── PathMatcher.scala │ │ │ ├── PathMatcherFactory.scala │ │ │ ├── PathSet.scala │ │ │ ├── PathSetLike.scala │ │ │ ├── PathURLStreamHandlerFactory.scala │ │ │ ├── attributes │ │ │ └── file_attributes.scala │ │ │ ├── defaultfs │ │ │ ├── DefaultFileOps.scala │ │ │ ├── DefaultFileSystem.scala │ │ │ └── DefaultPath.scala │ │ │ ├── option.scala │ │ │ ├── path-set.scala │ │ │ └── ramfs │ │ │ ├── Handler.scala │ │ │ ├── RamFileOps.scala │ │ │ ├── RamFileSystem.scala │ │ │ ├── RamPath.scala │ │ │ └── tree.scala │ ├── samples │ │ └── scala │ │ │ ├── PathsToJavaFile.scala │ │ │ ├── create-and-delete-files-and-directories.scala │ │ │ ├── create-and-move-files-and-directories.scala │ │ │ ├── create-paths.scala │ │ │ ├── create-temp.scala │ │ │ ├── creating-pathsets.scala │ │ │ ├── file-locking-and-block-execution.scala │ │ │ ├── implicits.scala │ │ │ ├── path-matching.scala │ │ │ ├── read-write-files.scala │ │ │ ├── readme │ │ │ ├── roots.scala │ │ │ ├── standard-path-operations.scala │ │ │ └── using-pathsets.scala │ └── test │ │ ├── resources │ │ └── resources │ │ │ ├── image.png │ │ │ └── text │ │ └── scala │ │ ├── scalaio │ │ └── test │ │ │ ├── AbstractFileOpsTests.scala │ │ │ ├── AbstractPathSetTests.scala │ │ │ ├── GlobParserTest.scala │ │ │ ├── Node.scala │ │ │ ├── PathMatcherFactoryTest.scala │ │ │ ├── ScalaIoMocks.scala │ │ │ ├── URLStreamHandlerFactoryTest.scala │ │ │ └── fs │ │ │ ├── FileSystemFixture.scala │ │ │ ├── Fixture.scala │ │ │ ├── FsAccessSetTests.scala │ │ │ ├── FsBasicPathTests.scala │ │ │ ├── FsFileOpsTests.scala │ │ │ ├── FsFileSystemTests.scala │ │ │ ├── FsMatchingTests.scala │ │ │ ├── FsPathObjectTests.scala │ │ │ ├── FsPathSetTests.scala │ │ │ ├── FsSeekableTests.scala │ │ │ ├── defaultfs │ │ │ ├── AllTests.scala │ │ │ └── DefaultFixture.scala │ │ │ └── ram │ │ │ ├── BackSlashTests.scala │ │ │ ├── ForwardSlashTests.scala │ │ │ └── RamFixture.scala │ │ └── scalax │ │ └── test │ │ └── sugar │ │ └── FSAssertionSugar.scala └── todo ├── notes ├── 0.1.1.markdown ├── 0.3.0.markdown ├── 0.4.0.markdown └── about.markdown ├── perf └── src │ └── main │ └── scala │ └── scalax │ └── io │ ├── Buffers.scala │ └── perf │ ├── AbstractFileSeekableTest.scala │ ├── AbstractInputTest.scala │ ├── AbstractOutputTest.scala │ ├── AbstractReadCharsTest.scala │ ├── AbstractReadableByteChannelInputTest.scala │ ├── AbstractSeekableTest.scala │ ├── AbstractWritableByteChannelOutputTest.scala │ ├── AbstractWriteCharsTest.scala │ ├── CountFunction.scala │ ├── Main.scala │ ├── NullOutputStream.scala │ ├── PerformanceSuite.scala │ ├── SmallDataSet.scala │ ├── SmallMediumDataSet.scala │ ├── Utils.scala │ ├── channel │ ├── FileBase.scala │ ├── MemoryBase.scala │ ├── SeekableBase.scala │ ├── input │ │ └── Input.scala │ └── output │ │ └── Output.scala │ ├── file │ ├── CopyFiles.scala │ ├── HardDriveScan.scala │ └── TraverseDirTreePerformanceTest.scala │ ├── iterator │ └── CloseableIteratorPerformanceTest.scala │ ├── reader │ ├── FileBase.scala │ ├── Input.scala │ └── MemoryBase.scala │ ├── seekable │ ├── AbstractArrayBufferSeekableTest.scala │ ├── PerformanceSuite.scala │ ├── SmallMediumSetFileSeekable.scala │ ├── SmallMediumSetMemorySeekable.scala │ ├── SmallSetFileSeekable.scala │ └── SmallSetMemorySeekable.scala │ ├── stream │ ├── FileBase.scala │ ├── MemoryBase.scala │ ├── input │ │ └── Input.scala │ └── output │ │ └── Output.scala │ └── writer │ ├── FileBase.scala │ ├── MemoryBase.scala │ └── Output.scala ├── project ├── Build.scala ├── Example.scala ├── ExampleProjects.scala ├── Keyword.scala ├── PerformanceReport.scala ├── StopWords.scala ├── WebsiteModel.scala ├── build.properties └── plugins.sbt ├── sbt └── sbt-launch-0.13.2.jar /.gitignore: -------------------------------------------------------------------------------- 1 | docs 2 | cobertura.ser 3 | project/boot/ 4 | target/ 5 | lib_managed/ 6 | /lib/ 7 | project/plugins/src_managed/ 8 | *.iws 9 | derby.log 10 | .idea 11 | *.iml -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | The goal of this project is to create an Input/Output and filesystem access API for scala. 2 | 3 | The main inspiration is the Java 7 NIO file API combined with the scala-arm project being worked on by jseureth. 4 | 5 | The implementation will work with Java 6+ and will depend on scala-arm but not on the Java 7 NIO file API. 6 | 7 | There are two main components to the API. Core and File. Core deals with obtaining data from streams, channels, etc... Basically adapting the IO object of the underlying platform (JVM, CLR) to be more idiomatic Scala. 8 | 9 | For details see [http://jesseeichar.github.com/scala-io-doc/](http://jesseeichar.github.com/scala-io-doc/). -------------------------------------------------------------------------------- /core/exception-handling.scala: -------------------------------------------------------------------------------- 1 | import java.io.File 2 | 3 | /** 4 | * Examples of how to provide custom error handlers when using Scala IO. 5 | *
6 | * By default a ScalaIOException is thrown when an error occurs accessing or closing a resource. The following examples illustrate how 7 | * this default behaviour can be customized for a specific application. 8 | *
9 | */ 10 | object ExceptionHandling { 11 | /** 12 | * Add a custom error handler that in the case of an error during closing simply logs the error and returns the result that 13 | * was calculated before closing. 14 | */ 15 | def logClosingError { 16 | import scalax.io._ 17 | 18 | // Create a new ResourceContext instance that provides a custom errorHandler method 19 | // Note: the openErrorHandler is not overridden so failure to open resource will use 20 | // default behaviour 21 | val context = new ResourceContext { 22 | override def errorHandler[U](accessResult: Either[Throwable, U], closingExceptions: List[Throwable]): U = { 23 | def throwError(t: Throwable) = throw t 24 | def logClosingErrorAndReturn(result: U) = { 25 | closingExceptions.foreach(_.printStackTrace()) 26 | result 27 | } 28 | accessResult.fold(throwError, logClosingErrorAndReturn) 29 | } 30 | } 31 | 32 | // after creating a resource assign context object to the Resource 33 | Resource.fromFile("someFile").updateContext(context).string 34 | 35 | // Remember Resources are immutable, so a new instance is created by updateContext 36 | // the following will not work: 37 | 38 | val resourceWithDefaultErrorHandler = Resource.fromFile("someFile") 39 | val resourceWithCustomErrorHandler = resourceWithDefaultErrorHandler.updateContext(context) 40 | // resourceWithDefaultErrorHandler != resourceWithDefaultErrorHandler 41 | // they are 2 different object and have 2 different ResourceContext objects 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /core/integration-tests: -------------------------------------------------------------------------------- 1 | Move more bytes in a single file than can fit in buffer 2 | Patch more bytes than can fit in buffer 3 | append more bytes than can fit in buffer 4 | insert data into start of large file 5 | patch a file with a very large string (several MB) in to a large file 6 | test DirectoryStream memory usage. Make sure that iterating through a DirectoryStream takes place in constant size 7 | -------------------------------------------------------------------------------- /core/peformanceTests: -------------------------------------------------------------------------------- 1 | Input 2 | Output 3 | Seekable 4 | ReadChars 5 | WriteChars 6 | 7 | test things like: 8 | file.ops.bytes.take(10).drop(300) 9 | file.ops.bytes.slice(10,300) 10 | file.ops.bytes.slice(10,300) ++ List[Byte](1,2,3,4,5,6) 11 | 12 | specifically test: 13 | (Chars and ints) 14 | file.ops.bytes ++ List(1,2,3,4,5).map{_.toByte}.drop(1000000) 15 | file.ops.bytes flatMap {i => List(1,i)}.drop(1000000) 16 | file.ops.bytes filter {i => List(1,i)}.drop(1000000) 17 | 18 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/AbstractLazyIteratorBasedBuilder.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | import scala.collection.mutable.Queue 3 | import scala.collection.mutable.Builder 4 | 5 | abstract class AbstractLazyIteratorBasedBuilder[A, +Repr] extends Builder[A, Repr] { 6 | val builderIterators: Queue[() => Iterator[A]] = Queue.empty 7 | override def clear() = builderIterators.clear() 8 | 9 | private def addCollector(xs: TraversableOnce[A]) { 10 | val collector = new Collector 11 | collector.elements ++= xs 12 | builderIterators += collector 13 | } 14 | override def +=(elem: A): this.type = { 15 | builderIterators match { 16 | case bi if bi.nonEmpty && bi.last.isInstanceOf[Collector] => 17 | bi.last.asInstanceOf[Collector].elements += elem 18 | case _ => addCollector(Iterator.single(elem)) 19 | } 20 | this 21 | } 22 | def addIter(iter: () => Iterator[A]) = builderIterators += iter 23 | override def ++=(xs: TraversableOnce[A]): this.type = { 24 | xs match { 25 | case lt: LongTraversableLike[_, _] => builderIterators += (() => lt.iterator) 26 | case xs if xs.isTraversableAgain => builderIterators += (() => xs.toIterator) 27 | case xs if builderIterators.nonEmpty && builderIterators.last.isInstanceOf[Collector] => 28 | builderIterators.last.asInstanceOf[Collector].elements ++= xs 29 | case xs => { 30 | addCollector(xs) 31 | } 32 | } 33 | this 34 | } 35 | class Collector extends Function0[Iterator[A]] { 36 | val elements = Queue.empty[A] 37 | def apply() = elements.toIterator 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/ArrayBufferSeekableChannel.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | 3 | /* __ *\ 4 | ** ________ ___ / / ___ Scala API ** 5 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 6 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 7 | ** /____/\___/_/ |_/____/_/ | | ** 8 | ** |/ ** 9 | \* */ 10 | 11 | import java.io.IOException 12 | import java.lang.Math.min 13 | import collection.mutable.ArrayBuffer 14 | import scalax.io.StandardOpenOption._ 15 | 16 | class ArrayBufferSeekableChannel(data:ArrayBuffer[Byte], 17 | openOptions: OpenOption*) 18 | (forceDeleteAction: (ArrayBufferSeekableChannel)=>Unit = _ => (), 19 | closeAction:(ArrayBufferSeekableChannel) => Unit = _ => ()) extends SeekableByteChannel { 20 | 21 | var closed = false 22 | var position = 0L 23 | 24 | if(openOptions contains Truncate) data.clear() 25 | if(openOptions contains Append) position = data.size 26 | 27 | override def write (src: java.nio.ByteBuffer):Int = { 28 | val traversable = new Traversable[Byte]() { 29 | def foreach[U](f: Byte => U): Unit = { 30 | (src.position until src.limit) foreach {i => f(src get i)} 31 | } 32 | 33 | override lazy val size = super.size 34 | } 35 | 36 | data.remove(position.toInt, min(traversable.size, data.size - position.toInt)) 37 | data.insertAll(position.toInt, traversable) 38 | position += traversable.size 39 | 40 | src.position(src.limit) 41 | 42 | traversable.size 43 | } 44 | override def truncate (size: Long):scalax.io.SeekableByteChannel = { 45 | data.reduceToSize(size.toInt) 46 | position = min(data.size, size) 47 | this 48 | } 49 | override def size = data.size 50 | override def read (dst: java.nio.ByteBuffer):Int = { 51 | if(position.toInt < data.size) { 52 | val toRead = data.view.slice(position.toInt, min(position.toInt + dst.limit-dst.position, data.size)) 53 | toRead foreach {b => dst.put(b)} 54 | position += toRead.size 55 | toRead.size 56 | } else { 57 | -1 58 | } 59 | } 60 | override def position (newPosition: Long):ArrayBufferSeekableChannel = { 61 | // TODO maybe new exception? 62 | if(newPosition > Int.MaxValue) throw new IOException(newPosition + " is larger than a Ram file can be"); 63 | position = newPosition.toInt 64 | this 65 | } 66 | 67 | override def close() = { 68 | closed = true 69 | if(openOptions contains DeleteOnClose) forceDeleteAction(this) 70 | closeAction(this) 71 | } 72 | override def isOpen() = !closed 73 | 74 | } 75 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/ByteBlock.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | 3 | trait ByteBlock { 4 | private[this] val self = this 5 | def apply(i: Int): Byte 6 | def size: Int 7 | def force:ByteBlock = new ByteBlock { 8 | val data = self.toSeq 9 | override val force = this 10 | override val toSeq = data 11 | override val toIterator = data.toIterator 12 | val size = data.size 13 | def apply(i:Int) = data(i) 14 | } 15 | 16 | def toSeq = toIterator.foldLeft(Seq[Byte]())((acc,next) => acc :+ next) 17 | def toIterator = new Iterator[Byte] { 18 | private[this] val _size = self.size 19 | private[this] var pos = 0 20 | def next = { 21 | pos += 1 22 | self.apply(pos - 1) 23 | } 24 | def hasNext = 25 | pos < _size 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/CompositeIterable.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | import scala.collection.mutable.Queue 3 | 4 | class CompositeIterable[A](builderIterators: Seq[() => Iterator[A]]) { 5 | def iterator = { 6 | val iterators = Queue(builderIterators: _*) 7 | if (iterators.isEmpty) CloseableIterator.empty[A] 8 | else new CloseableIterator[A] { 9 | val toClose = Queue.empty[Iterator[A]] 10 | var now = iterators.dequeue.apply() 11 | def next = now.next 12 | def hasNext = { 13 | if (now.hasNext) true 14 | else if (iterators.isEmpty) false 15 | else { 16 | toClose += now 17 | now = iterators.dequeue().apply() 18 | hasNext 19 | } 20 | } 21 | def doClose = { 22 | import CloseableIterator.safeClose 23 | safeClose(now) ++ toClose.flatMap(safeClose) ++ 24 | iterators.map(_.apply()).flatMap(safeClose) 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/Line.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io 10 | 11 | /** 12 | * A modularizing object for containing objects/classes related to reading lines 13 | */ 14 | object Line { 15 | object Terminators { 16 | 17 | /** 18 | * The super class for different types of line terminators/separators 19 | * 20 | * @see [[scalax.io.LineTraversable]] 21 | */ 22 | sealed abstract class Terminator 23 | /** 24 | * The Auto terminator detects the line terminator. 25 | * It can detect N,R and RN line terminators 26 | */ 27 | case object Auto extends Terminator 28 | 29 | abstract class SimpleTerminator(val sep:String) extends Terminator 30 | /* 31 | * The \n line terminator 32 | */ 33 | case object NewLine extends SimpleTerminator("\n") 34 | /** 35 | * The \r line terminator 36 | */ 37 | case object CarriageReturn extends SimpleTerminator("\r") 38 | /** 39 | * The \r\n line terminator 40 | */ 41 | case object RNPair extends SimpleTerminator("\r\n") 42 | /** 43 | * A custom line terminator. It can be an arbitrary string 44 | */ 45 | case class Custom(separator: String) extends SimpleTerminator(separator) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/LongTraversableMethods.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | override /*TraversableLike*/ def scanLeft[B, That](z: B)(op: (B, A) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {} 4 | override /*TraversableLike*/ def scanRight[B, That](z: B)(op: (A, B) => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {} 5 | 6 | override /*TraversableLike*/ def span(p: A => Boolean): (Repr, Repr) = {} 7 | 8 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/ReadChars.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io 10 | 11 | import scala.collection.Traversable 12 | import Line._ 13 | import java.net.{URL, URLConnection} 14 | import java.io.{Reader, File} 15 | 16 | /** 17 | * An trait for objects that viewed as a sequence of characters. For example java.io.Reader 18 | * a ReadChars object (or be converted to a ReadChars object). 19 | * 20 | * Note: All collections returned are non-strict collections and each 21 | * invocation of a method will typically open a new stream or channel. 22 | * That behaviour can be overrided by the implementation but 23 | * it is the default behaviour. 24 | * 25 | * The Default implementation is based on providing an implementation for 26 | * chars method and all other methods are implemented using 27 | * that method. 28 | * 29 | * @author Jesse Eichar 30 | * @since 1.0 31 | * 32 | * @see [[scalax.io.Output]] 33 | * @see [[scalax.io.Input]] 34 | * @see [[scalax.io.WriteChars]] 35 | */ 36 | trait ReadChars { 37 | /** 38 | * Get the Resource context that configures how the underlying resource is accessed 39 | * 40 | * @return the associated ResourceContext 41 | */ 42 | def context:ResourceContext 43 | /** 44 | * The characters in the object. 45 | * 46 | * @return 47 | * an traversable of all the characters 48 | */ 49 | def chars: LongTraversable[Char] 50 | /** 51 | * Obtain an non-strict traversable for iterating through the lines in the object 52 | * 53 | * @param terminator 54 | * The strategy for determining the end of line 55 | * Default is to auto-detect the EOL 56 | * @param includeTerminator 57 | * if true then the line will end with the line terminator 58 | * Default is false 59 | * 60 | * @return 61 | * a non-strict traversable for iterating through all the lines 62 | */ 63 | def lines(terminator: Terminators.Terminator = Terminators.Auto, 64 | includeTerminator: Boolean = false): LongTraversable[String] = { 65 | new LineTraversable(chars.iterator, terminator, includeTerminator, context) 66 | } 67 | /** 68 | * Loads all the characters into memory. There is no protection against 69 | * loading very large files/amounts of data. 70 | */ 71 | def string = chars.mkString 72 | 73 | } 74 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/ScalaIOException.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | 3 | import java.io.{PrintStream, PrintWriter, IOException} 4 | 5 | object ScalaIOException { 6 | private def throwableString (t:Throwable) = t.getClass + "("+t.getMessage+")" 7 | } 8 | import ScalaIOException.throwableString 9 | case class ScalaIOException(accessException: Option[Throwable], closeExceptions: List[Throwable]) 10 | extends IOException({ 11 | val m = accessException.map(e => "MainException: " + throwableString(e)).getOrElse("No Main Exception") :: closeExceptions.map(throwableString _) mkString "\n---\n" 12 | m 13 | }) { 14 | 15 | lazy val trace = (accessException.toList ++ closeExceptions).flatMap(_.getStackTrace()).toArray 16 | 17 | override def getStackTrace() = trace 18 | 19 | override def getCause = (accessException orElse closeExceptions.headOption).get 20 | 21 | override def toString = 22 | getMessage 23 | 24 | lazy val fullString = 25 | getMessage() + trace.mkString ("\n\t", "\n\t", "") 26 | override def printStackTrace() = println(fullString) 27 | 28 | override def printStackTrace(s: PrintStream) = s.print(fullString) 29 | 30 | override def printStackTrace(s: PrintWriter) = s.print(fullString) 31 | } 32 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/StreamIterator.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io 10 | 11 | import java.io.{ 12 | InputStream, Reader 13 | } 14 | 15 | protected[io] class StreamIterator[E](nextElem : => Option[E]) extends Iterator[E] { 16 | var i = nextElem 17 | def hasNext = i.isDefined 18 | def next() : E = { 19 | if(!hasNext) throw new java.util.NoSuchElementException() 20 | 21 | val n = i 22 | i = nextElem 23 | n.get 24 | } 25 | } 26 | 27 | private[io] object StreamIterator { 28 | def apply[E](nextElem : => Option[E]) = new StreamIterator(nextElem) 29 | def apply(inputStream : InputStream) = apply[Int] { 30 | val i = inputStream.read() 31 | if(i == -1) None 32 | else Some(i) 33 | } 34 | def apply(reader : Reader) = apply[Char] { 35 | val i = reader.read() 36 | if(i == -1) None 37 | else Some(i.toChar) 38 | } 39 | def apply(reader : Reader, from : Codec, to : Codec ) = apply[Char] { 40 | val i = reader.read() 41 | if(i == -1) None 42 | else Some(from.translate(i.toChar.toString)(to).head) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/TraversableOnceOps.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io 10 | 11 | import scala.annotation.tailrec 12 | import scala.collection.immutable.VectorBuilder 13 | 14 | /** 15 | * Provides some convenience methods for certain operations on TraversableOnce 16 | */ 17 | private[io] object TraversableOnceOps { 18 | def splitAt[T](data:TraversableOnce[T], index:Int):(TraversableOnce[T],TraversableOnce[T]) = { 19 | data match { 20 | case t:Traversable[_] => t.asInstanceOf[Traversable[T]].splitAt(index) 21 | case _ => 22 | val iter = data.toIterator 23 | val builder = new VectorBuilder[T]() 24 | var i = 0 25 | while(i < index && iter.hasNext) { 26 | builder += iter.next() 27 | i += 1 28 | } 29 | (builder.result,iter) 30 | } 31 | } 32 | def drop[T](data:TraversableOnce[T], length:Int) = { 33 | data match { 34 | case t:Traversable[_] => t.asInstanceOf[Traversable[T]] drop length 35 | case _ => data.toIterator drop length 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/extractor/FileChannelExtractor.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.extractor 2 | 3 | import java.nio.channels.FileChannel 4 | import java.io.FileInputStream 5 | import scalax.io.nio.SeekableFileChannel 6 | import scalax.io.Adapter 7 | 8 | object FileChannelExtractor { 9 | def unapply(obj:Any):Option[FileChannel] = 10 | obj match { 11 | case fin:FileInputStream => Some(fin.getChannel) 12 | case sfc:SeekableFileChannel => Some(sfc.self) 13 | case fc:FileChannel => Some(fc) 14 | case ad:Adapter[_] => unapply(ad.src) 15 | case _ => None 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/extractor/ReadableByteChannelExtractor.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.extractor 2 | 3 | import java.nio.channels.Channel 4 | import java.io.FileInputStream 5 | import java.nio.channels.Channels 6 | import java.io.InputStream 7 | import java.nio.channels.ReadableByteChannel 8 | import scalax.io.Adapter 9 | 10 | object ReadableByteChannelExtractor { 11 | def unapply(obj:Any):Option[ReadableByteChannel] = obj match { 12 | case ad:Adapter[_] => unapply(ad.src) 13 | case in:FileInputStream => Some(in.getChannel()) 14 | case in:InputStream => Some(Channels.newChannel(in)) 15 | case chan:ReadableByteChannel => Some(chan) 16 | case _ => None 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/extractor/WritableChannelExtractor.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.extractor 2 | 3 | import java.io.FileInputStream 4 | import java.io.OutputStream 5 | import java.nio.channels.Channels 6 | import java.nio.channels.WritableByteChannel 7 | 8 | import scalax.io.Adapter 9 | 10 | object WritableByteChannelExtractor { 11 | def unapply(obj:Any):Option[WritableByteChannel] = obj match { 12 | case ad:Adapter[_] => unapply(ad.src) 13 | case out:FileInputStream => Some(out.getChannel()) 14 | case out:OutputStream => Some(Channels.newChannel(out)) 15 | case chan:WritableByteChannel => Some(chan) 16 | case _ => None 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/managed/InputStreamResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package managed 3 | 4 | import java.io.{InputStreamReader, Reader, BufferedInputStream, InputStream} 5 | import java.nio.channels.Channels 6 | import scalax.io.ResourceAdapting.ReadableChannelAdapter 7 | import java.lang.String 8 | import java.nio.ByteBuffer 9 | import java.nio.channels.ReadableByteChannel 10 | 11 | /** 12 | * A ManagedResource for accessing and using InputStreams. Class can be created using the [[scalax.io.Resource]] object. 13 | */ 14 | class InputStreamResource[+A <: InputStream] ( 15 | opener: => A, 16 | val context:ResourceContext = DefaultResourceContext, 17 | closeAction: CloseAction[A] = CloseAction.Noop, 18 | protected val sizeFunc:() => Option[Long] = () => None) 19 | extends InputResource[A] 20 | with ResourceOps[A, InputStreamResource[A]] { 21 | 22 | self => 23 | 24 | def open():OpenedResource[A] = new CloseableOpenedResource(opener,context, closeAction) 25 | 26 | def updateContext(newContext:ResourceContext) = new InputStreamResource(opener, newContext, closeAction, sizeFunc) 27 | override def addCloseAction(newCloseAction: CloseAction[A]) = 28 | new InputStreamResource(opener, context, newCloseAction :+ closeAction, sizeFunc) 29 | 30 | def inputStream = this 31 | 32 | override def toString: String = "InputStreamResource("+context.descName.name+")" 33 | 34 | def reader(implicit sourceCodec: Codec) = { 35 | def nResource = { 36 | val a = open() 37 | new InputStreamReader(a.get, sourceCodec.charSet) with Adapter[A] { 38 | def src = a.get 39 | } 40 | } 41 | val closer = ResourceAdapting.closeAction(closeAction) 42 | new ReaderResource(nResource,context, closer) 43 | } 44 | 45 | def readableByteChannel:ReadableByteChannelResource[ReadableByteChannel] = { 46 | def nResource = new ReadableChannelAdapter(opener) 47 | val closer = ResourceAdapting.closeAction(closeAction) 48 | new ReadableByteChannelResource(nResource, context, closer, sizeFunc) 49 | } 50 | def chars(implicit codec: Codec) = reader(codec).chars 51 | override def blocks(blockSize: Option[Int] = None): LongTraversable[ByteBlock] = { 52 | def toChannelOpen = { 53 | val opened = open 54 | val closer = CloseAction((_:ReadableByteChannel) => if(false) opened.close()) // WTF see other InputStreamResource 55 | 56 | new CloseableOpenedResource (Channels.newChannel(opened.get), context, closer) 57 | } 58 | new traversable.ChannelBlockLongTraversable(blockSize, context, sizeFunc, toChannelOpen) 59 | } 60 | 61 | override def bytesAsInts : LongTraversable[Int] = readableByteChannel.bytesAsInts 62 | override def bytes : LongTraversable[Byte] = readableByteChannel.bytes 63 | } 64 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/managed/OutputStreamResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package managed 3 | 4 | import java.io.{OutputStream, BufferedOutputStream, Writer, OutputStreamWriter} 5 | import java.nio.channels.{Channels,WritableByteChannel} 6 | import scalax.io.ResourceAdapting.WritableChannelAdapter 7 | 8 | /** 9 | * A ManagedResource for accessing and using OutputStreams. Class can be created using the [[scalax.io.Resource]] object. 10 | */ 11 | class OutputStreamResource[+A <: OutputStream] ( 12 | opener: => A, 13 | val context:ResourceContext = DefaultResourceContext, 14 | closeAction: CloseAction[A] = CloseAction.Noop) 15 | extends OutputResource[A] 16 | with ResourceOps[A, OutputStreamResource[A]] { 17 | 18 | self => 19 | 20 | override def open():OpenedResource[A] = new CloseableOpenedResource(opener,context, closeAction) 21 | override def updateContext(newContext:ResourceContext) = new OutputStreamResource(opener, newContext, closeAction) 22 | override def addCloseAction(newCloseAction: CloseAction[A]) = 23 | new OutputStreamResource(opener, context, newCloseAction :+ closeAction) 24 | 25 | override def outputStream = this 26 | protected override def underlyingOutput = writableByteChannel 27 | override def writer(implicit sourceCodec: Codec):WriterResource[Writer] = { 28 | def nResource = { 29 | val a = open() 30 | new OutputStreamWriter(a.get, sourceCodec.name) with Adapter[A] { 31 | override def src = a.get 32 | } 33 | } 34 | val closer = ResourceAdapting.closeAction(closeAction) 35 | new WriterResource(nResource, context, closer) 36 | } 37 | override def writableByteChannel = { 38 | def nResource = new WritableChannelAdapter(opener) 39 | val closer = ResourceAdapting.closeAction(closeAction) 40 | new WritableByteChannelResource(nResource, context, closer) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/managed/ReadableByteChannelResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package managed 3 | 4 | import java.io.BufferedInputStream 5 | import java.nio.channels.{Channels, ReadableByteChannel} 6 | import scalax.io.ResourceAdapting.{ChannelReaderAdapter, ChannelInputStreamAdapter} 7 | import java.io.Reader 8 | import java.io.InputStream 9 | 10 | /** 11 | * A ManagedResource for accessing and using ByteChannels. Class can be created using the [[scalax.io.Resource]] object. 12 | */ 13 | class ReadableByteChannelResource[+A <: ReadableByteChannel] ( 14 | opener: => A, 15 | val context:ResourceContext = DefaultResourceContext, 16 | closeAction: CloseAction[A] = CloseAction.Noop, 17 | protected val sizeFunc:() => Option[Long] = () => None) 18 | extends InputResource[A] 19 | with ResourceOps[A, ReadableByteChannelResource[A]] { 20 | 21 | self => 22 | 23 | override def open():OpenedResource[A] = new CloseableOpenedResource(opener, context, closeAction) 24 | override def updateContext(newContext:ResourceContext) = 25 | new ReadableByteChannelResource(opener, newContext, closeAction, sizeFunc) 26 | override def addCloseAction(newCloseAction: CloseAction[A]) = 27 | new ReadableByteChannelResource(opener, context, newCloseAction :+ closeAction, sizeFunc) 28 | 29 | override def inputStream:InputResource[InputStream] = { 30 | def nResource = new ChannelInputStreamAdapter(opener) 31 | val closer = ResourceAdapting.closeAction(closeAction) 32 | new InputStreamResource(nResource, context, closer, sizeFunc) 33 | } 34 | override def reader(implicit sourceCodec: Codec) = { 35 | def nResource = new ChannelReaderAdapter(opener,sourceCodec) 36 | val closer = ResourceAdapting.closeAction(closeAction) 37 | new ReaderResource(nResource, context, closer) 38 | } 39 | override def readableByteChannel:InputResource[ReadableByteChannel] = this 40 | override def bytesAsInts = ResourceTraversable.byteChannelBased[Byte,Int](this.open, context, sizeFunc, initialConv = ResourceTraversable.toIntConv) 41 | override def bytes = ResourceTraversable.byteChannelBased[Byte,Byte](this.open, context, sizeFunc) 42 | override def chars(implicit codec: Codec) = reader(codec).chars // TODO optimize for byteChannel 43 | override def blocks(blockSize: Option[Int] = None): LongTraversable[ByteBlock] = 44 | new traversable.ChannelBlockLongTraversable(blockSize, context, sizeFunc, open) 45 | 46 | override def toString: String = "ReadableByteChannelResource ("+context.descName.name+")" 47 | } 48 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/managed/ReaderResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package managed 3 | 4 | import java.io.{Reader, BufferedReader} 5 | 6 | /** 7 | * A ManagedResource for accessing and using Readers. Class can be created using the [[scalax.io.Resource]] object. 8 | */ 9 | class ReaderResource[+A <: Reader] ( 10 | opener: => A, 11 | val context:ResourceContext = DefaultResourceContext, 12 | closeAction: CloseAction[A] = CloseAction.Noop) 13 | extends ReadCharsResource[A] 14 | with ResourceOps[A, ReaderResource[A]] { 15 | 16 | self => 17 | 18 | override def open():OpenedResource[A] = new CloseableOpenedResource(opener,context, closeAction) 19 | override def updateContext(newContext:ResourceContext) = 20 | new ReaderResource(opener, newContext, closeAction) 21 | override def addCloseAction(newCloseAction: CloseAction[A]) = 22 | new ReaderResource(opener, context, newCloseAction :+ closeAction) 23 | 24 | override def chars : LongTraversable[Char]= 25 | ResourceTraversable.readerBased(this.open, context) 26 | 27 | override def toString: String = "ReaderResource("+context.descName.name+")" 28 | } 29 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/managed/WritableByteChannelResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package managed 3 | 4 | import java.io.BufferedOutputStream 5 | import java.nio.channels.{Channels, WritableByteChannel} 6 | import scalax.io.ResourceAdapting.{ChannelOutputStreamAdapter, ChannelWriterAdapter} 7 | import java.io.OutputStream 8 | import java.io.Writer 9 | 10 | /** 11 | * A ManagedResource for accessing and using ByteChannels. Class can be created using the [[scalax.io.Resource]] object. 12 | */ 13 | class WritableByteChannelResource[+A <: WritableByteChannel] ( 14 | opener: => A, 15 | val context:ResourceContext = DefaultResourceContext, 16 | closeAction: CloseAction[A] = CloseAction.Noop) 17 | extends OutputResource[A] 18 | with ResourceOps[A, WritableByteChannelResource[A]] { 19 | 20 | 21 | self => 22 | 23 | override def open():OpenedResource[A] = new CloseableOpenedResource(opener,context, closeAction) 24 | override def updateContext(newContext:ResourceContext) = new WritableByteChannelResource(opener, newContext, closeAction) 25 | override def addCloseAction(newCloseAction: CloseAction[A]) = 26 | new WritableByteChannelResource(opener, context, newCloseAction :+ closeAction) 27 | 28 | override def outputStream = { 29 | def nResource = new ChannelOutputStreamAdapter(opener) 30 | val closer = ResourceAdapting.closeAction(closeAction) 31 | new OutputStreamResource(nResource, context, closer) 32 | } 33 | protected override def underlyingOutput = this 34 | override def writer(implicit sourceCodec: Codec) = { 35 | def nResource = new ChannelWriterAdapter(opener,sourceCodec) 36 | val closer = ResourceAdapting.closeAction(closeAction) 37 | new WriterResource(nResource, context, closer) 38 | } 39 | override def writableByteChannel = this 40 | } 41 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/managed/WriterResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package managed 3 | 4 | import java.io.{Writer, BufferedWriter} 5 | /** 6 | * A ManagedResource for accessing and using Writers. Class can be created using the [[scalax.io.Resource]] object. 7 | */ 8 | class WriterResource[+A <: Writer] ( 9 | opener: => A, 10 | val context:ResourceContext = DefaultResourceContext, 11 | closeAction: CloseAction[A] = CloseAction.Noop) 12 | extends WriteCharsResource[A] 13 | with ResourceOps[A, WriterResource[A]] { 14 | 15 | self => 16 | 17 | override def open():OpenedResource[A] = new CloseableOpenedResource(opener,context, closeAction) 18 | override def updateContext(newContext:ResourceContext) = 19 | new WriterResource(opener, newContext, closeAction) 20 | override def addCloseAction(newCloseAction: CloseAction[A]) = 21 | new WriterResource(opener, context, newCloseAction :+ closeAction) 22 | 23 | protected def writer = this 24 | } 25 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/nio/ByteBuffer.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io.nio 10 | 11 | import scalax.io.Codec 12 | import java.nio.{ByteBuffer => NioByteBuffer} 13 | 14 | /** 15 | * Allows use of a java.nio.ByteBuffer as an IndexedSeq. But remember that the underlying buffer 16 | * is mutable so this object can be mutated by the underlying object 17 | */ 18 | class ByteBuffer(buf : NioByteBuffer) extends IndexedSeq[Byte] { 19 | def apply(idx : Int) = {buf.get(idx)} 20 | def length = buf.limit 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/nio/SeekableFileChannel.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io.nio 10 | 11 | import scalax.io.SeekableByteChannel 12 | import java.nio.{ByteBuffer => JByteBuffer} 13 | import java.nio.channels.FileChannel 14 | import java.nio.channels.ReadableByteChannel 15 | import java.nio.channels.WritableByteChannel 16 | 17 | 18 | class SeekableFileChannel(val self : FileChannel) extends SeekableByteChannel with Proxy { 19 | private[this] val wrapped = self 20 | def write (src: java.nio.ByteBuffer) = 21 | wrapped.write(src) 22 | def truncate (size: Long) = new SeekableFileChannel(wrapped.truncate(size)) 23 | def size = wrapped.size 24 | def read (dst: java.nio.ByteBuffer) = wrapped.read(dst) 25 | def position (newPosition: Long) = new SeekableFileChannel(wrapped.position(newPosition)) 26 | def position = wrapped.position 27 | def close = wrapped.close 28 | def isOpen = wrapped.isOpen 29 | def transferFrom(channel:ReadableByteChannel,position:Long,count:Long) = 30 | wrapped.transferFrom(channel,position,count) 31 | def transferTo(position:Long,count:Long, channel:WritableByteChannel) = 32 | wrapped.transferTo(position,count,channel) 33 | 34 | override def write(src : JByteBuffer, pos:Long) = wrapped.write(src, pos) 35 | override def read(dst : JByteBuffer, pos:Long) = wrapped.read(dst, pos) 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/package.scala: -------------------------------------------------------------------------------- 1 | package scalax 2 | 3 | import scala.concurrent.ExecutionContext 4 | 5 | /** 6 | * Scala IO core classes 7 | */ 8 | package object io { 9 | lazy val executionContext = ExecutionContext.global 10 | } 11 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/processing/CharProcessorAPI.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package processing 3 | 4 | /** 5 | * ProcessorAPI for processing char input sources 6 | */ 7 | case class CharProcessor(base:CloseableIteratorProcessor[Char]) 8 | extends SpecificApiFactory[Char, CharProcessorAPI](base) { 9 | protected def create(iter: CloseableIterator[Char]) = new CharProcessorAPI(iter, base.context) 10 | } 11 | 12 | class CharProcessorAPI private[processing](iter: CloseableIterator[Char], 13 | resourceContext: ResourceContext) extends ProcessorAPI[Char](iter, resourceContext) { 14 | /** 15 | * Read the sequence of characters from the current element in the input source if A are Char. 16 | * 17 | * In practical terms the implicit portion of the method signature can be ignored. It is required to make the method 18 | * type safe so that a method call to the method will only compile when the type of A is Char 19 | * 20 | * @param includeTerminator flag to indicate whether the terminator should be discarded or kept 21 | * @param lineTerminator the method to use for determine where the line ends 22 | * @param lineParser a case class to ensure this method can only be called when A are Chars 23 | * 24 | * @return a Processor containing the sequence of characters from the current element in the input source 25 | */ 26 | def line(includeTerminator:Boolean = false, lineTerminator:Line.Terminators.Terminator = Line.Terminators.Auto) = { 27 | val wrapped = new CloseableIterator[Char]() { 28 | private[this] val proxy = iterator 29 | @inline final def next = proxy.next 30 | @inline final def hasNext = proxy.hasNext 31 | final def doClose = Nil 32 | } 33 | processFactory(Some(new LineTraversable(wrapped, lineTerminator, includeTerminator, resourceContext).headOption.getOrElse("").toSeq)) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/processing/ProcessorTransformer.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package processing 3 | 4 | /** 5 | * Case class to ensure control conversion of a Processor to other objects happens in a type safe way so 6 | * that resources do not escape and create a resource leak 7 | */ 8 | private[processing] sealed trait ProcessorTransformer[+A, -From, +To] { 9 | def transform(from: Processor[From]): To 10 | } 11 | 12 | private[this] object ProcessorTransformer { 13 | implicit def iterableToLongTraversableTransformer[A] = new ProcessorTransformer[A, Iterable[A], LongTraversable[A]] { 14 | def transform(from: Processor[Iterable[A]]) = iteratorToLongTraverableTransformer[A].transform(from.map(t => LongTraversable(from.context, t.iterator))) 15 | } 16 | 17 | implicit def iteratorToLongTraverableTransformer[A]: ProcessorTransformer[A, LongTraversable[A], LongTraversable[A]] = 18 | new ProcessorTransformer[A, LongTraversable[A], LongTraversable[A]] { 19 | def transform(from: Processor[LongTraversable[A]]) = new LongTraversable[A] { 20 | def context = from.context 21 | 22 | def iterator = { 23 | val opened = from.init 24 | new CloseableIterator[A] { 25 | private[this] val wrapped = opened.execute.map(_.iterator)getOrElse(CloseableIterator.empty) 26 | def hasNext = wrapped.hasNext 27 | def next = wrapped.next 28 | def doClose = opened.cleanUp 29 | } 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/processing/SpecializedBufferedIterator.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package processing 3 | import scala.collection.immutable.VectorBuilder 4 | 5 | private[processing] class SpecializedBufferedIterator[@specialized(Byte,Int,Char) +A](private[this] val sourceIter: CloseableIterator[A]) { 6 | private[this] var pushedBack:List[A] = Nil 7 | private[this] var ended: Boolean = false 8 | 9 | final def end() = ended = true 10 | 11 | /** 12 | * Will return an Array containing the i elements if i elements remain in the input source. Otherwise an empty 13 | * array will be returned 14 | */ 15 | final def takeIfPossible(i:Int) = { 16 | val result = new VectorBuilder[A]() 17 | result.sizeHint(i) 18 | var count = 0 19 | while(count < i && hasNext) { 20 | result += next 21 | count += 1 22 | } 23 | if(count < i) { 24 | result.result() foreach {a => pushedBack = a :: pushedBack} 25 | Vector.empty 26 | } else { 27 | result.result() 28 | } 29 | } 30 | final def takeWhile(f:A => Boolean):Seq[A] = { 31 | var result = new VectorBuilder[A]() 32 | var continue = true 33 | while(continue && hasNext) { 34 | val nextE = next 35 | continue = f(nextE) 36 | if(continue) { 37 | result += nextE 38 | nextE 39 | } else { 40 | pushedBack = nextE :: pushedBack 41 | } 42 | } 43 | result.result() 44 | } 45 | 46 | final def take(i: Int) = { 47 | var result = new VectorBuilder[A]() 48 | var count = 0 49 | while (count < i && hasNext) { 50 | result += next 51 | count += 1 52 | } 53 | result.result() 54 | } 55 | 56 | final def drop(i: Int) = { 57 | var count = 0 58 | while (count < i && hasNext) { 59 | next 60 | count += 1 61 | } 62 | } 63 | 64 | final def hasNext = 65 | !ended && (pushedBack.nonEmpty || sourceIter.hasNext) 66 | 67 | final def next() = 68 | if (pushedBack.nonEmpty) { 69 | var next = pushedBack.head 70 | pushedBack = pushedBack.tail 71 | next 72 | } else sourceIter.next() 73 | } 74 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/processing/SpecificApiFactory.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package processing 3 | 4 | /** 5 | * Wraps a CloseableIteratorProcessor, which normally produces a ProcessorAPI object, to a new Processor that 6 | * returns a ProcessorAPI subclass specific to a data type. For example 7 | * CharProcessorAPI has the lines() method and ByteProcessorAPI have int, long, float etc... methods 8 | * 9 | * for { 10 | * byteAPI <- ByteProcessorAPI(in.bytes.processor) 11 | * littleEndianAPI = byteApi.littleEndianAPI 12 | * littleEndianInt <- littleEndianAPI.nextInt 13 | * } yield littleEndianInt 14 | * 15 | * @see scalax.io.processing.ProcessorAPI 16 | * @see scalax.io.processing.CharProcessorAPI 17 | */ 18 | abstract class SpecificApiFactory[A,API <: ProcessorAPI[A]](base:CloseableIteratorProcessor[A]) extends Processor[API] { 19 | def context = base.context 20 | /** 21 | * Factory method to create the actual API object 22 | */ 23 | protected def create(commonAPI: CloseableIterator[A]):API 24 | private[processing] def init = new Opened[API] { 25 | val iter = base.iter() 26 | def execute() = Some(create(iter)) 27 | def cleanUp() = iter.close() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/processing/repeating.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package processing 3 | 4 | /** 5 | * Processor that repeats until empty or maxRepetitions 6 | */ 7 | private[processing] class RepeatUntilEmpty(private[this] val maxRepetitions:Long, processorFactory: ProcessorFactory, private[this] val ProcessorAPIs: ProcessorAPI[_]*) { 8 | private[this] def closeableIteratorOps = new CloseableIteratorOps(new CloseableIterator[Long] { 9 | private[this] var index = 0L 10 | def hasNext = index < maxRepetitions && ProcessorAPIs.exists{api => 11 | api.iterator.hasNext 12 | } 13 | def next = { 14 | index += 1 15 | index - 1 16 | } 17 | def doClose = Nil 18 | }) 19 | 20 | def foreach[U](f: Long => U) = closeableIteratorOps.iter foreach f 21 | def flatMap[U](f: Long => Processor[U]) = processorFactory[LongTraversable[U]](Some(LongTraversable(processorFactory.resourceContext, closeableIteratorOps.flatMap(i =>f(i).init.execute)))) 22 | def map[U](f: Long => U) = processorFactory[LongTraversable[U]](Some(LongTraversable(processorFactory.resourceContext, closeableIteratorOps map f))) 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/support/ArrayIterator.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io.support 10 | 11 | class ArrayIterator[A](var a:Array[A],var end:Int) extends Iterator[A]{ 12 | var start=0 13 | var now=0 14 | @inline 15 | final def hasNext = now < end 16 | @inline 17 | final def next = { 18 | now += 1 19 | a(now - 1) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/support/DeletingFileOutputStream.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.support 2 | 3 | /* __ *\ 4 | ** ________ ___ / / ___ Scala API ** 5 | ** / __/ __// _ | / / / _ | (c) 2009-2011, Jesse Eichar ** 6 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 7 | ** /____/\___/_/ |_/____/_/ | | ** 8 | ** |/ ** 9 | \* */ 10 | import java.io.{ 11 | File => JFile, 12 | FileOutputStream 13 | } 14 | 15 | class DeletingFileOutputStream(jfile:JFile, append : Boolean) extends FileOutputStream(jfile,append) { 16 | override def finalize() : Unit = { 17 | try if(jfile.exists) jfile.delete() 18 | finally super.finalize() 19 | } 20 | 21 | override def close() : Unit = { 22 | try super.close() 23 | finally if(jfile.exists) jfile.delete() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/support/Misc.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.support 2 | 3 | object Misc { 4 | def safeSum(numbers : Long*) = (0L /: numbers) { (next,acc) => 5 | val sum = acc + next 6 | if(sum < acc) Long.MaxValue 7 | else sum 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/support/NioByteBufferIterator.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io.support 10 | 11 | import java.nio.ByteBuffer 12 | 13 | class NioByteBufferIterator(var buffer: ByteBuffer) extends Iterator[Byte] { 14 | @inline 15 | final def hasNext = buffer.hasRemaining() 16 | @inline 17 | final def next = buffer.get() 18 | } 19 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/traversable/ByteResourceTraversable.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package traversable 3 | 4 | import java.io.Closeable 5 | import java.io.InputStream 6 | import java.nio.channels.Channels 7 | import java.nio.channels.ReadableByteChannel 8 | import scala.Option.option2Iterable 9 | import scalax.io.extractor.FileChannelExtractor 10 | import scalax.io.nio.SeekableFileChannel 11 | import scala.reflect.ClassTag 12 | 13 | /** 14 | * resourceOpener must either be a InputStream or a ReadableByteChannel (or subclass). Anything else will throw an exception 15 | */ 16 | protected[io] class ByteResourceTraversable( 17 | resourceOpener: => OpenedResource[Closeable], 18 | resourceContext: ResourceContext, 19 | sizeFunc: () => Option[Long], 20 | start: Long, 21 | end: Long, 22 | allowSeekable: Boolean) 23 | extends LongTraversable[Byte] 24 | with LongTraversableLike[Byte, LongTraversable[Byte]] { 25 | self => 26 | def context = resourceContext 27 | protected[io] def iterator: Sliceable = { 28 | val resource = resourceOpener 29 | resource.get match { 30 | case FileChannelExtractor(seekable) if allowSeekable => 31 | new SeekableByteChannelIterator(sizeFunc, new SeekableFileChannel(seekable), resource, start, end) 32 | case seekable: SeekableByteChannel if allowSeekable => 33 | new SeekableByteChannelIterator(sizeFunc, seekable, resource, start, end) 34 | case stream: InputStream => 35 | new ReadableByteChannelIterator(sizeFunc, Channels.newChannel(stream), resource, start, end) 36 | case rbc: ReadableByteChannel => 37 | new ReadableByteChannelIterator(sizeFunc, rbc, resource, start, end) 38 | case _ => 39 | throw new AssertionError(getClass.getSimpleName + " only accepts inputStreams and readableByteChannels as input") 40 | } 41 | } 42 | 43 | override lazy val hasDefiniteSize = sizeFunc().nonEmpty 44 | override def lsize = { 45 | CloseableIterator.withIterator(iterator,context) {_.size} 46 | } 47 | override def toArray[B >: Byte: ClassTag]: Array[B] = { 48 | CloseableIterator.withIterator(iterator,context) {_.toArray} 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/traversable/ChannelBlockLongTraversable.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package traversable 3 | import java.nio.channels.ReadableByteChannel 4 | import java.nio.ByteBuffer 5 | import annotation.switch 6 | 7 | private abstract class State { val id: Int } 8 | private object ReadyState extends State { final val id = 0 } 9 | private object ContinueState extends State { final val id = 1 } 10 | private object EmptyState extends State { final val id = 2 } 11 | 12 | class ChannelBlockLongTraversable(blockSize: Option[Int], val context: ResourceContext, sizeFunc:() => Option[Long], opener: => OpenedResource[ReadableByteChannel]) extends LongTraversable[ByteBlock] { 13 | self => 14 | 15 | protected[io] def iterator: CloseableIterator[ByteBlock] = new CloseableIterator[ByteBlock] { 16 | private[this] val opened = opener 17 | private[this] val channel = opened.get 18 | private[this] val context = opened.context 19 | private[this] var buffer = blockSize match { 20 | case Some(size) => context.createNioBuffer(size, Some(channel), true) 21 | case None => context.createNioBuffer(sizeFunc(), Some(channel), true) 22 | } 23 | // bytes read the last read. -1 24 | private[this] var state: State = ContinueState 25 | private[this] var block = new ByteBufferWrapperByteBlock(buffer) 26 | 27 | def next(): ByteBlock = { 28 | state = ContinueState 29 | block.set() 30 | block 31 | } 32 | def hasNext: Boolean = { 33 | (state.id: @switch) match { 34 | case ReadyState.id => true 35 | case EmptyState.id => false 36 | case ContinueState.id => 37 | buffer.clear() 38 | state = if (channel.read(buffer) < 0) EmptyState else ReadyState 39 | buffer.flip() 40 | state == ReadyState 41 | } 42 | } 43 | protected def doClose() = opened.close() 44 | } 45 | 46 | override def force = new LongTraversable[ByteBlock] { 47 | def context = self.context 48 | private[this] val data = self.withIterator { 49 | _.foldLeft(Vector[ByteBlock]()) { (acc, next) => 50 | acc :+ next.force 51 | } 52 | } 53 | 54 | def iterator = CloseableIterator(data.iterator) 55 | } 56 | } 57 | 58 | private class ByteBufferWrapperByteBlock(private[this] val buffer: ByteBuffer) extends ByteBlock { 59 | 60 | private[this] var _size = 0 61 | @inline 62 | def size = _size 63 | @inline 64 | final def apply(i: Int) = buffer.get(i) 65 | def set() = _size = buffer.limit 66 | } 67 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/traversable/ReaderResourceTraversable.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package traversable 3 | import java.io.Reader 4 | 5 | import scalax.io.CloseableIterator 6 | import scalax.io.LongTraversable 7 | import scalax.io.LongTraversableLike 8 | import scalax.io.OpenedResource 9 | 10 | private[io] class ReaderResourceTraversable ( 11 | resourceOpener: => OpenedResource[Reader], 12 | resourceContext: ResourceContext, 13 | val start:Long, 14 | val end:Long) 15 | extends LongTraversable[Char] 16 | with LongTraversableLike[Char, LongTraversable[Char]] { 17 | 18 | def context = resourceContext 19 | protected[io] def iterator: CloseableIterator[Char] = new CloseableIterator[Char] { 20 | private[this] val openResource = resourceOpener 21 | private[this] val buffer = new Array[Char](openResource.context.charBufferSize(None, true)) 22 | private[this] val inConcrete = openResource.get 23 | inConcrete.skip(start) 24 | private[this] var read = inConcrete.read(buffer) 25 | private[this] var i = 0 26 | 27 | def hasNext = { 28 | if(i < read) true 29 | else { 30 | i=0 31 | read = inConcrete.read(buffer) 32 | i < read 33 | } 34 | } 35 | def next = { 36 | i += 1 37 | buffer(i-1) 38 | } 39 | def doClose() = openResource.close() 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/unmanaged/ReadableByteChannelResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package unmanaged 3 | 4 | import java.nio.channels.{Channels, ReadableByteChannel} 5 | import scalax.io.ResourceAdapting.{ChannelReaderAdapter, ChannelInputStreamAdapter} 6 | import java.io.{InputStreamReader, BufferedInputStream, Reader, InputStream} 7 | 8 | /** 9 | * A ManagedResource for accessing and using ByteChannels. Class can be created using the [[scalax.io.Resource]] object. 10 | */ 11 | class ReadableByteChannelResource[+A <: ReadableByteChannel] ( 12 | resource: A, 13 | resourceContext:ResourceContext = DefaultResourceContext, 14 | closeAction: CloseAction[A] = CloseAction.Noop) 15 | extends Input { 16 | 17 | final val context = unmanagedContext(resourceContext) 18 | final val open:OpenedResource[A] = new UnmanagedOpenedResource(resource, context) 19 | val sizeFunc = () => None 20 | 21 | override def bytesAsInts = ResourceTraversable.byteChannelBased[Byte,Int](this.open, context, sizeFunc, initialConv = ResourceTraversable.toIntConv) 22 | override def bytes = ResourceTraversable.byteChannelBased[Byte,Byte](this.open, context, sizeFunc) 23 | override def blocks(blockSize: Option[Int] = None): LongTraversable[ByteBlock] = 24 | new traversable.ChannelBlockLongTraversable(blockSize, context, sizeFunc, open) 25 | override def chars(implicit codec: Codec = Codec.default): LongTraversable[Char] = { 26 | val opened = new UnmanagedOpenedResource(new InputStreamReader(Channels.newInputStream(resource), codec.name), context) 27 | ResourceTraversable.readerBased(opened, context) 28 | } 29 | override def size = None 30 | } 31 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/unmanaged/ReaderResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package unmanaged 3 | 4 | import java.io.{Reader, BufferedReader} 5 | 6 | /** 7 | * A ManagedResource for accessing and using Readers. Class can be created using the [[scalax.io.Resource]] object. 8 | */ 9 | class ReaderResource[+A <: Reader] ( 10 | resource: A, 11 | resourceContext:ResourceContext = DefaultResourceContext, 12 | closeAction: CloseAction[A] = CloseAction.Noop) 13 | extends ReadChars { 14 | 15 | self => 16 | final val context = unmanagedContext(resourceContext) 17 | private[this] val open:OpenedResource[A] = new UnmanagedOpenedResource(resource, unmanagedContext(context)) 18 | 19 | override def chars : LongTraversable[Char]= ResourceTraversable.readerBased(this.open, context) 20 | } 21 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/unmanaged/WritableByteChannelResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package unmanaged 3 | 4 | import java.nio.channels.WritableByteChannel 5 | import java.nio.ByteBuffer 6 | 7 | /** 8 | * A ManagedResource for accessing and using ByteChannels. Class can be created using the [[scalax.io.Resource]] object. 9 | */ 10 | class WritableByteChannelResource[+A <: WritableByteChannel] ( 11 | resource: A, 12 | resourceContext:ResourceContext = DefaultResourceContext, 13 | closeAction: CloseAction[A] = CloseAction.Noop) 14 | extends Output { 15 | 16 | self => 17 | final val context = unmanagedContext(resourceContext) 18 | //def open:OpenedResource[A] = new UnmanagedOpenedResource(resource, unmanagedContext(context)) 19 | protected override val underlyingOutput = { 20 | val uncloseableChannel = new WritableByteChannel{ 21 | def isOpen = resource.isOpen 22 | def write(src: ByteBuffer) = resource.write(src) 23 | override def close() {} 24 | } 25 | new managed.WritableByteChannelResource[WritableByteChannel](uncloseableChannel, resourceContext, CloseAction.Noop) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/unmanaged/WriterResource.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package unmanaged 3 | 4 | import java.io.{Writer, BufferedWriter} 5 | /** 6 | * A ManagedResource for accessing and using Writers. Class can be created using the [[scalax.io.Resource]] object. 7 | */ 8 | class WriterResource[+A <: Writer] ( 9 | resource: A, 10 | resourceContext:ResourceContext = DefaultResourceContext, 11 | closeAction: CloseAction[A] = CloseAction.Noop) 12 | extends WriteChars with Resource[A] { 13 | final val context = unmanagedContext(resourceContext) 14 | override def open:OpenedResource[A] = new UnmanagedOpenedResource(resource,unmanagedContext(context)){ 15 | override def closeAction[U >: A] = CloseAction(_ => resource.flush()) 16 | } 17 | override def updateContext(newContext:ResourceContext) = new WriterResource(resource, newContext, closeAction) 18 | override def addCloseAction(newCloseAction: CloseAction[A]) = 19 | new WriterResource(resource, context, newCloseAction :+ closeAction) 20 | 21 | 22 | override def writer = this 23 | } 24 | -------------------------------------------------------------------------------- /core/src/main/scala/scalax/io/unmanaged/package.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | 3 | package object unmanaged { 4 | private[unmanaged] def unmanagedContext(base:ResourceContext) = base.copy(newByteBufferSize=Some((_,_) => 1), newCharBufferSize=Some((_,_) => 1)) 5 | } 6 | -------------------------------------------------------------------------------- /core/src/samples/scala/InputComposition.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * These examples show various strategies for composing files together 3 | */ 4 | object InputComposition { 5 | 6 | /** 7 | * Zip the characters of two files together and find all that don't match 8 | */ 9 | def zipAndCompare { 10 | import scalax.io.Resource 11 | 12 | val googleCom = Resource.fromURL("http://google.com").chars 13 | val googleCH = Resource.fromURL("http://google.ch").chars 14 | 15 | googleCom.zip(googleCH).filter{case (com,ch) => com != ch} 16 | } 17 | 18 | /** 19 | * Compare two inputs by comparing the first byte of each 100 byte block 20 | */ 21 | def blockCompare { 22 | import scalax.io.Resource 23 | 24 | val googleCom = Resource.fromURL("http://google.com").bytes 25 | val googleCH = Resource.fromURL("http://google.ch").bytes 26 | 27 | val blocks = googleCom.sliding(100,100).zip(googleCH.sliding(100,100)) 28 | 29 | blocks.forall{case (com,ch) => com.head == ch.head} 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /core/src/samples/scala/lines.scala: -------------------------------------------------------------------------------- 1 | import java.io.File 2 | 3 | /** 4 | * Traversing lines in Input or ReadChars. 5 | *6 | * Both Input and ReadChars objects have a method traversing the object one line at a time. 7 | * The terminator can be autodetected (which assumes the ending is one of \n, \r\n, \r) or it 8 | * can be explicitely declared, or it can be a custom separator such as ';'. 9 | *
10 | * Note: The lines() method is lazily evaluated so calling the method without processing will 11 | * not result in any processing of the resource
12 | */ 13 | object LinesExamples { 14 | /** 15 | * Default behaviour with the parameter defaults. Autodetect ending assuming one of 16 | * \n, \r\n or \r. The terminator is not included in results 17 | */ 18 | def linesDefaults { 19 | import scalax.io._ 20 | 21 | val lines = Resource.fromFile("file").lines() 22 | println(lines.size) 23 | } 24 | /** 25 | * Explicitly declare line ending as AutoDetect and include terminator 26 | */ 27 | def linesAutoIncludeTerminators { 28 | import scalax.io._ 29 | import Line.Terminators.Auto 30 | 31 | val lines = Resource.fromFile("file").lines(Auto,true) 32 | println(lines.size) 33 | } 34 | /** 35 | * Explicitly declare line ending as NewLine and do not include terminator 36 | */ 37 | def linesNewLineTerminator { 38 | import scalax.io._ 39 | import Line.Terminators.NewLine 40 | 41 | val lines = Resource.fromFile("file").lines(NewLine,false) 42 | println(lines.size) 43 | } 44 | /** 45 | * Explicitly declare a custom line terminator and do not include terminator 46 | */ 47 | def linesCustomTerminator { 48 | import scalax.io._ 49 | import Line.Terminators.Custom 50 | 51 | val resource = Resource.fromFile("file") 52 | // read each segment ending in ** but do not include ** 53 | val lines = resource.lines(terminator=Custom("**"), includeTerminator=false) 54 | println(lines.size) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/samples/scala/more-input.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * One of the core IO classes is called Input. Normally the Input API will be encountered when a Resource object is 3 | * created. But a resource is not required to have an Input object. 4 | */ 5 | object MoreInputExamples { 6 | /** 7 | * All Input resources extend the Input trait so the following operations can be used on any Input resource 8 | * (ReadableByteChannel or InputStream for example). 9 | *10 | * This example does not try to cover all operations since they are covered in multiple examples like in the 11 | * basic-read-write examples. 12 | *
13 | */ 14 | def basicInput { 15 | import scalax.io._ 16 | 17 | val input:Input = Resource.fromFile("someFile") 18 | 19 | // read all bytes into an in memory arry 20 | input.byteArray 21 | 22 | // skip first 5 bytes and take the next 5 23 | // force the operation to take place. 24 | // The bytes is a ResourceView which is a LongTraversableView, 25 | // meaning it will evaluate lazily until the data is forced 26 | // or requested 27 | input.bytes.drop(5).take(5).force 28 | 29 | // read all bytes into a string 30 | // note: codec can be passed implicitely as well 31 | input.string(Codec.UTF8) 32 | } 33 | 34 | /** 35 | * Sometimes is can be handy to treat a List or Array of Bytes as an Input object. This example 36 | * demonstrates how to do that 37 | */ 38 | def convertTraversableToInput { 39 | import scalax.io._ 40 | import JavaConverters.asInputConverter 41 | 42 | // any Traversable[Int] can be implicitly converted 43 | // to an Input by the implicit conversions in the 44 | // Input object 45 | val input1:Input = List[Int](1,2,3).asInput 46 | 47 | // needed for the chars call below 48 | implicit val codec = Codec.UTF8 49 | 50 | // all normal Input ops can be used on the list 51 | val chars = input1.chars mkString "," 52 | 53 | // Traversable[Byte] can also be converted to an Input 54 | val input2:Input = List[Byte](1,2,3).asInput 55 | } 56 | 57 | /** 58 | * copyTo can be used to copy data from one Input object to another Output object 59 | * as efficiently as possible. 60 | */ 61 | def copyTo { 62 | import scalax.io._ 63 | import Resource._ 64 | 65 | fromFile("in") copyDataTo fromFile("out") 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /core/src/samples/scala/standard-java-interop.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Examples demonstrating how to interoperate with Existing Java libraries. The primary focus 3 | * is given a Java library that requires a InputStream, Reader, Writer, etc... what are some of 4 | * the strategies that can be used to obtain the underlying Java resource for the Java library. 5 | */ 6 | import scalax.io.managed.SeekableByteChannelResource 7 | object JavaInterop { 8 | 9 | /** 10 | * demonstrate a few ways to interoperate existing java APIs 11 | */ 12 | def basicInteropExamples { 13 | import scalax.io._ 14 | import java.io._ 15 | 16 | val file: SeekableByteChannelResource[SeekableByteChannel] = Resource.fromFile(new File("file")) 17 | 18 | // some APIs require a stream or channel. Using one of the file resources you can safely call the method and be guaranteed that the stream will be correctly closed and exceptions handled 19 | // see the documentation in resource.ManagedResource for details on all the options available 20 | def javaApiEntryPoint(stream: InputStream) = { 21 | // do something interesting 22 | stream.read() 23 | } 24 | 25 | // here is the code for calling that method 26 | file.inputStream.acquireFor (javaApiEntryPoint) 27 | 28 | // other APIs use inversion of to obtain the file object. 29 | // here is how to get a raw java OutputStream from a file 30 | val out: OutputStream = file.outputStream.open().get 31 | 32 | // however the above pattern must be used with care since any close actions will not be executed. 33 | // If acquireFor cannot be used (for example if you are implementing an interator) you can do the following 34 | val openedResource = file.outputStream.open() 35 | // do something with resource 36 | val out2: OutputStream = openedResource.get 37 | // this will close out2 and execute any closeActions 38 | val errorsDuringClose: scala.List[scala.Throwable] = openedResource.close() 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/test/resources/resources/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseeichar/scala-io/2bd04c3d0aa2f6073deb4439a0d7963264512ebc/core/src/test/resources/resources/image.png -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/AbstractWriteCharsTests.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test 10 | 11 | import scalax.io._ 12 | import org.junit.Assert._ 13 | import org.junit.{ 14 | Test, Ignore 15 | } 16 | import Constants.TEXT_VALUE 17 | import java.io.Writer 18 | 19 | abstract class AbstractWriteCharsTests extends scalax.test.sugar.AssertionSugar { 20 | private final val DEFAULT_DATA = "default data" 21 | 22 | def open(outCloser:CloseAction[Writer] = CloseAction.Noop): (ReadChars, WriteChars) 23 | 24 | @Test(timeout = 3000) 25 | def write_string(): Unit = { 26 | val (input, output) = open() 27 | output write DEFAULT_DATA 28 | 29 | assertEquals(DEFAULT_DATA, input.string) 30 | } 31 | 32 | 33 | @Test(timeout = 3000) 34 | def write_many_strings(): Unit = { 35 | val (input, output) = open() 36 | 37 | output.writeStrings (DEFAULT_DATA :: DEFAULT_DATA :: DEFAULT_DATA :: Nil, "") 38 | assertEquals(DEFAULT_DATA + DEFAULT_DATA + DEFAULT_DATA, input.string) 39 | 40 | val (input2, output2) = open() 41 | 42 | output2 writeStrings (DEFAULT_DATA :: DEFAULT_DATA :: DEFAULT_DATA :: Nil, "-") 43 | assertEquals(DEFAULT_DATA + "-" + DEFAULT_DATA + "-" + DEFAULT_DATA, input2.string) 44 | } 45 | 46 | 47 | @Test //@Ignore 48 | def openOutput: Unit = { 49 | var closes = 0; 50 | val (in,out0) = open(outCloser = CloseAction((_:Any) => closes += 1)) 51 | out0 match { 52 | case out:WriteCharsResource[_] => 53 | 54 | assertEquals(0,closes) 55 | out.write("whoop!") 56 | assertEquals(1,closes) 57 | 58 | for { 59 | processor <- out.writeCharsProcessor 60 | _ <- processor.write("hello") 61 | _ <- processor.write(" ") 62 | _ <- processor.write("world") 63 | } {} 64 | 65 | assertEquals(2,closes) 66 | assertEquals("whoop!hello world",in.string) 67 | case _ => () 68 | } 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/CloseActionTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test 10 | 11 | import scalax.io._ 12 | import scalax.test.sugar._ 13 | import org.junit.Assert._ 14 | import org.junit.Test 15 | import java.io.InputStream 16 | import scalax.io.managed.InputStreamResource 17 | 18 | class CloseActionTest extends AssertionSugar with IOSugar { 19 | implicit val codec = Codec.UTF8 20 | 21 | val source = "sample" 22 | 23 | def resource(closeAction:CloseAction[InputStream]) = 24 | Resource.fromInputStream(source.inputStream).addCloseAction(closeAction) 25 | 26 | @Test 27 | def close_actions_are_executed_at_resource_close = { 28 | var c = 0 29 | val resource2 = resource(CloseAction((_:Any) => c += 1)) 30 | 31 | assertEquals(source, resource2.string) 32 | assertEquals(1, c) 33 | resource2.bytes.force 34 | assertEquals(2, c) 35 | resource2.chars.force 36 | assertEquals(3, c) 37 | resource2.readableByteChannel.bytes.force 38 | assertEquals(4, c) 39 | } 40 | 41 | @Test 42 | def close_actions_can_be_combined = { 43 | var c = 0 44 | var d = 0 45 | val closer = CloseAction((_:Any) => c += 1) :+ CloseAction((_:Any) => {assertEquals(1,c);d += 1}) 46 | val resource2 = resource(closer) 47 | 48 | assertEquals(source, resource2.string) 49 | assertEquals(1, c) 50 | assertEquals(1, d) 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/Constants.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test 2 | 3 | import java.io.{ 4 | InputStreamReader, BufferedReader 5 | } 6 | import scalax.io.Resource 7 | import java.io.FilterInputStream 8 | 9 | object Constants { 10 | final lazy val IMAGE = resource("resources/image.png", getClass()) 11 | 12 | final lazy val IMAGE_FILE_SIZE = Resource.fromInputStream(IMAGE.openStream()).byteArray.size 13 | 14 | final lazy val TEXT_VALUE = "1\na\nA\n\u00E0\n\u00E4\n\u00A3\n\u2248\n\u331B\n\u0060\n" 15 | 16 | def resource(resourceName: String, base: Class[_]) = new { 17 | private val r = { 18 | base.getClassLoader.getResource(resourceName) match { 19 | case null => new java.net.URL(base.getClassLoader.getResource(".").toExternalForm+resourceName) 20 | case url => url 21 | } 22 | } 23 | 24 | def openStream(closeFunction: () => Unit = () => ()) = new FilterInputStream(r.openStream()){ 25 | override def close() = { 26 | closeFunction() 27 | super.close() 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/JavaConversionsTest.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test 2 | 3 | /* __ *\ 4 | ** ________ ___ / / ___ Scala API ** 5 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 6 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 7 | ** /____/\___/_/ |_/____/_/ | | ** 8 | ** |/ ** 9 | \* */ 10 | 11 | import scalax.io._ 12 | import JavaConverters._ 13 | import org.junit.Assert._ 14 | import org.junit.Test 15 | 16 | class JavaConversionsTest extends scalax.test.sugar.AssertionSugar { 17 | 18 | @Test 19 | def traversable_asInput { 20 | assertEquals((1 to 10).toList, (1 to 10).map(_.toByte).asInput.bytesAsInts.toList) 21 | assertEquals((1 to 10).toList, (1 to 10).map(_.toByte).toList.asInput.bytesAsInts.toList) 22 | assertEquals((1 to 10).toList, (1 to 10).asInput.bytesAsInts.toList) 23 | 24 | val s = "hello world" 25 | assertEquals(s, s.getBytes("UTF-8").asInput.chars.mkString) 26 | 27 | val processor = for { 28 | inp <- (1 to 10).asInput.bytesAsInts.processor 29 | _ <- inp.repeatUntilEmpty() 30 | next <- inp.next 31 | } yield next.toString 32 | 33 | assertEquals((1 to 10).map(_.toString).toList, processor.traversable.toList) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/LongTraversableViewTest.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test 2 | 3 | import scalax.io.LongTraversable 4 | import scalax.io.ResourceContext 5 | 6 | class LongTraversableViewTest extends LongTraversableTest{ 7 | override def traversable[U, A](tsize: Int, 8 | callback: (Int) => U, 9 | dataFunc: (Int) => Traversable[Int], 10 | conv: (Int) => A, 11 | closeFunction: () => Unit = () => (), 12 | context:ResourceContext): LongTraversable[A] = 13 | super.traversable(tsize,callback,dataFunc,conv,closeFunction, context) 14 | } 15 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/OutputStreamResourceTest.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test 2 | 3 | import org.junit.Assert._ 4 | import org.junit.{ 5 | Test, 6 | Before, 7 | After, 8 | Rule, 9 | Ignore 10 | } 11 | import scalax.io.Resource 12 | import java.io.ByteArrayOutputStream 13 | import scalax.io.Codec 14 | import scalax.io.OutputResource 15 | import java.nio.channels.Channels 16 | 17 | class OutputStreamResourceTest { 18 | @Test 19 | def convert_to_writer_must_respect_codec { 20 | var out = new ByteArrayOutputStream() 21 | def outResource = { 22 | out = new ByteArrayOutputStream() 23 | Resource.fromOutputStream(out) 24 | } 25 | 26 | def test(outResource: => OutputResource[_]) = { 27 | val data = "\u00E0" 28 | outResource.writer(Codec.UTF8).write(data) 29 | assertEquals(data, new String(out.toByteArray(), "UTF-8")) 30 | 31 | outResource.writer(Codec.ISO8859).write(data) 32 | assertEquals(data, new String(out.toByteArray(), Codec.ISO8859.name)) 33 | } 34 | test { 35 | out = new ByteArrayOutputStream() 36 | Resource.fromOutputStream(out) 37 | } 38 | 39 | test { 40 | out = new ByteArrayOutputStream() 41 | Resource.fromOutputStream(out).writableByteChannel 42 | } 43 | 44 | test { 45 | out = new ByteArrayOutputStream() 46 | Resource.fromWritableByteChannel(Channels.newChannel(out)) 47 | } 48 | 49 | test { 50 | out = new ByteArrayOutputStream() 51 | Resource.fromWritableByteChannel(Channels.newChannel(out)).outputStream 52 | } 53 | 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/SeekableTestUtils.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test 2 | import scalax.io.SeekableResource 3 | import scalax.io.Seekable 4 | import scalax.io.Input 5 | import scalax.io.Output 6 | import scalax.io.managed.InputStreamResource 7 | import scalax.io.CloseAction 8 | import scalax.io.Resource 9 | import scalaio.test.AbstractInputTests._ 10 | import java.io.InputStream 11 | import scalax.io.Codec 12 | trait SeekableTestUtils[ResourceType] { 13 | protected def forceErrorOnAccess():Unit 14 | protected def openResource(openFunction: () => Unit, closeAction: CloseAction[ResourceType]): Seekable 15 | def openSeekable(data: String, openFunction: () => Unit, closeFunction: () => Unit) = { 16 | val r = openResource(openFunction, CloseAction[ResourceType](_ => closeFunction())) 17 | r truncate 0 18 | r write data 19 | r 20 | } 21 | def open(closeAction: CloseAction[ResourceType] = CloseAction.Noop): (Input, Output) = { 22 | val r = openResource(() => (), closeAction) 23 | (r, r) 24 | } 25 | def errorOnWriteOut: Seekable = { 26 | val resource = openResource(() => (), CloseAction.Noop) 27 | forceErrorOnAccess() 28 | resource 29 | } 30 | 31 | def input(t: Type, openFunction: () => Unit, closeFunction: () => Unit) = t match { 32 | case t @ TextNewLine => text(t.sep,openFunction,closeFunction) 33 | case t @ TextPair => text(t.sep,openFunction,closeFunction) 34 | case t @ TextCarriageReturn => text(t.sep,openFunction,closeFunction) 35 | case TextCustom(sep) => text(sep,openFunction,closeFunction) 36 | case TextCustomData(sep, data) => 37 | val s = openResource(openFunction,CloseAction.Noop) 38 | s truncate 0 39 | s.write(data)(Codec.UTF8) 40 | if(s.isInstanceOf[Resource[_]]) { 41 | s.asInstanceOf[Resource[_]].addCloseAction(CloseAction(_ => closeFunction())) 42 | } 43 | s 44 | case Image => image(openFunction,closeFunction) 45 | case ErrorOnRead => errorOnWriteOut 46 | case ErrorOnClose => openResource(() => (), CloseAction(_ => throw new AssertionError("boom"))) 47 | 48 | } 49 | def image(openFunction: () => Unit, closeFunction:() => Unit) = 50 | copyResource(Resource.fromInputStream(Constants.IMAGE.openStream()), openFunction, closeFunction) 51 | 52 | def text(sep: String, openFunction: () => Unit, closeFunction:() => Unit) = { 53 | val resource = Resource.fromInputStream { 54 | val bytes = Constants.TEXT_VALUE.replaceAll("""\n""", sep).getBytes(Codec.UTF8.name) 55 | new java.io.ByteArrayInputStream(bytes) 56 | } 57 | copyResource(resource, openFunction, closeFunction) 58 | } 59 | def copyResource(source : InputStreamResource[InputStream],openFunction: () => Unit,closeFunction:() => Unit) : Seekable = { 60 | val dest = openResource(openFunction, CloseAction(_ => closeFunction)) 61 | dest truncate 0 62 | dest write (source.bytes) 63 | dest 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/channel/OutputTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.channel 10 | 11 | import scalaio.test._ 12 | import scalax.io._ 13 | import java.nio.channels._ 14 | import java.io._ 15 | 16 | class OutputTest extends AbstractOutputTests[ReadableByteChannel, WritableByteChannel] { 17 | def open(closeAction:CloseAction[WritableByteChannel] = CloseAction.Noop) = { 18 | val oStream = new ByteArrayOutputStream() 19 | val out = Channels.newChannel(oStream) 20 | def in = Channels.newChannel(new ByteArrayInputStream(oStream.toByteArray)) 21 | 22 | val inResource = Resource.fromReadableByteChannel(in) 23 | val outResource = Resource.fromWritableByteChannel(out).addCloseAction(closeAction) 24 | 25 | (inResource, outResource) 26 | } 27 | def errorOnWriteOut = Resource.fromWritableByteChannel(Channels.newChannel(errorStream)) 28 | override def writeErrorRaisedOnClose = true 29 | } 30 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/channel/SeekableBackedInputTest.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test.channel 2 | 3 | import java.nio.channels.Channels 4 | import scalax.io.ArrayBufferSeekableChannel 5 | import scala.collection.mutable.ArrayBuffer 6 | import scalax.io.Resource 7 | import scalax.io.Input 8 | import scalax.io.Codec 9 | import scalaio.test.Constants 10 | import scalax.io.support.FileUtils 11 | 12 | class SeekableBackedInputTest extends InputTest { 13 | 14 | override def sizeIsDefined = true 15 | override protected def textResource(sep: String, openFunction: () => Unit, closeFunction: () => Unit): Input = 16 | construct(text(sep), openFunction, closeFunction) 17 | 18 | override protected def customDataResource(data: String, openFunction: () => Unit, closeFunction: () => Unit): Input = 19 | construct(data.getBytes(Codec.UTF8.charSet), openFunction, closeFunction) 20 | 21 | override protected def imageResource(openFunction: () => Unit, closeFunction: () => Unit): Input = { 22 | construct(Resource.fromInputStream(Constants.IMAGE.openStream()).bytes, openFunction, closeFunction) 23 | } 24 | 25 | def construct(bytes:Traversable[Byte], openFunction: () => Unit, closeFunction: () => Unit) = { 26 | val buffer = new ArrayBuffer[Byte]() ++ bytes 27 | def channel = new ArrayBufferSeekableChannel(buffer)(closeAction = _ => closeFunction()) { 28 | openFunction() 29 | } 30 | Resource.fromSeekableByteChannel(channel) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/processing/ProcessorAsyncTest.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test.processing 2 | 3 | import scalax.test.sugar.AssertionSugar 4 | import org.junit.Test 5 | import org.junit.Assert._ 6 | import scalax.io._ 7 | import processing._ 8 | import java.util.concurrent.TimeoutException 9 | import scala.concurrent.duration._ 10 | import scala.util.{Success, Failure} 11 | 12 | class ProcessorAsyncTest extends AssertionSugar{ 13 | 14 | val factory = new ProcessorFactory(DefaultResourceContext) 15 | @Test 16 | def processor_async_must_timeout { 17 | 18 | // repeat test many times to verify that there are no Heisenbugs 19 | for(i <- 1 to 20) { 20 | val p = factory{Thread.sleep(500); Some(1)} timeout 10.milliseconds 21 | intercept[TimeoutException] { 22 | p.acquireAndGet(v => v) 23 | } 24 | 25 | val p2 = factory{Thread.sleep(10); Some(1)} timeout 30.seconds 26 | assertEquals(Some(1), p2.acquireAndGet(v => v)) 27 | 28 | var success = false 29 | 30 | intercept[TimeoutException] { 31 | for {v <- p} success = true 32 | } 33 | assertFalse(success) 34 | 35 | for {v <- p2} success = true 36 | assertTrue(success) 37 | } 38 | } 39 | 40 | @Test(timeout=1000L) 41 | def processor_future_should_complete { 42 | 43 | var success = false 44 | val future = (factory{Thread.sleep(10); Some(1)}).future 45 | 46 | implicit val executionContext = scalax.io.executionContext 47 | 48 | future.onComplete{ 49 | case Failure(e) => success = false 50 | case Success(r) => success = true 51 | } 52 | 53 | while(!future.isCompleted) { 54 | Thread.sleep(30); 55 | } 56 | 57 | assertTrue(success) 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/stream/OutputTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.stream 10 | 11 | import scalaio.test._ 12 | import java.io.{ 13 | ByteArrayInputStream, 14 | ByteArrayOutputStream 15 | } 16 | import scalax.io._ 17 | 18 | class OutputTest extends AbstractOutputTests[ByteArrayInputStream, ByteArrayOutputStream] { 19 | def open(closeAction: CloseAction[ByteArrayOutputStream] = CloseAction.Noop) = { 20 | val out = new ByteArrayOutputStream() 21 | def in = new ByteArrayInputStream(out.toByteArray) 22 | 23 | val inResource = Resource.fromInputStream(in) 24 | val outResource = Resource.fromOutputStream(out).addCloseAction(closeAction) 25 | 26 | (inResource, outResource) 27 | } 28 | def errorOnWriteOut = Resource.fromOutputStream(errorStream) 29 | override def writeErrorRaisedOnClose = true 30 | 31 | } 32 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/stream/ReadCharsTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.stream 10 | 11 | import scalax.io.{Codec, Resource} 12 | import scalaio.test._ 13 | 14 | class ReadCharsTest extends AbstractReadCharsTests { 15 | implicit val c = Codec.UTF8 16 | 17 | private def text(sep: String) = { 18 | val string = Constants.TEXT_VALUE.replaceAll("""\n""", sep) 19 | new java.io.StringReader(string) 20 | } 21 | 22 | protected def readChars(t: Type) = t match { 23 | case t@TextNewLine => Resource.fromReader(text(t.sep)) 24 | case t@TextPair => Resource.fromReader(text(t.sep)) 25 | case t@TextCarriageReturn => Resource.fromReader(text(t.sep)) 26 | case TextCustom(sep) => Resource.fromReader(text(sep)) 27 | } 28 | 29 | override protected def sizeIsDefined = false 30 | } 31 | -------------------------------------------------------------------------------- /core/src/test/scala/scalaio/test/stream/WriteCharsTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.stream 10 | 11 | import scalaio.test._ 12 | import scalax.io._ 13 | import org.junit.Test 14 | import org.junit.Assert._ 15 | import java.io.{ByteArrayInputStream, ByteArrayOutputStream, PipedInputStream, PipedOutputStream} 16 | import java.io.OutputStreamWriter 17 | import scalax.io.managed.WriterResource 18 | 19 | class WriteCharsTest extends AbstractWriteCharsTests { 20 | def open(ca:CloseAction[java.io.Writer] = CloseAction.Noop) = { 21 | 22 | val out = new ByteArrayOutputStream() 23 | def in = new ByteArrayInputStream(out.toByteArray) 24 | 25 | val inResource = Resource.fromInputStream(in).reader(Codec.UTF8) 26 | val outResource = Resource.fromWriter(new OutputStreamWriter(out)).addCloseAction(ca) 27 | 28 | (inResource, outResource) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /core/src/test/scala/scalax/io/ReaderResourceTraversableTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io 10 | 11 | import java.io.Reader 12 | import scalax.io.managed.ReaderResource 13 | 14 | 15 | class ReaderResourceTraversableTest extends ResourceTraversableTest { 16 | 17 | override def expectedData(tsize: Int, 18 | dataFunc: (Int) => Seq[Int]) = 19 | dataFunc(tsize) mkString "" map { 20 | _.toInt 21 | } 22 | 23 | override def traversable[U, A](tsize: Int, 24 | callback: (Int) => U, 25 | dataFunc: (Int) => Traversable[Int], 26 | conv: (Int) => A, 27 | closeFunction: () => Unit = () => (), 28 | resourceContext: ResourceContext) = { 29 | def callBackAndConv = (c: Char) => { 30 | val i = c.toInt 31 | callback(i) 32 | conv(i) 33 | } 34 | def reader = new java.io.StringReader(dataFunc(tsize) mkString "") { 35 | override def close() = closeFunction() 36 | } 37 | def resource = Resource.fromReader(reader).updateContext(resourceContext) 38 | ResourceTraversable.readerBased(resource.open, resource.context, initialConv = callBackAndConv) 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /core/src/test/scala/scalax/io/ResourceTraversableTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io 10 | 11 | import org.junit.Assert._ 12 | import org.junit.{ 13 | Test, Ignore 14 | } 15 | import java.io._ 16 | import scalaio.test.LongTraversableTest 17 | import scalax.io.CloseAction.Noop 18 | import java.nio.channels.Channels 19 | import java.nio.channels.ReadableByteChannel 20 | 21 | class ResourceTraversableTest extends LongTraversableTest { 22 | override def traversable[U, A](tsize: Int, 23 | callback: (Int) => U, 24 | dataFunc: (Int) => Traversable[Int], 25 | conv: (Int) => A, 26 | closeFunction: () => Unit, 27 | resourceContext:ResourceContext):LongTraversable[A] = { 28 | def in = new ByteArrayInputStream(dataFunc(tsize) map {_.toByte} toArray) { 29 | override def close() = { 30 | closeFunction() 31 | super.close 32 | } 33 | } 34 | def stream = Channels.newChannel(in) 35 | def resource = new CloseableOpenedResource(stream,DefaultResourceContext, CloseAction.Noop) 36 | val callBackAndConv = (i:Byte) => { 37 | callback(i.toInt) 38 | conv(i.toInt) 39 | } 40 | ResourceTraversable.byteChannelBased(resource, resourceContext, () => None, initialConv = callBackAndConv) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /core/src/test/scala/scalax/io/StreamIteratorTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.io 10 | 11 | import scalax.test.sugar._ 12 | 13 | import org.junit.Assert._ 14 | import org.junit.{ 15 | Test, Before, After, Rule, Ignore 16 | } 17 | import org.junit.rules.TemporaryFolder 18 | import java.io.{ 19 | StringReader, BufferedReader 20 | } 21 | 22 | class StreamIteratorTest extends AssertionSugar with IOSugar{ 23 | implicit val codec = Codec("UTF-8") 24 | 25 | val sample ="a1?£©àäカ゚ゼ" 26 | 27 | @Test 28 | def stream_converts_chars_to_bytes() : Unit = { 29 | def reader = new BufferedReader(new StringReader(sample)) 30 | 31 | assertEquals(sample, reader.readLine) 32 | 33 | assertEquals(sample, StreamIterator(reader) mkString "") 34 | } 35 | 36 | @Test 37 | def convert_codec() : Unit = { 38 | sample foreach {ch => 39 | val c = ch.toString 40 | 41 | val reader = new StringReader(c) 42 | val iter = StreamIterator(reader, codec, Codec("UTF-16")) 43 | 44 | val converted : Char = iter.next 45 | assertFalse(iter.hasNext) 46 | assertEquals(new String(c.getBytes(codec.name), "UTF-16").head, converted) 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /core/src/test/scala/scalax/test/sugar/IOSugar.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.test.sugar 10 | 11 | import java.io._ 12 | import scalax.io.Codec 13 | 14 | trait IOSugar { 15 | implicit def stringToStringExtras(s:String) = new { 16 | def inputStream(implicit codec : Codec = Codec.default) = new ByteArrayInputStream(s getBytes codec.name) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /documentation/src/main/example_projects/example-maven-project/src/main/scala/Main.scala: -------------------------------------------------------------------------------- 1 | import scalax.io._ 2 | import scalax.file._ 3 | import JavaConverters._ 4 | object Main extends App { 5 | val tmpPath = Path.createTempFile("scala-lang-site.html") 6 | new java.net.URL("http://www.scala-lang.org").asInput.copyDataTo(tmpPath) 7 | 8 | println(tmpPath.string) 9 | tmpPath.delete() 10 | } 11 | -------------------------------------------------------------------------------- /documentation/src/main/example_projects/example-sbt-project/build.sbt: -------------------------------------------------------------------------------- 1 | libraryDependencies += "com.github.scala-incubator.io" %% "scala-io-file" % "@IO_VERSION@" 2 | 3 | mainClass := Some("Main") 4 | 5 | scalaVersion := "@SCALA_VERSION@" -------------------------------------------------------------------------------- /documentation/src/main/example_projects/example-sbt-project/src/main/scala/Main.scala: -------------------------------------------------------------------------------- 1 | import scalax.io._ 2 | import scalax.file._ 3 | import JavaConverters._ 4 | object Main extends App { 5 | val tmpPath = Path.createTempFile("scala-lang-site.html") 6 | new java.net.URL("http://www.scala-lang.org").asInput.copyDataTo(tmpPath) 7 | 8 | println(tmpPath.string) 9 | tmpPath.delete() 10 | } 11 | -------------------------------------------------------------------------------- /documentation/src/main/java/JavaIOExample.java: -------------------------------------------------------------------------------- 1 | import java.io.FileOutputStream; 2 | import java.io.InputStream; 3 | import java.net.URL; 4 | 5 | public class JavaIOExample { 6 | public static void write(FileOutputStream out, String urlString) throws Exception { 7 | byte[] buffer = new byte[8192]; 8 | URL url = new URL(urlString); 9 | InputStream in1 = url.openStream(); 10 | try { 11 | int read = in1.read(buffer); 12 | while (read > -1) { 13 | out.write(buffer,0,read); 14 | read = in1.read(buffer); 15 | } 16 | } finally { 17 | in1.close(); 18 | } 19 | 20 | } 21 | public static void main(String[] args) throws Exception { 22 | FileOutputStream out = new FileOutputStream("javaout"); 23 | try { 24 | write(out,"http://www.scala-lang.org"); 25 | write(out,"http://www.scala-tools.org"); 26 | } finally { 27 | out.close(); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /documentation/src/main/resources/app/core/index.html: -------------------------------------------------------------------------------- 1 | 2 |The main goals of Scala IO is to provide a scalable solution to IO for Scala. In more 3 | concrete terms, the desire is to be able to both easily and quickly access the data from a 4 | data source like a file or URL as well as provide the options to micro manage how the data is 5 | accessed when performance is of the utmost importance.
6 |The first aspect is to provide an ARM (Automatic Resource Management) solution so resources 7 | are automatically closed after use. The design for ARM is essentially the loaner pattern where 8 | the framework opens a resource and passes the resource to a codeblock/function allowing the 9 | function to only concern itself with the data access logic and the ARM implementation will guarantee 10 | that the resource is closed after the access, irregardless of whether an error occurred or not.
11 |The second aspect is to provide lazy collection style access to an underlying resource allowing 12 | the skills obtained using the Scala collections library to be used to quickly implement solutions 13 | as if the resource is simply a collection. The underlying implementation will ensure the resource 14 | is closed and will ensure that only the necessary data is loaded. For example calls to drop will 15 | skip bytes when possible and take will close the connection after the requested data is obtained
16 |The third aspect is, as of 0.1 not yet implemented, is asynchronous data access in a simple manner. 17 | The first solution that is provided has been popularized by node js and is essentially the ability 18 | to register callbacks with a resource and they can, when possible, be executed in a single thread with 19 | a single connection.
20 |The fourth aspect (also not implemented for 0.1) is an iteree pattern for IO. This design will 21 | will be the basis of the async aspect and will have two levels of complexity. The first will be 22 | a simple function callback to obtain all data and the second will be the ability to return a Done 23 | event to short-circuit the data loading.
24 |The final piece of the puzzle is the provide a consistent manner for handling exceptions. The 25 | initial implementation simply throws exceptions as they occur but it will be possible to register an 26 | exception handle with your ARM resource to control how to handle exceptions. 27 |
28 | -------------------------------------------------------------------------------- /documentation/src/main/resources/app/css/img/texture_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseeichar/scala-io/2bd04c3d0aa2f6073deb4439a0d7963264512ebc/documentation/src/main/resources/app/css/img/texture_1.png -------------------------------------------------------------------------------- /documentation/src/main/resources/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseeichar/scala-io/2bd04c3d0aa2f6073deb4439a0d7963264512ebc/documentation/src/main/resources/app/favicon.ico -------------------------------------------------------------------------------- /documentation/src/main/resources/app/file/index.html: -------------------------------------------------------------------------------- 1 | The Scala IO File subproject is an adaptation of the Java NIO2 Filesystem to Scala. 2 | While the main inspiration was NIO2 because of its flexibility and design considerations 3 | for cross platform filesystem, the actual APIs have diverged in order to be more idiomatic 4 | Scala. 5 |6 | Note: At the moment scala.io.file is still very volatile the client APIs should be 7 | fairly stable (for a 0.1.0 version) but the API facing the implementer will likely change dramatically as more 8 | of the issues are encountered through implementation of new filesystems. So if you wish 9 | to implement a filesystem I would like the feedback but be aware that it will require migration 10 | as the API matures. 11 |
12 | The Filesystem API consists of two APIs one for the implementer of filesystems and one for the 13 | user of the Filesystem API. As described earlier the FileSystem API originated from the Java 7 14 | NIO2 filesystem and almost all the capability of that API are present in the scala.io.file API. 15 | However there are still aspects that I have not had time to add to scala.io.file. A few 16 | examples of features that will be added are: 17 |
3 | The Scala IO umbrella project consists of a few sub projects for different aspects and 4 | extensions of IO. There are two main components of Scala IO: 5 |
6 |13 | As an example of what Scala IO brings to the table the following examples compare Java IO vs Scala IO performing 14 | a simple task of reading data from two URLs and writing them to a file. (I found it amusing that I actually messed up 15 | the Java example the first try and had to debug it). 16 |
21 | If you have any suggestions please open a ticket at 22 | https://github.com/jesseeichar/scala-io/issues 23 |
24 | I welcome patches, bug reports and suggestions for this documentation or for the libraries themselves. 25 |
26 | The forum for discussions is the scala-incubator users group (at least for now) 27 | http://groups.google.com/group/scala-incubator 28 |
29 |30 | If you are interested at looking at the code, you are welcome to take a look at: 31 | https://github.com/jesseeichar/scala-io 32 |
33 | -------------------------------------------------------------------------------- /documentation/src/main/resources/app/performance/index.html: -------------------------------------------------------------------------------- 1 | 2 |In order ensure that Scala-IO will be a performant library there are an ever growing suite of tests that are designed to measure the performance of a particular IO operation performed by Scala-IO.
3 |In addition to the simple measurement is the "ideal" implementation which is a java based implementation that is the best possible implementation. Scala-IO isn't really intended to reach that performance goal but it should constantly approach that goal.
4 |Also, to keep us honest, there is a history of the performance. Hopefully that will track steadily improving performance characteristics
5 | 6 |The required change is essentially as follows: 20 |
output.openOutput{out =>
23 | out.write(3)
24 | out.write("hi")
25 | }
26 | for {
29 | outp <- output.outputProcessor
30 | out = outp.asOutput
31 | } {
32 | out.write(3)
33 | out.write(4)
34 | }
35 | Or: Since out's write operations return Processors they can be interleaved within the for comprehension if needed like:
36 | for {
37 | out <- output.outputProcessor
38 | _ <- out.write(3)
39 | _ <- out.write(4)
40 | } ()
41 | Scala IO Core will be completed before much more work is done on the FS API so that the library 3 | won't be forever being developed. In addition to the major items listed below the common task of 4 | improving API and removing inconsistency will always be a focus. As will performance.
5 |Welcome to the new Scala IO documentation Site.
9 | 10 | Find Version: 11 |17 | * IE a symbolic link maybe treated as a file in some cases but a Directory cannot. So 18 | * if a file operation is attempted on a Directory a NotFileException will be thrown 19 | *
20 | * To safely use {@link File} one should use the following code: 21 | *
22 | *
23 | * import scala.util.control.Exception._
24 | * catching(classOf[NotFileException]) opt {
25 | * file.lines foreach (println _)
26 | * } match {
27 | * case None => println ("Oh no the path is not a file")
28 | * case Some(names) => println ("oh everything went as planned and we got all the lines: "+lines)
29 | * }
30 | *
31 | *
32 | *
33 | * @author Jesse Eichar
34 | * @since 1.0
35 | */
36 | case class NotFileException(path:String) extends IOException with ControlThrowable {
37 | override lazy val toString = path + "is not a file"
38 | }
39 |
40 | /**
41 | * This is a control exception that indicates the underlying filesystem object either does not exist or is not a Directory
42 | * 43 | * To safely use {@link PathSet} one should use the following code: 44 | *
45 | *
46 | * import scala.util.control.Exception._
47 | * catching(classOf[NotDirectoryException]) opt {
48 | * ds map (_.name)
49 | * } match {
50 | * case None => println ("Oh no the path is not a directory!")
51 | * case Some(names) => println ("oh everything went as planned and we got all the names: "+names)
52 | * }
53 | *
54 | *
55 | *
56 | * @author Jesse Eichar
57 | * @since 1.0
58 | */
59 | case class NotDirectoryException(path:String) extends IOException with ControlThrowable{
60 | override lazy val toString = path + " is not a directory"
61 | }
62 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/FileSystemPlugins.scala:
--------------------------------------------------------------------------------
1 | package scalax.file
2 |
3 | import java.net.URI
4 |
5 | /**
6 | *
7 | * User: jeichar
8 | * Date: Oct 2, 2010
9 | * Time: 9:31:09 PM
10 | */
11 |
12 | object FileSystemPlugins {
13 | def lookup(uri:URI): Option[Path] = {
14 | uri.getScheme match {
15 | case "file" => Some(Path.fromString(uri.getRawPath))
16 | case "ramfs" => Some(scalax.file.ramfs.RamFileSystem(uri))
17 | case _ => None
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/GlobParser.scala:
--------------------------------------------------------------------------------
1 | package scalax.file
2 |
3 | import util.parsing.combinator.RegexParsers
4 | import java.util.regex.Pattern
5 |
6 | class GlobParser(fileSystem:FileSystem) extends RegexParsers {
7 | import Pattern.quote
8 |
9 |
10 | val safeSep = if(fileSystem.separator == "\\") "\\\\" else fileSystem.separator
11 | val quoteSep = if(fileSystem.separator == "\\") "\\\\" else quote(fileSystem.separator)
12 | val noSep = "[^"+safeSep+"]"
13 | val doubleStar: Parser[Any] = "**" ^^ {case _ => ".*"}
14 | val star: Parser[Any] = "*" ^^ {case _ => noSep+"*"}
15 | val question: Parser[Any] = "?" ^^ {case _ => noSep}
16 | val escape: Parser[String] = """\\.?""".r
17 | val removeEscape: Parser[String] = escape ^^ {case r => r drop 1}
18 | val choice: Parser[Any] = '{' ~> repsep(rep1(removeEscape | "[^{}},]".r) ^^ {case l => l mkString},',') <~ '}' ^^ {_.map (quote) mkString ("(","|",")") }
19 | val group: Parser[Any] = '[' ~> repsep(rep1(escape | """[^\[\]]""".r) ^^ {case l => l mkString},',') <~ ']' ^^ {
20 | case g =>
21 | val groups = g.mkString
22 | val finalGroups = if(groups startsWith "!") '^'+groups.drop(1) else groups
23 | "["+finalGroups+"]"
24 | }
25 | val value: Parser[Any] = ("""[^*?/\\\{\}\[\]""" + safeSep + "]+").r ^^ {case c => quote(c)}
26 | val segment: Parser[Any] = rep(group | choice | escape | value | star | question) ^^ {case segment => segment mkString ""} ||| doubleStar
27 | val separator: Parser[Any] ="/|" + quoteSep r
28 | val root: Parser[Any] = fileSystem.roots map {r => quote(r.path)} mkString ("|") r
29 |
30 | val path: Parser[String] = opt(root) ~ repsep(segment,separator) ^^ {
31 | case Some(root) ~ path => root + (path mkString quoteSep)
32 | case None ~ path => path mkString quoteSep
33 | }
34 |
35 | def apply(glob:String) : String = parseAll(path,glob) match {
36 | case Success(r,_) => r
37 | case Failure(msg,_) => throw new RuntimeException("Failed to parse "+glob+" as a 'glob' pattern: "+msg)
38 | case Error(msg,_) => throw new RuntimeException("Error parsing "+glob+" as a 'glob' pattern: "+msg)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/ImplicitConversions.scala:
--------------------------------------------------------------------------------
1 | package scalax.file
2 |
3 | import defaultfs.DefaultPath
4 | import java.io.File
5 |
6 | /**
7 | * Contains the implicit conversion methods for converting to Paths and related objects
8 | *
9 | * User: jeichar
10 | * Date: 3/24/12
11 | * Time: 7:26 PM
12 | */
13 | object ImplicitConversions {
14 | /**
15 | * Method to implicitly convert a string to a [[scalax.file.Path]]
16 | * object
17 | */
18 | implicit def string2path(s: String)(implicit fileSystem: FileSystem = FileSystem.default): Path = fileSystem.fromString(s)
19 | /**
20 | * Method to implicitly convert a [[java.io.File]] to a [[scalax.file.defaultfs.DefaultPath]]
21 | * object
22 | */
23 | implicit def jfile2path(jfile: File): DefaultPath = FileSystem.default.fromString(jfile.getPath)
24 | /**
25 | * Implicitly convert a [[scalax.file.defaultfs.DefaultPath]] to a [[java.io.File]]
26 | */
27 | implicit def defaultPath2jfile(path:DefaultPath): File = path.jfile
28 | }
29 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/ImplicitConverters.scala:
--------------------------------------------------------------------------------
1 | package scalax.file
2 |
3 | import defaultfs.DefaultPath
4 | import java.io.File
5 |
6 | /**
7 | * Contains the implicit conversion methods for converting to Paths and related objects
8 | *
9 | * User: jeichar
10 | * Date: 3/24/12
11 | * Time: 7:26 PM
12 | */
13 | object ImplicitConverters {
14 | /**
15 | * Method to implicitly add an asPath method to String
16 | */
17 | implicit def stringAsPath(s: String) = new {
18 | def asPath(implicit fileSystem: FileSystem = FileSystem.default):Path = fileSystem.fromString(s)
19 | }
20 |
21 | /**
22 | * Method to implicitly convert add an asPath method to [[java.io.File]]
23 | */
24 | implicit def jfileAsPath(jfile: File) = new {
25 | def asPath = FileSystem.default.fromString(jfile.getPath)
26 | }
27 |
28 | /**
29 | * Implicitly convert a an asJFile method to [[scalax.file.defaultfs.DefaultPath]]
30 | */
31 | implicit def defaultPathAsJFile(path: DefaultPath) = new {
32 | def asFile = path.jfile
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/PathMatcherFactory.scala:
--------------------------------------------------------------------------------
1 | package scalax.file
2 |
3 | import PathMatcher.{GlobNameMatcher, RegexNameMatcher, FunctionMatcher}
4 | import util.matching.Regex
5 | import java.util.regex.Pattern
6 |
7 | /**
8 | *
9 | * User: jeichar
10 | * Date: Oct 1, 2010
11 | * Time: 8:23:16 AM
12 | */
13 | trait PathMatcherFactory[-T] extends Function1[T,PathMatcher[Path]]
14 |
15 | object PathMatcherFactory {
16 | implicit object FunctionToMatcher extends PathMatcherFactory[Function1[Path, Boolean]] {
17 | def apply(f: (Path) => Boolean): PathMatcher[Path] = f match {
18 | case m: PathMatcher[Path] => m
19 | case f => new FunctionMatcher(f)
20 | }
21 | }
22 | implicit object GlobToMatcher extends PathMatcherFactory[String] {
23 | def apply(f: String): PathMatcher[Path] = GlobNameMatcher(f)
24 | }
25 | implicit object RegexToMatcher extends PathMatcherFactory[Regex] {
26 | def apply(f: Regex): PathMatcher[Path] = RegexNameMatcher(f)
27 | }
28 | implicit object PatternToMatcher extends PathMatcherFactory[Pattern] {
29 | def apply(f: Pattern): PathMatcher[Path] = RegexNameMatcher(f)
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/PathURLStreamHandlerFactory.scala:
--------------------------------------------------------------------------------
1 | /* __ *\
2 | ** ________ ___ / / ___ Scala API **
3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar **
4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5 | ** /____/\___/_/ |_/____/_/ | | **
6 | ** |/ **
7 | \* */
8 |
9 | package scalax.file
10 |
11 | import java.net._
12 | import ramfs.RamFileSystem
13 |
14 | /**
15 | * Adds support to for the filesystem URL protocols.
16 | *
17 | * This handler factory can be used as a replacement for the default handler factory
18 | * by calling PathURLStreamHandlerFactory.install. This will attempt to call
19 | * URL.setURLStreamHandlerFactory using the PathURLStreamHandlerFactory as the parameter
20 | *
21 | * This does not always work however because the URL.setURLStreamHandlerFactory method
22 | * can only be called once per JVM. For example Tomcat calls that method on startup
23 | * and therefore it cannot called when using tomcat.
24 | *
25 | * A second way to be able to create URLs that can open connections to custom Path
26 | * implementations is to create the URLs using:
27 | *
28 | * new URL(null,"protocol://path",new PathURLStreamHandler())
29 | *
30 | * The final and perhaps best way (if possible) is to start the JVM with the
31 | * parameter -Djava.protocol.handler.pkgs=scalax.file
32 | * This will instruct the JVM to look for protocol handlers provided by scalaio
33 | */
34 | object PathURLStreamHandlerFactory extends URLStreamHandlerFactory {
35 | def install = URL.setURLStreamHandlerFactory(this)
36 |
37 | val supported = List(RamFileSystem.protocol)
38 |
39 | def createURLStreamHandler(protocol:String) = {
40 | if(supported contains protocol) Class.forName("scalax.file."+protocol+".Handler").newInstance.asInstanceOf[URLStreamHandler]
41 | else null
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/attributes/file_attributes.scala:
--------------------------------------------------------------------------------
1 | /* __ *\
2 | ** ________ ___ / / ___ Scala API **
3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar **
4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5 | ** /____/\___/_/ |_/____/_/ | | **
6 | ** |/ **
7 | \* */
8 |
9 | package scalax.file.attributes
10 |
11 | /**
12 | * Represents a implementation specific attribute
13 | * of a file or directory.
14 | *
15 | * @author Jesse Eichar
16 | * @since 1.0
17 | */
18 | abstract class FileAttribute[T] (val name:String, val value:T)
19 | case class GenericFileAttribute[T](override val name:String, override val value:T) extends FileAttribute[T](name,value)
20 | case class LastModifiedAttribute(override val value:Long) extends FileAttribute[Long]("lastModified", value)
21 | case class ReadAccessAttribute(readable:Boolean) extends FileAttribute[Boolean]("read", readable)
22 | case class WriteAccessAttribute(writable:Boolean) extends FileAttribute[Boolean]("write", writable)
23 | case class ExecuteAccessAttribute(executable:Boolean) extends FileAttribute[Boolean]("execute", executable)
24 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/defaultfs/DefaultFileOps.scala:
--------------------------------------------------------------------------------
1 | /* __ *\
2 | ** ________ ___ / / ___ Scala API **
3 | ** / __/ __// _ | / / / _ | (c) 20010-2011, Jesse Eichar **
4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ **
5 | ** /____/\___/_/ |_/____/_/ | | **
6 | ** |/ **
7 | \* */
8 |
9 | package scalax.file
10 | package defaultfs
11 |
12 | import scalax.io._
13 | import scalax.io.managed._
14 | import StandardOpenOption._
15 | import scalax.io.nio.SeekableFileChannel
16 | import scalax.io.support.FileUtils._
17 | import java.io.{FileInputStream, File => JFile}
18 |
19 | /**
20 | * Not part of API.
21 | *
22 | * @author Jesse Eichar
23 | * @since 1.0
24 | */
25 | private[file] trait DefaultFileOps {
26 | self : DefaultPath =>
27 |
28 | override def inputStream =
29 | Resource.fromInputStream(new FileInputStream(jfile)).updateContext(fileSystem.context)
30 |
31 | override def outputStream(openOptions: OpenOption*) = {
32 | val r = openOptions match {
33 | case Seq() =>
34 | openOutputStream(jfile,ReadWrite)
35 | case opts if opts forall {opt => opt != Write && opt != Append} =>
36 | openOutputStream(jfile,openOptions :+ Write)
37 | case _ =>
38 | openOutputStream(jfile,openOptions)
39 | }
40 | r.updateContext(fileSystem.context)
41 | }
42 | override def channel(openOptions: OpenOption*) =
43 | Resource.fromSeekableByteChannel(openChannel(jfile,openOptions)).updateContext(fileSystem.context)
44 |
45 | override def fileChannel(openOptions: OpenOption*):Some[SeekableByteChannelResource[SeekableFileChannel]] =
46 | Some(Resource.fromSeekableByteChannel(openChannel(jfile,openOptions)).updateContext(fileSystem.context))
47 |
48 |
49 | def withLock[R](start: Long = 0, size: Long = -1, shared: Boolean = false, context:ResourceContext)(block: Seekable => R): Option[R] = {
50 | val self = this
51 | fileChannel().get.acquireAndGet{ fc =>
52 | Option(fc.self.tryLock(start,size,shared)).map{_ => block(self)}
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/file/src/main/scala/scalax/file/option.scala:
--------------------------------------------------------------------------------
1 | package scalax.file
2 |
3 | import scalax.io.OpenOption
4 |
5 | /**
6 | * Flags an option as an options that declares how to deal with links
7 | * 8 | * See LinkOption object for the common options 9 | *
10 | * 11 | * @author Jesse Eichar 12 | * @since 1.0 13 | */ 14 | trait LinkOption 15 | 16 | /** 17 | * Contains the common Link Options 18 | * 19 | * @author Jesse Eichar 20 | * @since 1.0 21 | */ 22 | object LinkOption extends Enumeration { 23 | val NoFollowLinks = new Val(nextId) with LinkOption with OpenOption with CopyOption 24 | } 25 | 26 | /** 27 | * Flags an option as an option that declares how a file should be copied 28 | * 29 | * @author Jesse Eichar 30 | * @since 1.0 31 | */ 32 | trait CopyOption 33 | -------------------------------------------------------------------------------- /file/src/main/scala/scalax/file/ramfs/Handler.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.file.ramfs 10 | import java.net._ 11 | import java.lang.Class 12 | 13 | class Handler extends URLStreamHandler { 14 | def openConnection(url:URL) = { 15 | require(url.getProtocol == RamFileSystem.protocol) 16 | require(url.getHost contains "!") 17 | 18 | new RamURLConnection(url) 19 | } 20 | } 21 | 22 | object Handler extends Handler 23 | 24 | class RamURLConnection(url:URL) extends URLConnection(url) { 25 | lazy val path = { 26 | val Array(id,path) = url.toString.drop(RamFileSystem.protocol+"://" size).split("!") 27 | val fs = RamFileSystem(RamFileSystem.RamFsId(id)) 28 | val segments = if(path startsWith "/") fs.separator +: path.split("/") else path.split("/") 29 | fs.fromSeq(segments) 30 | } 31 | def connect = {} 32 | 33 | override def getInputStream = { 34 | require(getDoInput, "getDoInput must be true") 35 | path.inputStream.open().get 36 | } 37 | 38 | override def getOutputStream = { 39 | require(getDoOutput, "getDoOutput must be true") 40 | path.outputStream().open().get 41 | } 42 | 43 | override def getLastModified = path.lastModified 44 | 45 | override def getContentLength = path.size.map{_.toInt}.getOrElse(-1) 46 | } 47 | -------------------------------------------------------------------------------- /file/src/samples/scala/PathsToJavaFile.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Shows how to obtain a java io File from a scala io Path (when possible). 3 | */ 4 | object PathsToJavaFile { 5 | /** 6 | * Not all Paths can be converted to java.io.File objects because a Path 7 | * is not necessarily a file on the default file system. It could be a file 8 | * in a zip file. As such one must first check to see if the the Path is 9 | * a DefaultPath. Once that is established the jfile can be obtained from 10 | * the DefaultPath. 11 | *12 | * In java 7 scala io paths will be able to be converted to java 7 paths 13 | *
14 | */ 15 | def pathToJavaFile { 16 | import scalax.file.Path 17 | import scalax.file.defaultfs.DefaultPath 18 | import java.io.File 19 | 20 | val somePath = Path("/somedir/somefile.txt") 21 | somePath match { 22 | case defaultPath:DefaultPath => 23 | val file:File = defaultPath.jfile 24 | // do something with file 25 | case _ => 26 | // handle non-file case 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /file/src/samples/scala/create-and-delete-files-and-directories.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Demonstrate how to create files or directories from a 3 | * path object. 4 | */ 5 | object CreateAndDeleteFilesAndDirectoriesFromPaths { 6 | /** 7 | * Create files and directories 8 | */ 9 | def create{ 10 | import scalax.file.Path 11 | 12 | val path: Path = Path ("/tmp/file") 13 | 14 | // create file but fail if the file already exists. 15 | // an exception may be thrown 16 | path.createFile() 17 | 18 | // force create a file will fail if it is a directory which 19 | // contain children 20 | path.createFile(failIfExists=false) 21 | 22 | // TODO createFile with attributes 23 | 24 | // create a directory at the path location 25 | path.createDirectory() 26 | path.createDirectory(failIfExists=false) 27 | } 28 | 29 | /** 30 | * Delete files and directories 31 | */ 32 | def delete { 33 | import scalax.file.Path 34 | 35 | val path: Path = Path ("/tmp/file") 36 | 37 | // Will throw IOException if file could not be deleted 38 | // even if it cannot be deleted because it does not exist 39 | path.delete() 40 | 41 | // Will not throw exception if file does not exist but will 42 | // if it is a non-empty directory or not writeable 43 | path.deleteIfExists() 44 | 45 | // Delete path and all children. This is currently not a safe method so 46 | // it should be used with caution. Future versions will be better 47 | // by default it will throw an exception if one of the files cannot be deleted 48 | path.deleteRecursively() 49 | 50 | // Delete path and all children. If a file cannot be deleted then continue on and delete 51 | // all that can be deleted 52 | path.deleteRecursively(true) 53 | // or 54 | path.deleteRecursively(continueOnFailure=true) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /file/src/samples/scala/create-and-move-files-and-directories.scala: -------------------------------------------------------------------------------- 1 | import scalax.file.ramfs.RamFileSystem 2 | 3 | /** 4 | * Demonstrate creating simple paths and moving them withing the filesystem and 5 | * to other filesystems. 6 | */ 7 | object CreateAndMoveFilesAndDirectories { 8 | /** 9 | * copy and move/rename files 10 | */ 11 | def copyAndMovePaths{ 12 | import scalax.file.Path 13 | 14 | val path: Path = Path ("/tmp/file") 15 | val dest: Path = Path ("/tmp/file2") 16 | 17 | // make a copy of the file 18 | // by default this will fail if dest already exists 19 | // also attribute information like datestamp will be 20 | // set on the destination file 21 | // If path is a directory the copy will not be recursive 22 | path.copyTo (dest) 23 | 24 | // Copy explicitly declaring options 25 | path.copyTo (target=dest, 26 | copyAttributes=false, 27 | replaceExisting=true) 28 | 29 | // Move/Rename the path 30 | // by default throw exception if destination exists 31 | // and if a copy is required by underlying filesystem then do that 32 | path.moveTo (target=dest) 33 | 34 | // Here we will overwrite existing files (but not non-empty directories) 35 | // and will fail if a copy is required (similar to java.file.File.renameTo) 36 | // if a failure occures an exception is thrown 37 | path.moveTo (target=dest, 38 | replace=true, 39 | atomicMove=true) 40 | } 41 | 42 | /** 43 | * Since the underlying filesystem could change to safely use the PathSet API it is recommended to handle the 44 | * NotDirectoryException 45 | */ 46 | def notDirectoryException { 47 | import scalax.file.{Path, NotDirectoryException} 48 | import scala.util.control.Exception._ 49 | 50 | catching (classOf[NotDirectoryException]) opt { 51 | Path ("/tmp/dir").children() map ( _.name) 52 | } match { 53 | case None => println ("Not a direcory") 54 | case Some(names) => println ("files names = "+names) 55 | } 56 | } 57 | 58 | /** 59 | * Move a file from one filesystem to another 60 | */ 61 | def moveBetweenFileSystems { 62 | import scalax.file._ 63 | import ramfs.RamFileSystem 64 | 65 | val fs = RamFileSystem() 66 | val ramPath = fs("/","tmp") 67 | val path = Path("file") // default filesystem 68 | 69 | path.moveTo(ramPath) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /file/src/samples/scala/create-paths.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Demonstrate various ways of creating Path objects 3 | */ 4 | object CreatePath { 5 | 6 | // Create a Path in the default filesystem explicitly 7 | def explicitCreation = { 8 | import scalax.file.{Path, FileSystem} 9 | val path1: Path = Path ("/tmp/file1",'/') 10 | 11 | // when an absolute path is desired don't forget "/" 12 | val path2: Path = Path ("/","tmp","file1") 13 | 14 | // include windows examples for completeness 15 | val path3: Path = Path ("c:/tmp/file2",'/') 16 | val path4: Path = Path ("c:","tmp","file2") 17 | val path5: Path = Path ("""c:\tmp\file3""",'\\') 18 | 19 | // a filesystem can also be used to create Paths 20 | val path6: Path = FileSystem.default ("/tmp/file6",'/') 21 | } 22 | 23 | // Create Path from URI 24 | def fromURI = { 25 | import scalax.file.{Path} 26 | import java.net.URI 27 | // the URI type indicates which filesystem to use 28 | // file:// indicates the default filesystem 29 | val path1: Option[Path] = Path (new URI ("file:///tmp/file1")) 30 | 31 | // include windows examples for completeness 32 | val path2: Option[Path]= Path (new URI ("file://c:/tmp/file2")) 33 | val path3: Option[Path]= Path (new URI ("file://c:\\tmp\\file3")) 34 | 35 | // For opening a zip filesystem 36 | val zipPath: Option[Path] = Path (new URI ("zip:///tmp/zipfile.zip!/file")) 37 | } 38 | 39 | // TODO demonstrate the GenericPath usage 40 | 41 | // Create path from java.file.File. 42 | def fromJFile = { 43 | import java.io.File 44 | import scalax.file.Path 45 | val path1: Path = Path (new File ("/tmp/file1")) 46 | // include windows examples for completeness 47 | val path2: Path = Path (new File ("file://c:/tmp/file2")) 48 | val path3: Path = Path (new File ("file://c:\\tmp\\file3")) 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /file/src/samples/scala/create-temp.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating Temporary Files and directories 3 | */ 4 | object CreateTemporary { 5 | 6 | def createTempFiles { 7 | import scalax.file.{Path, FileSystem} 8 | 9 | // by default the filesystem is the defaultFileSystem (surprise :-) ) 10 | // using the default parameters will create a randomly named file in 11 | // the system temp directory which will be deleted when the JVM exists 12 | val tmpFile1: Path = Path.createTempFile() 13 | 14 | // fully declare the temporary file parameters 15 | // all parameters have defaults so there are many option 16 | // Note that not all filesystems support creating temporary 17 | // files. 18 | // The default filesystem does 19 | val tmpFile2: Path = Path.createTempFile(prefix = "tmpFile", 20 | suffix = "tmp", 21 | dir = "/tmp", 22 | deleteOnExit = false) 23 | 24 | // a file system can also be used to create temporary files/directories 25 | FileSystem.default.createTempFile() 26 | } 27 | 28 | def createTempDirectories { 29 | // Note: Both createTempFile and createTempDirectory have the same parameters 30 | import scalax.file.{Path, FileSystem} 31 | 32 | // by default the filesystem is the defaultFileSystem (surprise :-) ) 33 | // using the default parameters will create a randomly named directory in 34 | // the system temp directory which will be deleted when the JVM exists 35 | val tmpFile1: Path = Path.createTempDirectory() 36 | 37 | // fully declare the temporary directory parameters 38 | // all parameters have defaults so there are many option 39 | // Note that not all filesystems support creating temporary 40 | // files/directories. 41 | // The default filesystem does 42 | val tmpFile2: Path = Path.createTempDirectory(prefix = "tmpFile", 43 | suffix = "tmp", 44 | dir = "/tmp", 45 | deleteOnExit = false) 46 | 47 | // a file system can also be used to create temporary files/directories 48 | FileSystem.default.createTempFile() 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /file/src/samples/scala/implicits.scala: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Using implicit conversions to convert between strings Java Files 4 | * and Scala Paths 5 | */ 6 | object implicits { 7 | /** 8 | * Implicitly convert strings to paths 9 | */ 10 | def stringToFile = { 11 | import scalax.file.Path 12 | import scalax.file.ImplicitConversions.string2path 13 | 14 | val filePath: Path = "/tmp/file" 15 | } 16 | 17 | /** 18 | * Implicitly convert files to paths 19 | */ 20 | def javaFileToPath = { 21 | import java.io.File 22 | import scalax.file.defaultfs.DefaultPath 23 | import scalax.file.ImplicitConversions.jfile2path 24 | 25 | val filePath: DefaultPath = new File ("/tmp/file") 26 | } 27 | 28 | /** 29 | * Implicitly convert files to paths 30 | */ 31 | def pathTojavaFile = { 32 | import java.io.File 33 | import scalax.file.FileSystem 34 | import scalax.file.ImplicitConversions.defaultPath2jfile 35 | 36 | // DefaultPath objects can be converted to java.io.File objects 37 | val file: File = FileSystem.default("somefile") 38 | } 39 | 40 | /** 41 | * Examples of using the implicit converters to convert to 42 | * and from java.io.File and scalax.file.Path objects 43 | */ 44 | def implicitConverters = { 45 | import java.io.File 46 | import scalax.file.defaultfs.DefaultPath 47 | import scalax.file.Path 48 | import scalax.file.ImplicitConverters._ 49 | 50 | val path: DefaultPath = new File("/tmp/file").asPath 51 | val fileAgain: File = path.asFile 52 | val pathFromString: Path = "hi".asPath 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /file/src/samples/scala/readme: -------------------------------------------------------------------------------- 1 | The following copyright and warning apply to all code in the samples directory 2 | 3 | __ 4 | ________ ___ / / ___ Scala API 5 | / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar 6 | __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ 7 | /____/\___/_/ |_/____/_/ | | 8 | |/ 9 | 10 | 11 | 12 | ************************************************************************************* 13 | This file contains code samples illustrating how to use the Scala IO API. It is 14 | not a test file, other than it is compiled. 15 | 16 | 17 | These examples will be the bases for the tests created for the IO project 18 | 19 | Note: In order to be more useful all variable have the expected type explicitly 20 | declared so that the compiler can detect if there is a problem with the 21 | sample code. It is not required to work 22 | -------------------------------------------------------------------------------- /file/src/samples/scala/roots.scala: -------------------------------------------------------------------------------- 1 | import scalax.file.defaultfs.DefaultPath 2 | 3 | /** 4 | * Look up the rots of a path 5 | */ 6 | object Roots { 7 | def listRoots { 8 | // list roots of defaultFileSystem 9 | import scalax.file.{Path, FileSystem} 10 | val roots1: Set[DefaultPath] = Path.roots 11 | // This method delegates to the defaultFileSystem as follows 12 | val roots2: Set[DefaultPath] = FileSystem.default.roots 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /file/src/test/resources/resources/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jesseeichar/scala-io/2bd04c3d0aa2f6073deb4439a0d7963264512ebc/file/src/test/resources/resources/image.png -------------------------------------------------------------------------------- /file/src/test/resources/resources/text: -------------------------------------------------------------------------------- 1 | 1 2 | a 3 | A 4 | à 5 | ä 6 | £ 7 | ≈ 8 | ゼ 9 | ` 10 | 11 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/GlobParserTest.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test 2 | 3 | /* __ *\ 4 | ** ________ ___ / / ___ Scala API ** 5 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 6 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 7 | ** /____/\___/_/ |_/____/_/ | | ** 8 | ** |/ ** 9 | \* */ 10 | 11 | import org.junit.Assert._ 12 | import org.junit.Test 13 | import scalax.file.ramfs.RamFileSystem 14 | import scalax.file.FileSystem 15 | import scalax.file.GlobParser 16 | import java.util.regex.Pattern 17 | 18 | class GlobParserTest { 19 | def compareGlob(glob:String, regex:String)(implicit fs:FileSystem) { 20 | val parser = new GlobParser(fs) 21 | val result = parser(glob) 22 | assertEquals("expected '"+glob+"' to be parsed into '"+regex+"' but got '"+result+"'", regex, result) 23 | } 24 | @Test 25 | def testGlobToRegEx :Unit = { 26 | val sep = "/" 27 | implicit val fs = new RamFileSystem(separator=sep) 28 | 29 | val noSep = "[^"+sep+"]" 30 | compareGlob("**",".*") 31 | compareGlob("*","[^"+sep+"]*") 32 | compareGlob(""+sep+"*",sep+noSep+"*") 33 | compareGlob(""+sep+"**",""+sep+".*") 34 | compareGlob("\\*","\\*") 35 | compareGlob("/?","/"+noSep) 36 | compareGlob("h\\?","\\Qh\\E\\?") 37 | compareGlob("[a-z.]","[a-z.]") 38 | compareGlob("[!a-z.]","[^a-z.]") 39 | compareGlob("[!-]","[^-]") 40 | compareGlob("[-ab\\\\\\]]","[-ab\\\\\\]]") 41 | compareGlob("{h,he,l, escape?\\}}",List("h","he","l","escape?}") map (Pattern.quote) mkString ("(","|",")")) 42 | compareGlob("hi"+sep+"o**k","\\Qhi\\E\\Q"+sep+"\\E\\Qo\\E"+noSep+"*"+noSep+"*\\Qk\\E") 43 | compareGlob("hi"+sep+"o\\?","\\Qhi\\E\\Q"+sep+"\\E\\Qo\\E\\?") 44 | compareGlob("hi"+sep+"o\\"+sep+"hi"+sep,"\\Qhi\\E\\Q"+sep+"\\E\\Qo\\E\\"+sep+"\\Qhi\\E\\Q"+sep+"\\E") 45 | compareGlob("th.s"+sep+"\\\\ws"+sep,"\\Qth.s\\E\\Q"+sep+"\\E\\\\\\Qws\\E\\Q"+sep+"\\E") 46 | compareGlob("hi"+sep+"**"+sep+"[a-b]*.{scala,java}","\\Qhi\\E\\Q"+sep+"\\E.*\\Q"+sep+"\\E[a-b]"+noSep+"*\\Q.\\E(\\Qscala\\E|\\Qjava\\E)") 47 | 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/Node.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test 10 | 11 | import collection.mutable.ListBuffer 12 | 13 | object Node { 14 | val Sep = "/" 15 | } 16 | case class Node(path : String, parent : Option[Node], children : ListBuffer[Node] = ListBuffer[Node]()) extends Iterable[Node]{ 17 | self => 18 | parent.foreach {_.children += self} 19 | 20 | def iterator = children.iterator 21 | def all = (List[Node]() /: this) {case (acc,next) => acc ++ next} 22 | def name = path.split(Node.Sep).last 23 | 24 | override def toString = path 25 | } 26 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/PathMatcherFactoryTest.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test 2 | 3 | /* __ *\ 4 | ** ________ ___ / / ___ Scala API ** 5 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 6 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 7 | ** /____/\___/_/ |_/____/_/ | | ** 8 | ** |/ ** 9 | \* */ 10 | 11 | import org.junit.Assert._ 12 | import org.junit.Test 13 | import scalax.file.ramfs.RamFileSystem 14 | import scalax.file.PathMatcherFactory._ 15 | import scalax.file.{PathMatcher, Path, PathMatcherFactory} 16 | import scalax.file.PathMatcher.NameIs 17 | 18 | class PathMatcherFactoryTest { 19 | 20 | @Test 21 | def `function path matcher converts a function to a PathMatcher` : Unit = { 22 | val fs = new RamFileSystem() 23 | val namePath = fs("world","name") 24 | val notNamePath = fs("world","not") 25 | val nameis = FunctionToMatcher{_.name == "name"} 26 | val notnameis = - FunctionToMatcher{_.name == "name"} 27 | assertTrue(nameis(namePath)) 28 | assertFalse(nameis(notNamePath)) 29 | assertTrue(notnameis(notNamePath)) 30 | } 31 | 32 | @Test 33 | def `function path matcher converts a PathMatcher to a PathMatcher` : Unit = { 34 | val fs = new RamFileSystem() 35 | val namePath = fs("world","name") 36 | val notNamePath = fs("world","not") 37 | val nameis = FunctionToMatcher(FunctionToMatcher{_.name == "name"}) 38 | val notnameis = FunctionToMatcher(- FunctionToMatcher{_.name == "name"}) 39 | assertTrue(nameis(namePath)) 40 | assertFalse(nameis(notNamePath)) 41 | assertTrue(notnameis(notNamePath)) 42 | } 43 | 44 | def performAssertion[F](f:F = PathMatcher.All, path:Path, expectation:Boolean)(implicit fac:PathMatcherFactory[F]) = { 45 | assert(expectation == fac(f)(path)) 46 | } 47 | 48 | 49 | @Test 50 | def `method with implicit factory and default` : Unit = { 51 | val fs = new RamFileSystem() 52 | val namePath = fs("world","name") 53 | val notNamePath = fs("world","not") 54 | val nameis = NameIs("name") 55 | val notnameis = - NameIs("name") 56 | performAssertion(nameis,namePath,true) 57 | performAssertion(nameis,notNamePath,false) 58 | performAssertion(notnameis,notNamePath,true) 59 | performAssertion(notnameis,namePath,false) 60 | } 61 | 62 | 63 | } 64 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/ScalaIoMocks.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test 10 | 11 | import scalax.file.FileSystem 12 | import scalax.file.ramfs.RamFileSystem 13 | object ScalaIoMocks { 14 | def fileSystemMock:FileSystem = new RamFileSystem 15 | } 16 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/URLStreamHandlerFactoryTest.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test 10 | 11 | import scalax.file.PathURLStreamHandlerFactory 12 | import org.junit.Assert._ 13 | import org.junit.Test 14 | import scalax.file.ramfs.RamFileSystem 15 | 16 | class URLStreamHandlerFactoryTest { 17 | @Test 18 | def testDefaultFactories :Unit = { 19 | assertNotNull(PathURLStreamHandlerFactory createURLStreamHandler RamFileSystem.protocol) 20 | // the following should return null so the default handlers will be used 21 | assertNull(PathURLStreamHandlerFactory createURLStreamHandler "file") 22 | assertNull(PathURLStreamHandlerFactory createURLStreamHandler "http") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/Fixture.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs 10 | 11 | import scalax.file.Path.AccessModes._ 12 | import org.junit.{ 13 | Before, After 14 | } 15 | import scalax.file.FileSystem 16 | import scalax.test.sugar.AssertionSugar 17 | 18 | trait Fixture { 19 | 20 | def createFixture() : FileSystemFixture 21 | 22 | var fixture : FileSystemFixture = _ 23 | 24 | @Before 25 | def before() : Unit = { 26 | fixture = createFixture() 27 | assert(fixture != null) 28 | def testFile(javaRoot:java.io.File) = { 29 | javaRoot.getCanonicalPath == fixture.root.toRealPath().path 30 | } 31 | assert(fixture.root.fileSystem != FileSystem.default || !(java.io.File.listRoots().exists(testFile)), "Root cannot be the true file system root because some tests delete root which could be a major issues as it could delete entire filesystem") 32 | } 33 | 34 | @After 35 | def after() : Unit = try {fixture.after()} catch {case e => println("error in after:"+e)} 36 | 37 | def isWindows = AssertionSugar.isWindows && fixture.fs == FileSystem.default 38 | def permissions(modes:AccessMode*)= 39 | if(isWindows) Set(modes:_*) ++ Set(Read, Execute) 40 | else Set(modes:_*) 41 | 42 | } 43 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/FsFileOpsTests.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs 10 | 11 | import scalaio.test.AbstractFileOpsTests 12 | abstract class FsFileOpsTests extends AbstractFileOpsTests with Fixture { 13 | 14 | def path(implicit data : Array[Byte]) = { 15 | val path = fixture.path 16 | path.createFile() 17 | val ops = path 18 | ops write data 19 | path 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/FsFileSystemTests.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs 10 | 11 | import scalax.io._ 12 | import scalax.file._ 13 | import org.junit.Assert._ 14 | import org.junit.Test 15 | abstract class FsFileSystemTests extends scalax.test.sugar.AssertionSugar with Fixture{ 16 | implicit val codec = Codec.UTF8 17 | 18 | @Test 19 | def fileSystem_apply_creates_a_path() : Unit = { 20 | val path = Path.fromString(getClass.getClassLoader.getResource("resources/text").getFile) 21 | assertTrue(path.exists) 22 | assertTrue(path.canRead) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/FsPathObjectTests.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs 10 | 11 | import org.junit.Assert._ 12 | import org.junit.Test 13 | import scalax.file._ 14 | 15 | import java.io.File 16 | import java.net.URI 17 | 18 | abstract class FsPathObjectTests extends Fixture { 19 | 20 | @Test 21 | def path_object_should_implicitly_create_path_from_string(): Unit = { 22 | import scalax.file.ImplicitConversions.string2path 23 | 24 | { // brackets needed so compiler doesn't think later implicit was a mistake 25 | assertSame(FileSystem.default, "nonsense path".fileSystem) 26 | } 27 | 28 | implicit val fs = fixture.fs 29 | val p:Path = "hi" 30 | assertSame(fs, "path".fileSystem) 31 | } 32 | 33 | @Test 34 | def path_object_should_implicitly_create_jfile_from_path(): Unit = { 35 | import scalax.file.ImplicitConversions.defaultPath2jfile 36 | 37 | val p = FileSystem.default.createTempFile() 38 | val file:java.io.File = p 39 | assertSame(p.jfile, file) 40 | } 41 | 42 | @Test 43 | def path_object_extract_path_segments(): Unit = { 44 | fixture.fs("a", "b") match { 45 | case Path("a", _) => () // good 46 | case _ => fail("Path extractor should have extracted path segments") 47 | } 48 | 49 | } 50 | 51 | @Test 52 | def path_object_should_implicitly_create_path_from_a_java_file() : Unit = { 53 | import scalax.file.ImplicitConversions.jfile2path 54 | 55 | assertSame(FileSystem.default, new File("nonsense path").fileSystem) 56 | 57 | implicit val fs = fixture.fs 58 | assertSame(FileSystem.default, new File("path").fileSystem) 59 | } 60 | 61 | @Test 62 | def path_object_should_create_paths_from_a_string() : Unit = { 63 | assertSame(FileSystem.default, Path("nonsense path").fileSystem) 64 | } 65 | 66 | @Test 67 | def path_object_can_create_paths_from_a_uri() : Unit = { 68 | assertSame(FileSystem.default, Path(new URI("file:///tmp/")).get.fileSystem) 69 | val path = fixture.path 70 | val uri = path.toURI 71 | val fromURI = Path(uri).get 72 | assertSame(fixture.fs, fromURI.fileSystem) 73 | assertEquals(path, fromURI) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/FsSeekableTests.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs 10 | 11 | import scalax.io._ 12 | import scalaio.test.AbstractSeekableTests 13 | import org.junit.Test 14 | import scalax.file.Path 15 | import scalaio.test.SeekableTestUtils 16 | import java.io.IOException 17 | 18 | abstract class FsSeekableTests extends AbstractSeekableTests[Path] with Fixture with SeekableTestUtils[Path] { 19 | def forceErrorOnAccess() = { 20 | fixture.root.***.filter(_.isFile).foreach{ 21 | path => 22 | path .access = "" 23 | } 24 | fixture.root.access = "" 25 | } 26 | def openResource(openFunction: () => Unit, closeAction: CloseAction[Path]): Seekable = { 27 | fixture.root.*("*").foreach(_.deleteRecursively(true,true)) 28 | val path = fixture.path 29 | path.createFile(true) 30 | path 31 | } 32 | 33 | override def scalaIoException_On_Write_Error_by_default{ 34 | intercept[IOException] { 35 | errorOnWriteOut.write("hi") 36 | } 37 | } 38 | override def scalaIoException_On_Read_Error_by_default{ 39 | intercept[IOException] { 40 | errorOnWriteOut.write("hi") 41 | } 42 | } 43 | def canAddCloseAction = false 44 | override def canExecuteOpenFunction = false 45 | // can't do the close action for paths so... 46 | override def correctly_closes_resources = () 47 | override def input_closed_after_each_action = () 48 | override def scalaIoException_On_Write_Close_Error_by_default = () 49 | override def scalaIoException_On_Close_Error_by_default = () 50 | 51 | } 52 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/defaultfs/AllTests.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs.defaultfs 10 | 11 | import scalax.file.FileSystem 12 | import org.junit.Test 13 | import org.junit.Ignore 14 | 15 | class RandomPrefixTest { 16 | @Test 17 | def `windows paths cannot end in .` { 18 | 0 to 500 foreach {i => 19 | val prefix = FileSystem.default.randomPrefix 20 | assert(prefix(prefix.size - 1) != '.', "'"+prefix+"' should not end in a .") 21 | } 22 | } 23 | } 24 | class FsMatchingTest extends scalaio.test.fs.FsMatchingTests with DefaultFixture 25 | class FsDirectoryStreamTest extends scalaio.test.fs.FsPathSetTests with DefaultFixture { 26 | @Test @Ignore // ignore because if it passes it does nearly a full scan of harddrive so only when the issue is known to fail do we want to test this 27 | def stackOverflowBug : Unit = { 28 | println("start overflow bug test") 29 | FileSystem.default.roots.headOption foreach {path => 30 | val start = System.currentTimeMillis() 31 | val iter = (path ** "*.scala").iterator 32 | while(iter.hasNext && System.currentTimeMillis() - start < 30000) { 33 | iter.next 34 | } 35 | } 36 | println("done overflow bug test and it passed... yay") 37 | // no error is a pass 38 | } 39 | 40 | } 41 | class FsFileOpsTest extends scalaio.test.fs.FsFileOpsTests with DefaultFixture 42 | class FileSystemTest extends scalaio.test.fs.FsFileSystemTests with DefaultFixture 43 | class SeekableTest extends scalaio.test.fs.FsSeekableTests with DefaultFixture 44 | class BasicPathTest extends scalaio.test.fs.FsBasicPathTests with DefaultFixture 45 | class AccessSetTest extends scalaio.test.fs.FsAccessSetTests with DefaultFixture 46 | class PathObjectTest extends scalaio.test.fs.FsPathObjectTests with DefaultFixture 47 | class PathSetTest extends scalaio.test.fs.FsPathSetTests with DefaultFixture 48 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/defaultfs/DefaultFixture.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs.defaultfs 10 | 11 | 12 | import util.Random 13 | import scalax.file.{ 14 | Path, FileSystem 15 | } 16 | import org.junit.rules.TemporaryFolder 17 | 18 | import scalaio.test.fs.{ 19 | FileSystemFixture, Fixture 20 | } 21 | 22 | trait DefaultFixture extends Fixture{ 23 | val rnd : Random = new Random() 24 | 25 | def createFixture() = { 26 | val folder = new TemporaryFolder() 27 | new FileSystemFixture(FileSystem.default, rnd) { 28 | folder.create() 29 | 30 | override val root = FileSystem.default(folder.getRoot) 31 | override def after = { 32 | folder.delete() 33 | Thread.sleep(500) 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/ram/BackSlashTests.scala: -------------------------------------------------------------------------------- 1 | package scalaio.test.fs.ram 2 | 3 | /* __ *\ 4 | ** ________ ___ / / ___ Scala API ** 5 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 6 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 7 | ** /____/\___/_/ |_/____/_/ | | ** 8 | ** |/ ** 9 | \* */ 10 | 11 | class BackSlashFsMatchingTest extends scalaio.test.fs.FsMatchingTests with BackSlashRamFixture 12 | class BackSlashFsDirectoryStreamTest extends scalaio.test.fs.FsPathSetTests with BackSlashRamFixture 13 | class BackSlashFsFileOpsTest extends scalaio.test.fs.FsFileOpsTests with BackSlashRamFixture 14 | class BackSlashFileSystemTest extends scalaio.test.fs.FsFileSystemTests with BackSlashRamFixture 15 | class BackSlashSeekableTest extends scalaio.test.fs.FsSeekableTests with BackSlashRamFixture 16 | class BackSlashBasicPathTest extends scalaio.test.fs.FsBasicPathTests with BackSlashRamFixture 17 | class BackSlashAccessSetTest extends scalaio.test.fs.FsAccessSetTests with BackSlashRamFixture 18 | class BackSlashPathObjectTest extends scalaio.test.fs.FsPathObjectTests with BackSlashRamFixture 19 | class BackSlashPathSetTest extends scalaio.test.fs.FsPathSetTests with BackSlashRamFixture 20 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/ram/ForwardSlashTests.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs.ram 10 | 11 | 12 | class ForwardSlashFsMatchingTest extends scalaio.test.fs.FsMatchingTests with ForwardSlashRamFixture 13 | class ForwardSlashFsDirectoryStreamTest extends scalaio.test.fs.FsPathSetTests with ForwardSlashRamFixture 14 | class ForwardSlashFsFileOpsTest extends scalaio.test.fs.FsFileOpsTests with ForwardSlashRamFixture 15 | class ForwardSlashFileSystemTest extends scalaio.test.fs.FsFileSystemTests with ForwardSlashRamFixture 16 | class ForwardSlashSeekableTest extends scalaio.test.fs.FsSeekableTests with ForwardSlashRamFixture 17 | class ForwardSlashBasicPathTest extends scalaio.test.fs.FsBasicPathTests with ForwardSlashRamFixture 18 | class ForwardSlashAccessSetTest extends scalaio.test.fs.FsAccessSetTests with ForwardSlashRamFixture 19 | class ForwardSlashPathObjectTest extends scalaio.test.fs.FsPathObjectTests with ForwardSlashRamFixture 20 | class ForwardSlashPathSetTest extends scalaio.test.fs.FsPathSetTests with ForwardSlashRamFixture 21 | -------------------------------------------------------------------------------- /file/src/test/scala/scalaio/test/fs/ram/RamFixture.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalaio.test.fs.ram 10 | 11 | import util.Random 12 | 13 | import scalax.file.ramfs.RamFileSystem 14 | import scalaio.test.fs.{ 15 | FileSystemFixture, Fixture 16 | } 17 | 18 | trait BasicRamFixture extends Fixture{ 19 | val rnd = new Random() 20 | 21 | val sep:String 22 | def createFixture() = new FileSystemFixture(new RamFileSystem(separator=sep), rnd) { 23 | override val root = fs.roots.head 24 | } 25 | } 26 | 27 | trait ForwardSlashRamFixture extends BasicRamFixture { 28 | val sep = "/" 29 | } 30 | 31 | trait BackSlashRamFixture extends BasicRamFixture { 32 | val sep = "\\" 33 | } 34 | -------------------------------------------------------------------------------- /file/src/test/scala/scalax/test/sugar/FSAssertionSugar.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2010, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scalax.test.sugar 10 | import scala.reflect.{ 11 | Manifest, ClassManifest 12 | } 13 | import org.junit.Assert._ 14 | import scalax.file.Path 15 | import scalaio.test.Node 16 | 17 | trait FSAssertionSugar extends AssertionSugar{ 18 | 19 | def assertSameStructure(path : Iterable[Path], tree : Seq[Node], maxDepth : Int = Int.MaxValue) 20 | (implicit filter : Node => Boolean = _ => true) { 21 | val pathList = path.toList 22 | val sep = path.headOption.map { _.separator} getOrElse Node.Sep 23 | val pathsAsString = pathList map {_.path} mkString "\n" 24 | var count = 0 25 | 26 | def contains(desiredPathName:String) = { 27 | pathList exists {p => 28 | desiredPathName == p.path 29 | } 30 | } 31 | def walk(tree:Seq[Node], depth : Int) : Unit = { 32 | if(depth <= maxDepth ) { 33 | tree.filter(filter) foreach { n => 34 | count += 1 35 | val nodePath = n.path replace (Node.Sep, sep) replace (sep+sep,sep) 36 | assertTrue("expected "+nodePath+" to be in "+pathsAsString, contains(nodePath)) 37 | } 38 | tree foreach {n=>walk(n.children, depth+1)} 39 | } 40 | } 41 | 42 | walk(tree,1) 43 | 44 | assertEquals(count, path.size) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /notes/0.1.1.markdown: -------------------------------------------------------------------------------- 1 | Two critical bugs with 0.1.0 so I have made a quick patch release to fix the issue. 2 | 3 | Specifically the bugs are: 4 | 5 | * [Input.byteArray iterates through stream twice](https://github.com/jesseeichar/scala-io/issues/closed#issue/3) 6 | * [Resource.fromFileString("...").byteArray goes into an infinite loop](https://github.com/jesseeichar/scala-io/issues/closed#issue/5) 7 | 8 | Both are now fixed with the 0.1.1 release. 9 | 10 | In addition the following issue was addressed: 11 | 12 | * [Add more asFoo converters for converting objects to Input/Output/etc... objects](https://github.com/jesseeichar/scala-io/issues/closed#issue/2) 13 | 14 | The files are on scala-tools.org. To get running with Scala IO take a look at http://jesseeichar.github.com/scala-io/getting-started.html -------------------------------------------------------------------------------- /notes/0.3.0.markdown: -------------------------------------------------------------------------------- 1 | The main issues addressed in this release were bug fixes and performance related to PathFinder/PathSets and more performance improvements related to reading data from streams. 2 | 3 | The extended release notes are available at: [http://jesseeichar.github.com/scala-io-doc/0.3.0/index.html#!/releaseNotes/index](http://jesseeichar.github.com/scala-io-doc/0.3.0/index.html#!/releaseNotes/index) 4 | -------------------------------------------------------------------------------- /notes/0.4.0.markdown: -------------------------------------------------------------------------------- 1 | I am happy to announce the release of Scala-IO version 0.4.0. It is a fairly major release that introduces a "Processing API" for declarative IO processing and some asynchronous capabilities. 2 | 3 | The extended release notes are available at: [http://jesseeichar.github.com/scala-io-doc/0.4.0/index.html#!/releaseNotes/index](http://jesseeichar.github.com/scala-io-doc/0.4.0/index.html#!/releaseNotes/index) 4 | 5 | 6 | I am happy to announce the release of Scala-IO version 0.4.0. It is a fairly major release that introduces a "Processing API" for declarative IO processing and some asynchronous capabilities. 7 | -------------------------------------------------------------------------------- /notes/about.markdown: -------------------------------------------------------------------------------- 1 | The Scala IO umbrella project consists of a few sub projects for different aspects and extensions of IO. There are two main components of Scala IO: 2 | 3 | * Core - Core primarily deals with Reading and writing data to and from arbitrary sources and sinks. The corner stone traits are Input, Output and Seekable which provide the core API. Other classes of importance are Resource, ReadChars and WriteChars. 4 | * File - File is a File (called Path) API that is based on a combination of Java 7 NIO filesystem and SBT PathFinder APIs. Path and FileSystem are the main entry points into the Scala IO File API. 5 | 6 | The full documentation of Scala IO is available at: [http://jesseeichar.github.com/scala-io-doc/latest.html](http://jesseeichar.github.com/scala-io-doc/latest.html) 7 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/Buffers.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2009-2011, Jesse Eichar ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | package scalax.io 9 | import java.io.InputStream 10 | import java.nio.channels.ReadableByteChannel 11 | import java.nio.ByteBuffer 12 | import java.io.Closeable 13 | 14 | object Buffers { 15 | final val BufferSize = 4 * 1024 16 | final val CharBufferSize = 1024 17 | 18 | def arrayBuffer(size: Option[Long]) = { 19 | size match { 20 | case Some(size) => new Array[Byte](bufferSize(size, 0)) 21 | case _ => new Array[Byte](BufferSize) 22 | } 23 | } 24 | def nioByteBuffer(size: Option[Long]) = { 25 | size match { 26 | case Some(size) => ByteBuffer.allocate(bufferSize(size, 0)) 27 | case _ => ByteBuffer.allocate(BufferSize) 28 | } 29 | 30 | } 31 | def nioDirectBuffer(size: Option[Long]) = { 32 | size match { 33 | case Some(size) => ByteBuffer.allocateDirect(bufferSize(size, 0)) 34 | case _ => ByteBuffer.allocateDirect(BufferSize) 35 | } 36 | } 37 | def byteBuffer(c: ReadableByteChannel): ByteBuffer = c match { 38 | case s: SeekableByteChannel => 39 | byteBuffer(s.size) 40 | case _ => ByteBuffer.allocate(BufferSize) 41 | } 42 | def byteBuffer(size: Long, min: Int = 0): ByteBuffer = { 43 | ByteBuffer.allocate(bufferSize(size, min)) 44 | } 45 | def readerBuffer = new Array[Char](CharBufferSize) 46 | def bufferSize(size: Long, min: Int) = { 47 | if (size < BufferSize && size > min) size.toInt 48 | else BufferSize 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/CountFunction.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | 3 | class CountFunction[@specialized(Char,Byte) A] extends Function[A,Unit] { 4 | private[this] var i = 0 5 | override def apply(b: A) { i += 1 } 6 | } 7 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/Main.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | 3 | import java.io.File 4 | 5 | import sperformance.store.XmlLoadResults 6 | import sperformance.store.XmlStoreResults 7 | import sperformance.PerformanceTest 8 | 9 | /** 10 | * This class is meant to be the final runner of the SPerformance test framework. 11 | */ 12 | object Main { 13 | var outputDirectory = if(new File("perf").exists) new File("perf","results") 14 | else new File("results") 15 | outputDirectory.mkdirs() 16 | 17 | def runTestsReflectively(tests: Class[_ <: PerformanceTest]*) { 18 | //TODO - ClassLoader magic.... 19 | runTests(tests.map(t => () => t.newInstance): _*) 20 | } 21 | 22 | def runTests(tests: (() => PerformanceTest)*) { 23 | for (testFactory <- tests) { 24 | val test = testFactory() 25 | println("Starting "+test.name) 26 | val context = new sperformance.HistoricalRunContext(outputDirectory, new XmlStoreResults(_), new XmlLoadResults(_)) 27 | test.runTest(context) 28 | 29 | if (!"true".equalsIgnoreCase(System.getProperty("sperf.no.graphs"))) { 30 | context.generateResultsPage(test.name) 31 | } 32 | } 33 | } 34 | 35 | def main(args: Array[String]) { 36 | runTestsReflectively(args.map(arg => Class.forName(arg).asInstanceOf[Class[_ <: PerformanceTest]]): _*) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/NullOutputStream.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | import java.io.OutputStream 3 | 4 | object NullOutputStream extends OutputStream { 5 | override def close:Unit = () 6 | override def flush:Unit = () 7 | override def write(b:Array[Byte]) = () 8 | override def write(b:Array[Byte],off:Int, len:Int) = () 9 | override def write(b:Int) = () 10 | } 11 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/SmallDataSet.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | 3 | trait SmallDataSet { 4 | val MaxSize = 150000 5 | val Inc = 50000 6 | val From = 50000 7 | } 8 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/SmallMediumDataSet.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | 3 | trait SmallMediumDataSet { 4 | val MaxSize = 1000000 5 | val Inc = 500000 6 | val From = 250000 7 | 8 | } 9 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/Utils.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | import scalax.io.Line.Terminators.NewLine 3 | import util.Random._ 4 | object Utils { 5 | def generateTestData(size: Int, lines: Int = 2, term: String = NewLine.sep) = { 6 | val data = new StringBuilder() 7 | 1 to lines foreach { _ => 8 | 1 to size foreach { _ => data.append(util.Random.alphanumeric.head) } 9 | } 10 | data.toString 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/channel/FileBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package channel 3 | 4 | import java.io.File 5 | import java.io.FileInputStream 6 | import java.io.FileOutputStream 7 | 8 | import org.apache.commons.io.FileUtils 9 | import _root_.scalax.io.Line.Terminators.NewLine 10 | import Utils._ 11 | 12 | trait FileBase { 13 | def newIn(size: Int, lines: Int = 2, term: String = NewLine.sep) = { 14 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 15 | val data = generateTestData(size, lines, term) 16 | FileUtils.writeStringToFile(file, data, "UTF-8") 17 | () => new FileInputStream(file).getChannel() 18 | } 19 | def newOut = { 20 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 21 | () => new FileOutputStream(file).getChannel() 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/channel/MemoryBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package channel 3 | 4 | import java.io.ByteArrayInputStream 5 | import java.io.ByteArrayOutputStream 6 | import java.nio.channels.Channels 7 | import _root_.scalax.io.Line.Terminators.NewLine 8 | 9 | import Utils._ 10 | 11 | trait MemoryBase { 12 | def newIn(size: Int, lines: Int = 2, term: String = NewLine.sep) = { 13 | val data = generateTestData(size, lines, term) 14 | () => Channels.newChannel(new ByteArrayInputStream(data.getBytes)) 15 | } 16 | def newOut = { 17 | () => Channels.newChannel(new ByteArrayOutputStream()) 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/channel/SeekableBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package channel 3 | 4 | import _root_.scalax.io.perf.AbstractReadableByteChannelInputTest 5 | import java.io.FileInputStream 6 | import java.io.FileOutputStream 7 | import java.io.File 8 | import _root_.scalax.io.perf.AbstractWritableByteChannelOutputTest 9 | import org.apache.commons.io.FileUtils 10 | import _root_.scalax.io.Line.Terminators.NewLine 11 | import Utils._ 12 | import _root_.scalax.io.Input 13 | import _root_.scalax.io.Resource 14 | import _root_.scalax.io.nio.SeekableFileChannel 15 | 16 | trait SeekableBase { 17 | 18 | def newIn(size: Int, lines: Int = 2, term: String = NewLine.sep) = { 19 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 20 | val data = generateTestData(size, lines, term) 21 | FileUtils.writeStringToFile(file, data, "UTF-8") 22 | () => new SeekableFileChannel(new FileInputStream(file).getChannel()) 23 | } 24 | 25 | def newOut = { 26 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 27 | () => new SeekableFileChannel(new FileOutputStream(file).getChannel()) 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/file/CopyFiles.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package file 3 | 4 | import scalax.io._ 5 | import sperformance.Keys.WarmupRuns 6 | import sperformance.dsl._ 7 | import util.Random._ 8 | import Resource._ 9 | import Line.Terminators._ 10 | import java.io.{ ByteArrayOutputStream, ByteArrayInputStream } 11 | import org.apache.commons.io.FileUtils 12 | import org.apache.commons.io.IOUtils 13 | import scalax.test.sugar._ 14 | import sperformance.Keys 15 | import scalax.file.Path 16 | import scalaio.test.fs.defaultfs.DefaultFixture 17 | 18 | class CopyFilesPerformanceTest extends PerformanceDSLTest with DefaultFixture{ 19 | val NumFiles = 40 20 | val root = Path.roots.head 21 | before() // setup fixture 22 | println("CopyFilesPerformanceTest: setting up test") 23 | val fromPath = fixture.tree(NumFiles,5)._1 24 | val text = util.Random.nextString(50) 25 | fromPath.***.filter (_.isFile).foreach(f => f.write(text)) 26 | val copyPath = fixture.path(1) 27 | fromPath.copyTo(copyPath, replaceExisting=true) 28 | val toPath = fixture.path(1).createDirectory() 29 | println("CopyFilesPerformanceTest: done setup") 30 | 31 | def copyLibrary() { 32 | def copyFile(from: Path) { 33 | val toCopy = copyPath \ from.relativize(fromPath) 34 | val toMake = toPath \ from.relativize(fromPath) 35 | toMake.deleteIfExists(force = true) 36 | toMake.createFile() 37 | toCopy.copyDataTo(output = toMake) 38 | } 39 | 40 | fromPath.descendants().collect { 41 | case item if item.isFile => copyFile(item) 42 | } 43 | } 44 | 45 | performance of "Path" in { 46 | having attribute (Keys.WarmupRuns -> 10) in { 47 | measure method "**" in { 48 | withSize from (NumFiles) upTo NumFiles withSetup { i => 49 | () 50 | } run { max => 51 | val i = System.currentTimeMillis() 52 | copyLibrary() 53 | println(System.currentTimeMillis - i) 54 | } 55 | } 56 | } 57 | } 58 | 59 | override def tearDown = { 60 | println("CopyFilesPerformanceTest: tearingDown created files") 61 | fixture.after() 62 | } 63 | 64 | } 65 | 66 | object CopyFilesPerformanceTest { 67 | def main(args: Array[String]) { 68 | Main.runTests(() => new CopyFilesPerformanceTest) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/file/HardDriveScan.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package file 3 | 4 | import scalax.io._ 5 | import sperformance.Keys.WarmupRuns 6 | import sperformance.dsl._ 7 | import util.Random._ 8 | import Resource._ 9 | import Line.Terminators._ 10 | import java.io.{ ByteArrayOutputStream, ByteArrayInputStream } 11 | import org.apache.commons.io.FileUtils 12 | import org.apache.commons.io.IOUtils 13 | import java.io.BufferedInputStream 14 | import java.io.BufferedOutputStream 15 | import java.io.InputStreamReader 16 | import java.nio.charset.Charset 17 | import java.io.File 18 | import java.io.FileInputStream 19 | import scalax.test.sugar._ 20 | import sperformance.Keys 21 | import scalax.file.Path 22 | 23 | class HardDriveScan extends PerformanceDSLTest { 24 | val root = Path.roots.head 25 | 26 | performance of "Path" in { 27 | having attribute (Keys.WarmupRuns -> 10) in { 28 | measure method "**" in { 29 | withSize from (1000) upTo 10000 by 5000 withSetup { i => 30 | i 31 | } run { max => 32 | val iter = (root ** "*.*").iterator 33 | var i = 0 34 | while (i < max && iter.hasNext) { 35 | iter.next 36 | i += 1 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | } 44 | 45 | object HardDriveScan { 46 | def main(args: Array[String]) { 47 | Main.runTests(() => new HardDriveScan) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/reader/FileBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package reader 3 | 4 | import java.io.File 5 | import java.io.FileReader 6 | import java.io.FileWriter 7 | 8 | import org.apache.commons.io.FileUtils 9 | 10 | import Utils._ 11 | import scalax.io.Line.Terminators.NewLine 12 | 13 | trait FileBase { 14 | def newIn(size: Int, lines: Int = 2, term: String = NewLine.sep) = { 15 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 16 | val data = generateTestData(size, lines, term) 17 | FileUtils.writeStringToFile(file, data, "UTF-8") 18 | () => new FileReader(file) 19 | } 20 | def newOut = { 21 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 22 | () => new FileWriter(file) 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/reader/Input.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package reader 3 | 4 | import Utils._ 5 | import scalax.io._ 6 | import sperformance.Keys.WarmupRuns 7 | import sperformance.dsl._ 8 | import util.Random._ 9 | import Resource._ 10 | import Line.Terminators._ 11 | import java.io.{ ByteArrayOutputStream, ByteArrayInputStream } 12 | import org.apache.commons.io.FileUtils 13 | import org.apache.commons.io.IOUtils 14 | import java.io.BufferedInputStream 15 | import java.io.BufferedOutputStream 16 | import java.io.InputStreamReader 17 | import java.nio.charset.Charset 18 | import java.io.File 19 | import java.io.FileInputStream 20 | import java.io.FileOutputStream 21 | 22 | // ---------------------------------------------------------------- 23 | 24 | class SmallMediumSetsFromFileReadCharsTest 25 | extends AbstractReadCharsTest 26 | with FileBase with SmallMediumDataSet 27 | 28 | object SmallMediumSetsFromFileReadCharsRunner { 29 | def main(args: Array[String]) { 30 | Main.runTests(() => new SmallMediumSetsFromFileReadCharsTest) 31 | } 32 | } 33 | 34 | // ---------------------------------------------------------------- 35 | 36 | class SmallMediumSetsFromMemoryReadCharsTest 37 | extends AbstractReadCharsTest 38 | with MemoryBase with SmallMediumDataSet 39 | 40 | object SmallMediumSetsFromMemoryReadCharsRunner { 41 | def main(args: Array[String]) { 42 | Main.runTests(() => new SmallMediumSetsFromMemoryReadCharsTest) 43 | } 44 | } 45 | 46 | // ---------------------------------------------------------------- 47 | 48 | class SmallSetsFromFileReadCharsTest 49 | extends AbstractReadCharsTest 50 | with FileBase with SmallDataSet 51 | 52 | object SmallSetsFromFileReadCharsRunner { 53 | def main(args: Array[String]) { 54 | Main.runTests(() => new SmallSetsFromFileReadCharsTest) 55 | } 56 | } 57 | 58 | // ---------------------------------------------------------------- 59 | 60 | class SmallSetsInMemoryReadCharsTest 61 | extends AbstractReadCharsTest 62 | with MemoryBase with SmallDataSet 63 | 64 | object SmallSetsInMemoryReadCharsTest { 65 | def main(args: Array[String]) { 66 | Main.runTests(() => new SmallSetsInMemoryReadCharsTest) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/reader/MemoryBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package reader 3 | 4 | import scalax.io.perf.AbstractReadableByteChannelInputTest 5 | import java.io.FileInputStream 6 | import java.io.FileOutputStream 7 | import java.io.File 8 | import scalax.io.perf.AbstractWritableByteChannelOutputTest 9 | import org.apache.commons.io.FileUtils 10 | import scalax.io.Line.Terminators.NewLine 11 | import Utils._ 12 | import java.nio.channels.Channels 13 | import java.io.ByteArrayInputStream 14 | import java.io.ByteArrayOutputStream 15 | import java.io.InputStreamReader 16 | import java.io.OutputStreamWriter 17 | 18 | trait MemoryBase{ 19 | def newIn(size: Int, lines: Int = 2, term: String = NewLine.sep) = { 20 | val data = generateTestData(size, lines, term) 21 | () => new InputStreamReader(new ByteArrayInputStream(data.getBytes), "UTF-8") 22 | } 23 | def newOut = { 24 | () => new OutputStreamWriter(new ByteArrayOutputStream()) 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/seekable/AbstractArrayBufferSeekableTest.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package seekable 3 | 4 | import scala.collection.mutable.ArrayBuffer 5 | import scalax.io._ 6 | import Resource._ 7 | import StandardOpenOption._ 8 | import Line.Terminators._ 9 | import scalax.io.ArrayBufferSeekableChannel 10 | import scalax.io.OpenOption 11 | import scalax.io.SeekableByteChannel 12 | import Utils._ 13 | abstract class AbstractArrayBufferSeekableTest extends AbstractSeekableTest { 14 | type Source = ArrayBuffer[Byte] 15 | def setup(size:Int, 16 | lines: Int = 2, 17 | term: String = NewLine.sep):Source = { 18 | ArrayBuffer(generateTestData(size, lines, term).getBytes(Codec.UTF8.name):_*) 19 | } 20 | 21 | /** 22 | * Return a Function that will create an input stream for testing 23 | * The function should not take very much time since it will be called during the test 24 | * and if it does it could interfere with what the test measures. 25 | * 26 | * For example newIn could create a file and the function would simply open a stream to the file 27 | */ 28 | def newIn(source:Source, 29 | openOptions: Seq[OpenOption] = ReadWrite):() => SeekableByteChannel = () => { 30 | new ArrayBufferSeekableChannel(source,openOptions:_*)(_=>(),_=>()):SeekableByteChannel 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/seekable/PerformanceSuite.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package seekable 3 | 4 | /** 5 | * Run all performance tests 6 | */ 7 | object SeekablePerformanceSuite { 8 | 9 | def main(args: Array[String]): Unit = { 10 | Main.runTests( 11 | () => new SmallMediumSetFileSeekable, 12 | () => new SmallSetFileSeekable, 13 | () => new SmallMediumSetMemorySeekable, 14 | () => new SmallSetMemorySeekable 15 | ) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/seekable/SmallMediumSetFileSeekable.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package perf 3 | package seekable 4 | 5 | class SmallMediumSetFileSeekable extends AbstractFileSeekableTest { 6 | val MaxSize = 15000 7 | val Inc = 5000 8 | val From = 5000 9 | val WarmUpRuns = 100 10 | 11 | } 12 | 13 | object SmallMediumSetFileSeekable { 14 | def main(args: Array[String]) { 15 | Main.runTests(() => new SmallMediumSetFileSeekable) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/seekable/SmallMediumSetMemorySeekable.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package perf 3 | package seekable 4 | 5 | class SmallMediumSetMemorySeekable extends AbstractArrayBufferSeekableTest { 6 | val MaxSize = 15000 7 | val Inc = 5000 8 | val From = 5000 9 | val WarmUpRuns = 100 10 | 11 | } 12 | 13 | object SmallMediumSetMemorySeekable { 14 | def main(args: Array[String]) { 15 | Main.runTests(() => new SmallMediumSetMemorySeekable) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/seekable/SmallSetFileSeekable.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package perf 3 | package seekable 4 | 5 | 6 | class SmallSetFileSeekable extends AbstractFileSeekableTest { 7 | val MaxSize = 50 8 | val Inc = 25 9 | val From = 1 10 | val WarmUpRuns = 100 11 | 12 | } 13 | 14 | object SmallSetFileSeekable { 15 | def main(args: Array[String]) { 16 | Main.runTests(() => new SmallSetFileSeekable) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/seekable/SmallSetMemorySeekable.scala: -------------------------------------------------------------------------------- 1 | package scalax.io 2 | package perf 3 | package seekable 4 | 5 | class SmallSetMemorySeekable extends AbstractArrayBufferSeekableTest { 6 | val MaxSize = 50 7 | val Inc = 25 8 | val From = 1 9 | val WarmUpRuns = 1000 10 | 11 | } 12 | 13 | object SmallSetMemorySeekable { 14 | def main(args: Array[String]) { 15 | Main.runTests(() => new SmallSetMemorySeekable) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/stream/FileBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | 3 | import java.io.FileInputStream 4 | import java.io.FileOutputStream 5 | import java.io.File 6 | import org.apache.commons.io.FileUtils 7 | import scalax.io.Line.Terminators.NewLine 8 | import scalax.io.perf.Utils._ 9 | 10 | trait FileBase{ 11 | def newIn(size: Int, lines: Int = 2, term: String = NewLine.sep) = { 12 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 13 | val data = generateTestData(size, lines, term) 14 | FileUtils.writeStringToFile(file, data, "UTF-8") 15 | () => new FileInputStream(file) 16 | } 17 | def newOut = { 18 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 19 | () => new FileOutputStream(file) 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/stream/MemoryBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf.stream 2 | 3 | import java.io.FileInputStream 4 | import java.io.FileOutputStream 5 | import java.io.File 6 | import org.apache.commons.io.FileUtils 7 | import scalax.io.Line.Terminators.NewLine 8 | import scalax.io.perf.Utils._ 9 | import java.nio.channels.Channels 10 | import java.io.ByteArrayInputStream 11 | import java.io.ByteArrayOutputStream 12 | 13 | trait MemoryBase { 14 | def newIn(size: Int, lines: Int = 2, term: String = NewLine.sep) = { 15 | val data = generateTestData(size, lines, term) 16 | () => new ByteArrayInputStream(data.getBytes) 17 | } 18 | def newOut = { 19 | () => new ByteArrayOutputStream() 20 | } 21 | 22 | 23 | } 24 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/stream/input/Input.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package stream 3 | package input 4 | 5 | import Utils._ 6 | import scalax.io._ 7 | import sperformance.Keys.WarmupRuns 8 | import sperformance.dsl._ 9 | import util.Random._ 10 | import Resource._ 11 | import Line.Terminators._ 12 | import java.io.{ ByteArrayOutputStream, ByteArrayInputStream } 13 | import org.apache.commons.io.FileUtils 14 | import org.apache.commons.io.IOUtils 15 | import java.io.BufferedInputStream 16 | import java.io.BufferedOutputStream 17 | import java.io.InputStreamReader 18 | import java.nio.charset.Charset 19 | import java.io.File 20 | import java.io.FileInputStream 21 | import java.io.FileOutputStream 22 | 23 | // ---------------------------------------------------------------- 24 | 25 | class SmallMediumSetsFromFileInputStreamTest 26 | extends AbstractInputTest 27 | with FileBase with SmallMediumDataSet 28 | 29 | object SmallMediumSetsFromFileInputStreamRunner { 30 | def main(args: Array[String]) { 31 | Main.runTests(() => new SmallMediumSetsFromFileInputStreamTest) 32 | } 33 | } 34 | 35 | // ---------------------------------------------------------------- 36 | 37 | class SmallMediumSetsFromMemoryInputStreamTest 38 | extends AbstractInputTest 39 | with MemoryBase with SmallMediumDataSet 40 | 41 | object SmallMediumSetsFromMemoryInputStreamRunner { 42 | def main(args: Array[String]) { 43 | Main.runTests(() => new SmallMediumSetsFromMemoryInputStreamTest) 44 | } 45 | } 46 | 47 | // ---------------------------------------------------------------- 48 | 49 | class SmallSetsFromFileInputStreamTest 50 | extends AbstractInputTest 51 | with FileBase with SmallDataSet 52 | 53 | object SmallSetsFromFileInputStreamRunner { 54 | def main(args: Array[String]) { 55 | Main.runTests(() => new SmallSetsFromFileInputStreamTest) 56 | } 57 | } 58 | 59 | // ---------------------------------------------------------------- 60 | 61 | class SmallSetsInMemoryInputStreamTest 62 | extends AbstractInputTest 63 | with MemoryBase with SmallDataSet 64 | 65 | object SmallSetsInMemoryInputStreamTest { 66 | def main(args: Array[String]) { 67 | Main.runTests(() => new SmallSetsInMemoryInputStreamTest) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/stream/output/Output.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package stream 3 | package output 4 | 5 | import Utils._ 6 | import scalax.io._ 7 | import sperformance.Keys.WarmupRuns 8 | import sperformance.dsl._ 9 | import util.Random._ 10 | import Resource._ 11 | import Line.Terminators._ 12 | import java.io.{ ByteArrayOutputStream, ByteArrayInputStream } 13 | import org.apache.commons.io.FileUtils 14 | import org.apache.commons.io.IOUtils 15 | import java.io.BufferedInputStream 16 | import java.io.BufferedOutputStream 17 | import java.io.InputStreamReader 18 | import java.nio.charset.Charset 19 | import java.io.File 20 | import java.io.FileInputStream 21 | import java.nio.channels.Channels 22 | 23 | class SmallMediumSetsInMemoryOutputStreamTest 24 | extends AbstractOutputTest 25 | with MemoryBase with SmallMediumDataSet 26 | 27 | object SmallMediumSetsInMemoryOutputStreamRunner { 28 | def main(args: Array[String]) { 29 | Main.runTests(() => new SmallMediumSetsInMemoryOutputStreamTest) 30 | } 31 | } 32 | 33 | // ---------------------------------------------------------------- 34 | 35 | class SmallMediumSetsToFileOutputStreamTest 36 | extends AbstractOutputTest 37 | with FileBase with SmallMediumDataSet 38 | 39 | object SmallMediumSetsToFileOutputStreamRunner { 40 | def main(args: Array[String]) { 41 | Main.runTests(() => new SmallMediumSetsToFileOutputStreamTest) 42 | } 43 | } 44 | 45 | // ---------------------------------------------------------------- 46 | 47 | class SmallSetsInMemoryOutputStreamTest 48 | extends AbstractOutputTest 49 | with MemoryBase with SmallDataSet 50 | 51 | object SmallSetsInMemoryOutputStreamTest { 52 | def main(args: Array[String]) { 53 | Main.runTests(() => new SmallSetsInMemoryOutputStreamTest) 54 | } 55 | } 56 | 57 | // ---------------------------------------------------------------- 58 | 59 | class SmallSetsToFileOutputStreamTest 60 | extends AbstractOutputTest 61 | with FileBase with SmallDataSet 62 | 63 | object SmallSetsToFileOutputStreamTest { 64 | def main(args: Array[String]) { 65 | Main.runTests(() => new SmallSetsToFileOutputStreamTest) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/writer/FileBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package writer 3 | 4 | import java.io.File 5 | import java.io.FileReader 6 | import java.io.FileWriter 7 | 8 | import org.apache.commons.io.FileUtils 9 | 10 | import Utils._ 11 | import scalax.io.Line.Terminators.NewLine 12 | 13 | trait FileBase { 14 | def newOut = { 15 | val file = File.createTempFile(getClass().getSimpleName(), "txt") 16 | () => new FileWriter(file) 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/writer/MemoryBase.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package writer 3 | 4 | import scalax.io.perf.AbstractReadableByteChannelInputTest 5 | import java.io.FileInputStream 6 | import java.io.FileOutputStream 7 | import java.io.File 8 | import scalax.io.perf.AbstractWritableByteChannelOutputTest 9 | import org.apache.commons.io.FileUtils 10 | import scalax.io.Line.Terminators.NewLine 11 | import Utils._ 12 | import java.nio.channels.Channels 13 | import java.io.ByteArrayInputStream 14 | import java.io.ByteArrayOutputStream 15 | import java.io.InputStreamReader 16 | import java.io.OutputStreamWriter 17 | 18 | trait MemoryBase{ 19 | def newOut = { 20 | () => new OutputStreamWriter(new ByteArrayOutputStream()) 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /perf/src/main/scala/scalax/io/perf/writer/Output.scala: -------------------------------------------------------------------------------- 1 | package scalax.io.perf 2 | package writer 3 | 4 | import Utils._ 5 | import scalax.io._ 6 | import sperformance.Keys.WarmupRuns 7 | import sperformance.dsl._ 8 | import util.Random._ 9 | import Resource._ 10 | import Line.Terminators._ 11 | import java.io.{ ByteArrayOutputStream, ByteArrayInputStream } 12 | import org.apache.commons.io.FileUtils 13 | import org.apache.commons.io.IOUtils 14 | import java.io.BufferedInputStream 15 | import java.io.BufferedOutputStream 16 | import java.io.InputStreamReader 17 | import java.nio.charset.Charset 18 | import java.io.File 19 | import java.io.FileInputStream 20 | import java.nio.channels.Channels 21 | 22 | class SmallMediumSetsInMemoryWriteCharsTest 23 | extends AbstractWriteCharsTest 24 | with MemoryBase with SmallMediumDataSet 25 | 26 | object SmallMediumSetsInMemoryWriteCharsRunner { 27 | def main(args: Array[String]) { 28 | Main.runTests(() => new SmallMediumSetsInMemoryWriteCharsTest) 29 | } 30 | } 31 | 32 | // ---------------------------------------------------------------- 33 | 34 | class SmallMediumSetsToFileWriteCharsTest 35 | extends AbstractWriteCharsTest 36 | with FileBase with SmallMediumDataSet 37 | 38 | object SmallMediumSetsToFileWriteCharsRunner { 39 | def main(args: Array[String]) { 40 | Main.runTests(() => new SmallMediumSetsToFileWriteCharsTest) 41 | } 42 | } 43 | 44 | // ---------------------------------------------------------------- 45 | 46 | class SmallSetsInMemoryWriteCharsTest 47 | extends AbstractWriteCharsTest 48 | with MemoryBase with SmallDataSet 49 | 50 | object SmallSetsInMemoryWriteCharsTest { 51 | def main(args: Array[String]) { 52 | Main.runTests(() => new SmallSetsInMemoryWriteCharsTest) 53 | } 54 | } 55 | 56 | // ---------------------------------------------------------------- 57 | 58 | class SmallSetsToFileWriteCharsTest 59 | extends AbstractWriteCharsTest 60 | with FileBase with SmallDataSet 61 | 62 | object SmallSetsToFileWriteCharsTest { 63 | def main(args: Array[String]) { 64 | Main.runTests(() => new SmallSetsToFileWriteCharsTest) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /project/ExampleProjects.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | 3 | object ExampleProjects { 4 | def prepare(exampleDir:File, outputDir:File) = { 5 | val files = exampleDir.listFiles.filterNot(_.isHidden).map{dir => 6 | IO.withTemporaryDirectory {tmpDir => 7 | val files = dir.***.get.filterNot(_ == dir) 8 | val mappings = files.filter(_.isFile) x relativeTo(List(exampleDir)) 9 | mappings.foreach { case (file,relativeName) => 10 | val data = IO.read(file). 11 | replaceAll("@SCALA_VERSION@",BuildConstants.scalaVersion). 12 | replaceAll("@SCALA_BASE_VERSION@",BuildConstants.scalaVersion.take(BuildConstants.scalaVersion.lastIndexOf('.'))). 13 | replaceAll("@IO_VERSION@",BuildConstants.version) 14 | IO.write(new File(tmpDir, relativeName), data) 15 | } 16 | zip(tmpDir, new File(tmpDir,dir.getName), outputDir) 17 | } 18 | Path.richFile(dir).relativeTo(exampleDir).get.name 19 | } 20 | val data = files.mkString("[\"","\",\"","\"]") 21 | IO.write(new File(outputDir, "examples.json"), data,C.utf8) 22 | } 23 | private def zip(tmpDir:File, dir:File, outDir:File) = { 24 | // println("Zipping: "+dir+" to "+ outDir) 25 | 26 | val files = dir.***.get.filterNot(_ == dir) 27 | 28 | val mappings = files x relativeTo(List(tmpDir)) 29 | IO.zip(mappings, new File(outDir, dir.name+".zip")) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /project/Keyword.scala: -------------------------------------------------------------------------------- 1 | import sbt.IO 2 | import java.nio.charset.Charset 3 | 4 | case class Keyword( 5 | section:String, id:String, name:String, depth:Int, shortName:String, 6 | `type`:String, parent:String, shortSummary:String, keywords:Set[String]) { 7 | override lazy val toString = """{"section":"%s","id":"%s","name":"%s","depth":%s,"shortName":"%s","type":"%s","parent":"%s","shortSummary":"%s","keywords":"%s"}""".format(section,id,name,depth,shortName,`type`,parent,shortSummary,keywords.mkString(" ")) 8 | } 9 | 10 | object Keyword { 11 | val gettingStarted = Keyword("getting-started","index","Getting Started Guide",0,"Getting Started","overview", "", "", Set("start introduction intro")) 12 | val roadmap = Keyword("roadmap","index","Scala IO Development Roadmap",0,"Roadmap","overview", "", "", Set("future map roadmap")) 13 | val overview = Keyword("overview","index","Scala IO Documentation ",0,"Overview","overview", "", "", Set("overview")) 14 | val performance = Keyword("performance","index","Performance Test Reports",0,"Performance","overview", "", "", Set("performance")) 15 | val core = Keyword("core","index","Scala IO Core API",0,"Core API","overview", "", "", Set("core")) 16 | val file = Keyword("file","index","Scala IO File API",0,"File API","overview", "", "", Set("file")) 17 | val releaseNotes = Keyword("releaseNotes","index","Release Notes for "+BuildConstants.version,0,"Release Notes","overview", "", "", Set("release notes")) 18 | 19 | def split(text:String):Set[String] = { 20 | val words = text.split("""\s+""").filter(_.trim.nonEmpty).toSet 21 | words.filter(Stopwords.EN contains _) 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /project/PerformanceReport.scala: -------------------------------------------------------------------------------- 1 | import sbt.IO 2 | import java.io._ 3 | import java.nio.charset.Charset 4 | 5 | object PerformanceReport { 6 | val utf8 = Charset.forName("UTF-8") 7 | def buildSite(outDir:File, inDir:File):Seq[Keyword] = { 8 | assert(inDir.listFiles != null, inDir+" does not have any performance reports") 9 | val reportDirs = inDir.listFiles.filter(_.isDirectory) 10 | reportDirs.zipWithIndex flatMap { case (reportDir,i) => 11 | val name = { 12 | val raw = reportDir.getName.split("\\.").last 13 | if(raw endsWith "Test") { 14 | raw.dropRight(4) 15 | } else { 16 | raw 17 | } 18 | } 19 | val children = reportDir.listFiles 20 | val childNames = children.map(childName) 21 | val keyword = Keyword("performance",name,formatName(name)+" Performance Report",1,formatName(name),"performance", "performance", formatName(name)+" Performance Report", Set("performance", name.toLowerCase) ++ childNames.map(_.toLowerCase)) 22 | val childKeywords = childNames.map{n => Keyword("performance",childId(reportDir,n),n.capitalize,2,n.capitalize,"performance graph","performance", n.capitalize, Set("performance", n.toLowerCase))} 23 | 24 | IO.write(new File(outDir, name+".html"), mainReport(reportDir,name,children).toString, utf8) 25 | IO.copyDirectory(inDir, outDir) 26 | children.foreach { child => 27 | val htmlFile = new File(outDir, childId(reportDir, childName(child))+".html") 28 | IO.write(htmlFile,childReport(child).toString, utf8) 29 | } 30 | keyword +: childKeywords 31 | } 32 | 33 | } 34 | 35 | def mainReport(reportDir:File,name:String,children:Seq[File]) = { 36 | val columns = 2 37 | val namesInRows = children.sliding(columns,columns) 38 | Performance reports for module {name.capitalize} 39 |
43 |
44 | | }