I am new to Commons VFS and am trying to understand how to open a nested archive. I found an example in the source code that deals with this. This test passes.
@Test
void testTGZ() throws Exception {
FileSystemManager fsManager = VFS.getManager();
String uri = "tgz:file:///c:/data/nested.tgz!/test.tgz";
FileObject archive = fsManager.resolveFile(uri);
FileObject nestedFs = fsManager.createFileSystem(archive);
// List the children of the archive file
FileObject[] children = nestedFs.getChildren();
for (FileObject child : children) {
System.out.println(child.getURI());
}
}
whereas this one fails with
org.apache.commons.vfs2.FileSystemException: Could not find a file provider that can handle file "tgz:file:///C:/data/nested.tar.gz!/test.tar.gz".
@Test
void testTarGZ() throws Exception {
FileSystemManager fsManager = VFS.getManager();
String uri = "tgz:file:///c:/data/nested.tar.gz!/test.tar.gz";
FileObject archive = fsManager.resolveFile(uri);
FileObject nestedFs = fsManager.createFileSystem(archive);
// List the children of the archive file
FileObject[] children = nestedFs.getChildren();
for (FileObject child : children) {
System.out.println(child.getURI());
}
}
Other than the names the files are the same so why would one work and not the other? What am I doing wrong?
I came across the same issue and after debugging I was able to find the source of the problem.
If you take a look at createFileSystem(FileObject file)
in the DefaultFileSystemManager
class, you can find that it uses the method getScheme(FileObject file)
from the FileTypeMap
class to detect the scheme:
/**
* Find the scheme for the provider of a layered file system.
* <p>
* This will check the FileContentInfo or file extension.
* </p>
*
* @return Scheme supporting the file type or null (if unknown).
*/
public String getScheme(final FileObject file) throws FileSystemException {
// Check the file's mime type for a match
final FileContent content = file.getContent();
final String mimeType = content.getContentInfo().getContentType();
if (mimeType != null) {
return mimeTypeMap.get(mimeType);
}
// no specific mime-type - if it is a file also check the extension
if (!file.isFile()) {
return null; // VFS-490 folders don't use extensions for mime-type
}
final String extension = file.getName().getExtension();
return extensionMap.get(extension);
}
When the extension is tgz
, mimeType
is evaluated to null
and the method tries to get the scheme using the extension itself. In this case, tgz
is returned from extensionMap
and DefaultFileSystemManager
uses that value to select a FileProvider
(TarFileProvider
in this case).
When the extension is tar.gz
, mimeType
is parsed as application/octet-stream
which doesn't have any mapping in mimeTypeMap
and the methods returns null
. In this case, DefaultFileSystemManager
fails to create a file system because no FileProvider
was found.
Solution:
You can specify the FileProvider
while creating the file system:
FileSystemManager manager = VFS.getManager();
// tgz file
String tgz = "file:/C:/data/nested.tgz";
FileObject tgzFileObject = manager.resolveFile(tgz);
FileObject tgzFileSystem = manager.createFileSystem("tgz", tgzFileObject);
// tar.gz file
String targz = "file:/C:/data/nested.tar.gz";
FileObject targzFileObject = manager.resolveFile(targz);
FileObject targzFileSystem = manager.createFileSystem("tgz", targzFileObject);