File Handling with HopVFS
Apache Hop uses Apache Commons VFS as its unified file system abstraction.
Whether your data resides on a local NVMe drive, in AWS S3, Google Cloud Storage, Azure Blob, an SFTP server, or inside a ZIP archive, Hop treats every path through a single, consistent API: org.apache.commons.vfs2.FileObject and the org.apache.hop.core.vfs.HopVfs helper class.
The Golden Rule: Avoid java.io.File
|
Unless there really is no other choice, never use |
Using java.io.File is one of the most common causes of bugs when running pipelines outside a local developer workstation:
-
Non-local Schemes:
java.io.Fileonly understands the local operating system’s filesystem syntax. Passing a cloud path such ass3://my-bucket/orders.csvorgs://my-bucket/orders.csvtojava.io.Filewill either throw aFileNotFoundExceptionor corrupt the path into a nonsensical local directory like./s3:/my-bucket/orders.csv. -
Portability across Runtimes: Pipelines configured on a local machine frequently execute on a remote Hop Server, in a Docker container, or on a distributed cluster with Apache Beam / Spark / Flink. Using
HopVfsensures that paths remain portable across all runtime targets. -
Variable Resolution:
HopVfsautomatically expands variables (such as${PROJECT_HOME}/data/file.csvor${S3_BUCKET}/data.parquet) before resolving the underlying file system provider.
Core File Operations with HopVfs
The HopVfs utility class provides static convenience methods for interacting with files across all supported schemes.
1. Obtaining a FileObject
import org.apache.commons.vfs2.FileObject;
import org.apache.hop.core.vfs.HopVfs;
import org.apache.hop.core.variables.IVariables;
IVariables variables = ...;
String path = "${PROJECT_HOME}/input/sales_data.csv";
// Resolves variables and obtains the Commons VFS FileObject
FileObject fileObject = HopVfs.getFileObject(path, variables);
if (fileObject.exists()) {
long sizeInBytes = fileObject.getContent().getSize();
boolean isFolder = fileObject.isFolder();
}
2. Reading Streams
Always read file contents through HopVfs.getInputStream():
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
// Open stream directly from a path:
try (InputStream inputStream = HopVfs.getInputStream("s3://analytics-bucket/logs/app.log", variables);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
// Process line
}
}
You can also retrieve an InputStream directly from an existing FileObject:
try (InputStream inputStream = HopVfs.getInputStream(fileObject)) {
// Read bytes
}
3. Writing Streams
To create or overwrite a file, obtain an OutputStream via HopVfs.getOutputStream():
import java.io.OutputStream;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
String targetPath = "azure://data-container/output/results.json";
boolean append = false;
try (OutputStream outputStream = HopVfs.getOutputStream(targetPath, append, variables);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {
writer.write("{\"status\": \"OK\"}");
writer.flush();
}
4. Directory & File Management
FileObject folder = HopVfs.getFileObject("s3://bucket/landing-zone/", variables);
// Create directory (and parents if needed)
if (!folder.exists()) {
folder.createFolder();
}
// List child files
FileObject[] children = folder.getChildren();
for (FileObject child : children) {
if (child.isFile()) {
System.out.println("Found file: " + child.getName().getBaseName());
}
}
// Delete file or folder
fileObject.delete();
// Delete folder and all recursive contents
folder.deleteAll();
Closing Resources: Preventing Descriptor and Connection Leaks
|
Always close streams and |
Best Practices for Resource Management
-
Use try-with-resources for all streams:
javatry (InputStream in = HopVfs.getInputStream(filename, variables)) { // Read stream } // Automatically closed on exit -
Close
FileObjectinstances when finished:FileObjectimplementsAutoCloseable. When performing extensive file system scans or operations, close theFileObjectto release cached metadata and network channel handles:javatry (FileObject file = HopVfs.getFileObject(remotePath, variables)) { if (file.exists()) { // perform operations } } // file.close() releases underlying VFS resources -
Use
file.close()in transformdispose()methods: If a transform opens aFileObjectininit()orprocessRow(), ensurefile.close()is called indispose().
Supported URL Schemes and Related Docs
Hop supports standard VFS schemes out of the box, with additional schemes provided via plugins:
| Scheme | Storage Provider | Plugin / Documentation |
|---|---|---|
|
Local file system |
Built into |
|
Amazon Simple Storage Service (S3) |
|
|
Google Cloud Storage (GCS) |
|
|
Microsoft Azure Blob & Data Lake |
|
|
FTP and Secure FTP (SSH) |
|
|
Git repository checked out at a branch, tag or commit |
|
|
Compressed archives |
Apache Commons VFS core |
|
Hadoop Distributed File System |
|
|
Databricks Unity Catalog Volumes |
-
For configuring VFS connections in projects, see Hop VFS in the User Manual.
-
For creating custom VFS schemes and storage providers, see VFS Plugins.