I'm trying to experiment with apache commons vfs2 to read content of a zip file as if it is just another directory. The zip files will ultimately hold all kinds of files (perhaps even a small database).
For illustration purposes, I have created some zip files containing a file called project.json which is json for a project with a name and a description. When I get the zip file, I want to read the json file to get the project definition information, etc. from within.
This all works great. Now, I want my users to be able to delete these files from within the application. This is where things go south on me.
I think I closed all of the input streams and such, but there appears to be a lock on the file from within the application that will not allow me to delete it.
Here's a simple json string if you want to create your own zip file to try it.
{"project": {"name": "ProjectX", "description": "X is a project."}}
Copy that to a file called project.json, and save it. Then, zip it into a zip file in the root directory of the Java project.
The following example illustrates my dilemma:
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.vfs2.FileContent;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemManager;
import org.apache.commons.vfs2.VFS;
import org.json.JSONObject;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
public class FileLockExample extends Application {
@Override
public void start(Stage arg0) throws Exception {
ObservableList<File> files = retrieveFiles();
deleteFiles(files);
Platform.exit();
}
public static void main(String[] args) {
Application.launch(args);
}
public ObservableList<File> retrieveFiles() {
File[] files = new File(".").listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".zip");
}
});
for (File file : files) {
try {
FileSystemManager fsManager = VFS.getManager();
FileObject zipFile = fsManager.resolveFile("zip:" + file.toURI());
FileObject projectJson = fsManager.resolveFile(zipFile, "project.json");
FileContent content = projectJson.getContent();
InputStream in = content.getInputStream();
byte[] buffer = new byte[1024];
StringBuilder sb = new StringBuilder();
int len;
while ((len = in.read(buffer)) > 0) {
sb.append(new String(buffer, 0, len));
}
in.close();
String json = sb.toString();
JSONObject obj = new JSONObject(json);
String name = obj.getJSONObject("project").getString("name");
String description = obj.getJSONObject("project").getString("description");
System.out.println("Found project : " + name + "(" + description + ")");
content.close();
projectJson.close();
zipFile.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return FXCollections.observableArrayList(files);
}
public void deleteFiles(ObservableList<File> files) {
for (File file : files) {
System.out.println("Deleting " + file.getName());
file.deleteOnExit();
}
}
}
In light of the fact that no one seemed interested in my question, it caused me to reflect on the use of Apache Commons VFS in this case. I decided to explore other options, and was able to accomplish my short-term goal by using the java.nio API. Now, on to the longer-term goal of attempting to store other types of files in the zip file, and access them in a random fashion.
In case anyone cares, here is my sample code to read from and delete zip files from the file system without having to resort to InputStream
and OutputStream
.
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.nio.file.spi.FileSystemProvider;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONObject;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
public class FileLockExample extends Application {
@Override
public void start(Stage arg0) throws Exception {
ObservableList<File> files = retrieveFiles();
deleteFiles(files);
Platform.exit();
}
public static void main(String[] args) {
Application.launch(args);
}
public ObservableList<File> retrieveFiles() {
File[] files = new File(".").listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".zip");
}
});
for (File file : files) {
try {
Map<String, Object> env = new HashMap<>();
FileSystemProvider provider = getZipFSProvider();
URI uri = new URI("jar:" + file.toURI());
FileSystem zipfs = provider.newFileSystem(uri, env);
List<String> jsonList = Files.readAllLines(zipfs.getPath("/project.json"));
StringBuilder sb = new StringBuilder();
for (String string : jsonList) {
sb.append(string);
}
String json = sb.toString();
JSONObject obj = new JSONObject(json);
String name = obj.getJSONObject("project").getString("name");
String description = obj.getJSONObject("project").getString("description");
System.out.println("Found project : " + name + " (" + description + ")");
} catch (URISyntaxException use) {
use.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return FXCollections.observableArrayList(files);
}
public void deleteFiles(ObservableList<File> files) {
for (File file : files) {
System.out.println("Deleting " + file.getName());
file.deleteOnExit();
}
}
private static FileSystemProvider getZipFSProvider() {
for (FileSystemProvider provider : FileSystemProvider.installedProviders()) {
if ("jar".equals(provider.getScheme()))
return provider;
}
return null;
}
}