Comments (10)
Any progress on this? I would love to browse jar files this way...
from better-files.
@lu4nm3 : This month
from better-files.
from better-files.
Is anyone working on this? I can take it up if not.
from better-files.
@acrisci : Feel free to pick this up. Before you begin, can you outline your plan? Like what APIs would you like to add?
from better-files.
I am kind of new to the jvm and scala and my knowledge of what makes for a good scala library interface is lacking so I might need some help with this :)
My use case I think is a rather common one. I have an application which I package as a jar and I want to get the contents of some file in the resources directory such as a config file or something.
When I simply run sbt run
from the project root, this works fine:
val f = File(getClass.getResource("/some-file.txt").toURI)
println(f.contentAsString)
But when the application is packaged as a jar (such as with sbt assembly
), it does not work:
Exception in thread "main" java.nio.file.FileSystemNotFoundException
at com.sun.nio.zipfs.ZipFileSystemProvider.getFileSystem(ZipFileSystemProvider.java:171)
at com.sun.nio.zipfs.ZipFileSystemProvider.getPath(ZipFileSystemProvider.java:157)
at java.nio.file.Paths.get(Paths.java:143)
at better.files.File$.apply(File.scala:543)
at example.Main$.main(Main.scala:9)
at example.Main.main(Main.scala)
The URI in the first case is the path to the actual file on the disk. In the second case, it is this:
jar:file:/home/myuser/projects/example/target/scala-2.11/default-assembly-0.1-SNAPSHOT.jar!/resource.txt
This obviously doesn't exist in the file system, so I don't believe it is possible to turn it into a proper better files File
(although it would be nice if we could do that to reuse the interface).
So what I will propose first is a new class called Resource
which can be made like so:
val resource = resource"/some-file.txt"
val resource = Resource("/some-file.txt")
That will load the file from the resource path similar to what you would expect could be gotten with getClass.getResource("/some-file.txt")
.
Loading resources from other classes would also be useful, and maybe that could be accomplished with a method such as Resource("/some-file.txt", classOf[SomeClass])
or something similar.
The Resource
class would then implement as many methods from the File
class as makes sense (given that the resource may not actually be a file in the file system). Useful methods would be contentAsString()
, copyTo()
, bytes()
, lineIterator()
, and others. Obviously only a small number of methods that are available on the File
are going to make sense in this context though.
Then we can do cool stuff like this:
val myConfig = resource"/path-to-config.txt".contentAsString
// parse config somehow
instead of having to look up how to do that another way on google over and over again like i do now.
from better-files.
@acrisci: I think for all practical purposes, resources are just vanilla files that happen to live in a special place and loaded in a special way (i.e. inside the app's jar). Thus, if we classify all operations on a file into 2 camps - reads (e.g. .bytes
or .size
or .contentAsString
) vs writes (e.g. .move
, .delete
), resources are just files that only supports the operations from the read camp.
Thus we can do this then:
trait ReadOperations {
def contentAsString: String
def bytes: Iterator[Byte]
....
}
trait WriteOperations {
def delete(): Unit
def moveTo(dest: File): File
....
}
class File extends ReadOperations with WriteOperations
class Resource extends ReadOperations
The above looks elegant but I ran into problems with certain read operations (e.g. listing a directory) which is not easy for Resources and thus I shelved progress on this issue. Maybe .list()
should throw UnsupportedOperationException
for Resources? But, that is pretty evil!
Would be happy to hear your thoughts on this.
from better-files.
This blog post gives a fairly reasonable explanation on how to do that (untested). I think it would be less evil to throw a kind of NotImplementedException
in cases like that so that people might be annoyed enough to come up with an implementation. But that solution still seems a bit ugly to me.
I'm starting to think that the best solution for this would be for java NIO to implement the jar file system but I'm not sure how likely that is to happen.
Another solution might be to divide the operations based on what can be generalized to any stream, and what is specifically a file system operation.
trait StreamOperations {
def contentAsString: String
def bytes: Iterator[Byte]
....
}
trait FileSystemOperations {
def delete(): Unit
def moveTo(dest: File): File
....
}
class File extends StreamOperations with FileSystemOperations
class Resource extends StreamOperations
Then we don't have to worry about nasty implementations of file system operations which aren't even that useful for resources to begin with.
This also can be reused for other streams in the future (STDIN, STDOUT).
from better-files.
SGTM. As a first attempt, just add a new Resource.scala class. I can work on the refactor of common APIs into separate traits.
from better-files.
Is there a timeline for when this will be released?
from better-files.
Related Issues (20)
- make File serializible HOT 3
- Calling size on a broken symlink throws a NoSuchFileException,
- Switch to new codecov reporter
- Scala3 version HOT 6
- Support scala-native? HOT 2
- Use common settings style HOT 1
- Stream closed with Scala 2.12.15
- usingTemporaryDirectory should return `U` instead of `Unit` HOT 1
- is there a way to read huge gz csv file line by line of this package? HOT 1
- Make build pass on windows
- Make all side-effecty APIs use parens
- Add error handler to File.walk
- Imlement features from sbt IO
- Write self cleaning tests - no mutable vars
- Enable warnings for Scala 2.13 and above
- Generate scaladoc for all Scala versions
- Port ShapelessScannaerSpec to Scala 3
- scalaformat organize imports
- changeExtensionTo does not account for multiple dots in file name
- Directory Traversal Issue in File.unzipTo HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from better-files.