Simple IO

A file and folder abstraction.

License

License

GroupId

GroupId

org.keeber
ArtifactId

ArtifactId

simple-io
Last Version

Last Version

2.1.0
Release Date

Release Date

Type

Type

jar
Description

Description

Simple IO
A file and folder abstraction.
Project URL

Project URL

https://github.com/json-k/simple-io
Source Code Management

Source Code Management

https://github.com/json-k/simple-io

Download simple-io

How to add to project

<!-- https://jarcasting.com/artifacts/org.keeber/simple-io/ -->
<dependency>
    <groupId>org.keeber</groupId>
    <artifactId>simple-io</artifactId>
    <version>2.1.0</version>
</dependency>
// https://jarcasting.com/artifacts/org.keeber/simple-io/
implementation 'org.keeber:simple-io:2.1.0'
// https://jarcasting.com/artifacts/org.keeber/simple-io/
implementation ("org.keeber:simple-io:2.1.0")
'org.keeber:simple-io:jar:2.1.0'
<dependency org="org.keeber" name="simple-io" rev="2.1.0">
  <artifact name="simple-io" type="jar" />
</dependency>
@Grapes(
@Grab(group='org.keeber', module='simple-io', version='2.1.0')
)
libraryDependencies += "org.keeber" % "simple-io" % "2.1.0"
[org.keeber/simple-io "2.1.0"]

Dependencies

compile (3)

Group / Artifact Type Version
commons-net : commons-net jar 3.3
jcifs : jcifs jar 1.3.17
com.jcraft : jsch jar 0.1.53

Project Modules

There are no modules declared in this project.

Simple IO

Simple IO is a library similar to the Apache Virtual Filesystem - wrapping different protocols in an abstraction that uses the pattern of files and folders.

It has a plugin architecture that currently supports the File, SMB, FTP and SFTP protocols.

Philosophy

I built this library on three ideas:

  1. Efficiency - if the implementation for the different protocols behaves the same way the code created is protocol independent. How many times can you write something that deletes a directory or implement a hot-folder?
  2. Simplicity - both the API and the implementation. Not every possible scenario is accounted for, because until they are needed good enough is OK.
  3. Consistency - why does a Java File created with a path containing a trailing slash not assume it is a directory when the file does not exist? Why does it return the path without the trailing slash when it does (exist)?

Maven

The project is now available in the Maven Central Repository. For your Gradle build:

	compile 'org.keeber:simple-io:2.0.0'

Quickstart

Creation

It all starts with the static resolve method. Here we create a 'plain' file (in the user home):

File file=File.resolve("~/my/path/to/file.txt");

When the file is no longer needed it should be disposed - this releases any resources used by the file. The file should not be used after it is disposed.

file.dispose();

Files can also be created from existing files (the reference to them - this is NOT akin to the touch command). This example creates a file called 'file.txt' in the provided folder:

File dir=File.resolve("/user/local/");
File file=dir.create("file.txt");

Plugins

The library includes a set of built-in plugins that can be loaded with the static addPlugin method. Files can then be created with one of the loaded protocols:

File.addPlugin(FtpPlugin.create());
File.addPlugin(SmbPlugin.create());
File ftp=File.resolve("ftp://user:pass@server/path/to/file.txt");

Note: special characters in the authorization can (should) be URL escaped (eg: p@ss becomes p%40ss).

Listing Folders

Listing files is controlled by two filter classes which are (functional) interfaces that determine which files should be listed and which directories should be followed (for easy recursion).

This example will list every text file (extension is 'txt') in every visible directory below the resolved folder:

File folder = File.resolve("ftp://username:password@server/some/folder/");
List<File> files = folder.list(new GrabFilter() {

  @Override
  public boolean shouldGrab(File f) throws IOException {
    return f.getExtension().equals("txt");
  }
}, new MoveFilter() {

  @Override
  public boolean shouldMove(File f, int depth) throws IOException {
    return false;
  }
});

Because the filters (Grab and Move) are functional interfaces this can also be written:

File folder = File.resolve("ftp://username:password@server/some/folder/");
List<File> files = folder.list((f) -> f.getExtension().equals("txt"), (f, d) -> false);

There are also some built in filters stored statically on the File.filters class and list operations can be sorted (by either providing a standard comparator or one generated by the built in factory methods):

List<File> files = folder.list(File.filters.VISIBLE_FILES, File.filters.ONLY_THIS_DIRECTORY);

Reading and Writing

Files can be read from and written to by opening them:

OutputStream os=file.open(File.WRITE);
//...do something useful
os.close();

Don't forget to close the streams, because you always should, and this may be important to the particular file implementation (like finalizing an FTP transfer).

Copying the content from one file to another can be done quite simply using the copy method from the Streams class:

File ifile = File.resolve("sftp://user:pass@server/path/to/file.txt");
File ofile = File.resolve("/user/local/file.txt");
 
Streams.copy(ifile.open(File.READ), ofile.open(File.WRITE), true);

Operations

There are some useful operations attached to each file (part of the abstract file object and not the individual implementations):

String content=file.operations.getStringContent();
 
ifile.operations.copyTo(ofile);

(Including a copy method, for when you don't need control over the resulting streams (eg: for counting)).

Utilities

In addition to the resolve method the File class also provides other static utility methods:

File desktop=File.getUserDesktop();

File temp=File.createTempFile("TempFile_", ".txt");

Versions

Version
2.1.0
2.0.0