Files and Folders Manipulation
Introduction
In the polyglot backend code of the Netuno platform, we can manipulate any file or folder.
Manipulation consists of being able to create, rename, and delete files and folders, change the contents of files, and list the contents of folders. In general, these are the operations we typically need to perform programmatically.
The Netuno platform has low-code programming features that allow you to manipulate the application's internal folders and files, but also any files and folders in the system in general, that is, outside the application.
This is useful when we need to automate a process that requires manipulating any file; let's see how.
The low-code polyglot programming features that allow you to manipulate files are:
_app- Application_storage- Storage_os- Operating System
Through these resources we have the methods to:
.file- Existing file..folder- Existing folder..path- A generic path can be either a file or a folder, and it may or may not exist.
With these methods we obtain an object of type File, which provides all the means for manipulating files, folders and paths in general, allowing operations such as:
- Create files and folders.
- Delete files and folders.
- List the contents of folders.
- Rename files and folders.
- Read and write data to files.
- Delete folders and their respective subfolders and files recursively.
Application
To perform the main file and folder manipulation operations within the application structure, we use
the _app resource:
Folders in the Application
Ensures that an existing folder is retrieved, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const myFolder = _app.folder("my/folder")
myFolder = _app.folder("my/folder")
myFolder = _app.folder("my/folder")
val myFolder = _app.folder("my/folder")
final myFolder = _app.folder("my/folder")
Files in the Application
Ensures that a file that exists is retrieved, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const myFile = _app.file("my/folder/file.txt")
myFile = _app.file("my/folder/file.txt")
myFile = _app.file("my/folder/file.txt")
val myFile = _app.file("my/folder/file.txt")
final myFile = _app.file("my/folder/file.txt")
Paths in the Application
Retrieve a file or folder path, regardless of whether it exists or not, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const newFile = _app.path("my/folder/new-file.txt")
newFile = _app.path("my/folder/new-file.txt")
newFile = _app.path("my/folder/new-file.txt")
val newFile = _app.path("my/folder/new-file.txt")
final newFile = _app.path("my/folder/new-file.txt")
Storage
To perform the main file and folder manipulation operations within the application's 📁 storage folder,
we use the _storage resource:
Folders in Storage
Ensures that a folder that exists is retrieved, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
// The actual path to the folder will be:
// storage/filesystem/server/my/folder
const storageMyFolder = _storage.filesystem("server", "my/folder")
const myFolder = storageMyFolder.folder()
# The actual path to the folder will be:
# storage/filesystem/server/my/folder
storageMyFolder = _storage.filesystem("server", "my/folder")
myFolder = storageMyFolder.folder()
# The actual path to the folder will be:
# storage/filesystem/server/my/folder
storageMyFolder = _storage.filesystem("server", "my/folder")
myFolder = storageMyFolder.folder()
// The actual path to the folder will be:
// storage/filesystem/server/my/folder
val storageMyFolder = _storage.filesystem("server", "my/folder")
val myFolder = storageMyFolder.folder()
// The actual path to the folder will be:
// storage/filesystem/server/my/folder
final storageMyFolder = _storage.filesystem("server", "my/folder")
final myFolder = storageMyFolder.folder()
Files in Storage
Ensures that a file that exists is retrieved, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
// The actual file path will be:
// storage/filesystem/server/my/folder/file.txt
const storageFile = _storage.filesystem("server", "my/folder", "file.txt")
const file = storageArquivo.file()
# The actual file path will be:
# storage/filesystem/server/my/folder/file.txt
storageFile = _storage.filesystem("server", "my/folder", "file.txt")
file = storageArquivo.file()
# The actual file path will be:
# storage/filesystem/server/my/folder/file.txt
storageFile = _storage.filesystem("server", "my/folder", "file.txt")
file = storageArquivo.file()
// The actual file path will be:
// storage/filesystem/server/my/folder/file.txt
val storageFile = _storage.filesystem("server", "my/folder", "file.txt")
val file = storageArquivo.file()
// The actual file path will be:
// storage/filesystem/server/my/folder/file.txt
final storageFile = _storage.filesystem("server", "my/folder", "file.txt")
final file = storageArquivo.file()
Paths in Storage
Retrieve a file or folder path, regardless of whether it exists or not, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
// The actual new folder path will be:
// storage/filesystem/server/my/new-folder
const storageFolder = _storage.filesystem("server", "my/new-folder")
const folder = storageFolder.path()
// The actual new file path will be:
// storage/filesystem/server/my/folder/new-file.txt
const storageFile = _storage.filesystem("server", "my/folder", "new-file.txt")
const file = storageFile.path()
# The actual new folder path will be:
# storage/filesystem/server/my/new-folder
storageFolder = _storage.filesystem("server", "my/new-folder")
folder = storageFolder.path()
# The actual new file path will be:
# storage/filesystem/server/my/folder/new-file.txt
storageFile = _storage.filesystem("server", "my/folder", "new-file.txt")
file = storageFile.path()
# The actual new folder path will be:
# storage/filesystem/server/my/new-folder
storageFolder = _storage.filesystem("server", "my/new-folder")
folder = storageFolder.path()
# The actual new file path will be:
# storage/filesystem/server/my/folder/new-file.txt
storageFile = _storage.filesystem("server", "my/folder", "new-file.txt")
file = storageFile.path()
// The actual new folder path will be:
// storage/filesystem/server/my/new-folder
val storageFolder = _storage.filesystem("server", "my/new-folder")
val folder = storageFolder.path()
// The actual new file path will be:
// storage/filesystem/server/my/folder/new-file.txt
val storageFile = _storage.filesystem("server", "my/folder", "new-file.txt")
val file = storageFile.path()
// The actual new folder path will be:
// storage/filesystem/server/my/new-folder
final storageFolder = _storage.filesystem("server", "my/new-folder")
final folder = storageFolder.path()
// The actual new file path will be:
// storage/filesystem/server/my/folder/new-file.txt
final storageFile = _storage.filesystem("server", "my/folder", "new-file.txt")
final file = storageFile.path()
Operating System
To perform the main file and folder manipulation operations anywhere in the operating system, we use
the _os feature:
Folders in the Operating System
Ensures that a folder that exists is retrieved, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const myFolder = _os.folder("/tmp/my/folder")
myFolder = _os.folder("/tmp/my/folder")
myFolder = _os.folder("/tmp/my/folder")
val myFolder = _os.folder("/tmp/my/folder")
final myFolder = _os.folder("/tmp/my/folder")
Files in the Operating System
Ensures that a file that exists is retrieved, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const myFile = _os.file("/tmp/my/folder/file.txt")
myFile = _os.file("/tmp/my/folder/file.txt")
myFile = _os.file("/tmp/my/folder/file.txt")
val myFile = _os.file("/tmp/my/folder/file.txt")
final myFile = _os.file("/tmp/my/folder/file.txt")
Paths in the Operating System
Retrieve a file or folder path, regardless of whether it exists or not, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const newFile = _os.path("/tmp/my/folder/new-file.txt")
newFile = _os.path("/tmp/my/folder/new-file.txt")
newFile = _os.path("/tmp/my/folder/new-file.txt")
val newFile = _os.path("/tmp/my/folder/new-file.txt")
final newFile = _os.path("/tmp/my/folder/new-file.txt")
Create Folders
The mkdir method creates a folder.
In the following example, it creates the specific folder in the application root:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const folder = _app.path("temp")
folder.mkdir()
folder = _app.path("temp")
folder.mkdir()
folder = _app.path("temp")
folder.mkdir()
val folder = _app.path("temp")
folder.mkdir()
final folder = _app.path("temp")
folder.mkdir()
To create a subfolder within an existing folder, specify the full path, separating the folder hierarchy with /:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const subfolder = _app.path("temp/other")
subfolder.mkdir()
subfolder = _app.path("temp/other")
subfolder.mkdir()
subfolder = _app.path("temp/other")
subfolder.mkdir()
val subfolder = _app.path("temp/other")
subfolder.mkdir()
final subfolder = _app.path("temp/other")
subfolder.mkdir()
The mkdirs command creates the previous folders and/or subfolders if they don't exist, thus allowing you to
create a folder structure in the application, for example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const foldersPath = _app.path("temp/a/b/c")
foldersPath.mkdirs()
foldersPath = _app.path("temp/a/b/c")
foldersPath.mkdirs()
foldersPath = _app.path("temp/a/b/c")
foldersPath.mkdirs()
val foldersPath = _app.path("temp/a/b/c")
foldersPath.mkdirs()
final foldersPath = _app.path("temp/a/b/c")
foldersPath.mkdirs()
The _storage resource has the ensurePath method which checks
if the path exists; if it doesn't, it will be created.
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const file = _storage.filesystem(
"public",
"temp/subfolder",
"file.txt"
)
// Creates the folder structure if it doesn't already exist:
file.ensurePath()
file = _storage.filesystem(
"public",
"temp/subfolder",
"file.txt"
)
# Creates the folder structure if it doesn't already exist:
file.ensurePath()
file = _storage.filesystem(
"public",
"temp/subfolder",
"file.txt"
)
# Creates the folder structure if it doesn't already exist:
file.ensurePath()
val file = _storage.filesystem(
"public",
"temp/subfolder",
"file.txt"
)
// Creates the folder structure if it doesn't already exist:
file.ensurePath()
final file = _storage.filesystem(
"public",
"temp/subfolder",
"file.txt"
)
// Creates the folder structure if it doesn't already exist:
file.ensurePath()
Therefore, ensurePath guarantees that the folder structure exists.
Delete Files and Folders
With the delete method we can remove both folders and files, provided the folders are empty, see the example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
// Remove an empty folder:
const emptyFolder = _app.folder("folder/empty")
emptyFolder.delete()
// Remove a file:
const file = _app.file("folder/file.txt")
file.delete()
// Remove a path, empty folder, or file:
const path = _app.path("folder1/file-or-empty-folder")
path.delete()
# Remove an empty folder:
emptyFolder = _app.folder("folder/empty")
emptyFolder.delete()
# Remove a file:
file = _app.file("folder/file.txt")
file.delete()
# Remove a path, empty folder, or file:
path = _app.path("folder1/file-or-empty-folder")
path.delete()
# Remove an empty folder:
emptyFolder = _app.folder("folder/empty")
emptyFolder.delete()
# Remove a file:
file = _app.file("folder/file.txt")
file.delete()
# Remove a path, empty folder, or file:
path = _app.path("folder1/file-or-empty-folder")
path.delete()
// Remove an empty folder:
val emptyFolder = _app.folder("folder/empty")
emptyFolder.delete()
// Remove a file:
val file = _app.file("folder/file.txt")
file.delete()
// Remove a path, empty folder, or file:
val path = _app.path("folder1/file-or-empty-folder")
path.delete()
// Remove an empty folder:
final emptyFolder = _app.folder("folder/empty")
emptyFolder.delete()
// Remove a file:
final file = _app.file("folder/file.txt")
file.delete()
// Remove a path, empty folder, or file:
final path = _app.path("folder1/file-or-empty-folder")
path.delete()
Using deleteAll allows you to delete everything, that is, all files, folders, and subfolders recursively:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
// Remove the folder and all its contents recursively:
const emptyFolder = _app.folder("folder/empty")
emptyFolder.deleteAll()
// Remove the path to a folder and all its contents,
// including subfolders and files:
const path = _app.path("path/folder")
path.deleteAll()
# Remove the folder and all its contents recursively:
emptyFolder = _app.folder("folder/empty")
emptyFolder.deleteAll()
# Remove the path to a folder and all its contents,
# including subfolders and files:
path = _app.path("path/folder")
path.deleteAll()
# Remove the folder and all its contents recursively:
emptyFolder = _app.folder("folder/empty")
emptyFolder.deleteAll()
# Remove the path to a folder and all its contents,
# including subfolders and files:
path = _app.path("path/folder")
path.deleteAll()
// Remove the folder and all its contents recursively:
val emptyFolder = _app.folder("folder/empty")
emptyFolder.deleteAll()
// Remove the path to a folder and all its contents,
// including subfolders and files:
val path = _app.path("path/folder")
path.deleteAll()
// Remove the folder and all its contents recursively:
final emptyFolder = _app.folder("folder/empty")
emptyFolder.deleteAll()
// Remove the path to a folder and all its contents,
// including subfolders and files:
final path = _app.path("path/folder")
path.deleteAll()
To delete only the files within the folder and not delete anything in the subfolders, we have deleteFiles,
which allows you to specify an extension if you want to remove only files with a specific extension:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
// Remove files only within the folder:
const folder = _app.folder("folder/example")
folder.deleteFiles()
// Remove files with the JPG extension only within the folder:
const path = _app.path("path/folder")
path.deleteFiles("jpg")
# Remove files only within the folder:
folder = _app.folder("folder/example")
folder.deleteFiles()
# Remove files with the JPG extension only within the folder:
path = _app.path("path/folder")
path.deleteFiles("jpg")
# Remove files only within the folder:
folder = _app.folder("folder/example")
folder.deleteFiles()
# Remove files with the JPG extension only within the folder:
path = _app.path("path/folder")
path.deleteFiles("jpg")
// Remove files only within the folder:
val folder = _app.folder("folder/example")
folder.deleteFiles()
// Remove files with the JPG extension only within the folder:
val path = _app.path("path/folder")
path.deleteFiles("jpg")
// Remove files only within the folder:
final folder = _app.folder("folder/example")
folder.deleteFiles()
// Remove files with the JPG extension only within the folder:
final path = _app.path("path/folder")
path.deleteFiles("jpg")
To delete only files recursively and maintain the folder structure, we have deleteAllFiles, which also allows
you to specify an extension if you want to remove only a particular file type. See these two examples:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
// Remove all files within the folder and subfolders:
const folder = _app.folder("folder/example")
folder.deleteAllFiles()
// Remove all files with the JPG extension within the folder and subfolders:
const path = _app.path("path/folder")
path.deleteAllFiles("jpg")
# Remove all files within the folder and subfolders:
folder = _app.folder("folder/example")
folder.deleteAllFiles()
# Remove all files with the JPG extension within the folder and subfolders:
path = _app.path("path/folder")
path.deleteAllFiles("jpg")
# Remove all files within the folder and subfolders:
folder = _app.folder("folder/example")
folder.deleteAllFiles()
# Remove all files with the JPG extension within the folder and subfolders:
path = _app.path("path/folder")
path.deleteAllFiles("jpg")
// Remove all files within the folder and subfolders:
val folder = _app.folder("folder/example")
folder.deleteAllFiles()
// Remove all files with the JPG extension within the folder and subfolders:
val path = _app.path("path/folder")
path.deleteAllFiles("jpg")
// Remove all files within the folder and subfolders:
final folder = _app.folder("folder/example")
folder.deleteAllFiles()
// Remove all files with the JPG extension within the folder and subfolders:
final path = _app.path("path/folder")
path.deleteAllFiles("jpg")
Rename or Move
To move a folder, it's the same as renaming it:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const folder = _app.folder("temp")
folder.renameTo("test")
folder = _app.folder("temp")
folder.renameTo("test")
folder = _app.folder("temp")
folder.renameTo("test")
val folder = _app.folder("temp")
folder.renameTo("test")
final folder = _app.folder("temp")
folder.renameTo("test")
To rename a folder and change its level in the folder hierarchy, it's the same as moving the folder:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const folder = _app.folder("temp/a/b")
folder.renameTo("test/z")
folder = _app.folder("temp/a/b")
folder.renameTo("test/z")
folder = _app.folder("temp/a/b")
folder.renameTo("test/z")
val folder = _app.folder("temp/a/b")
folder.renameTo("test/z")
final folder = _app.folder("temp/a/b")
folder.renameTo("test/z")
To move a subfolder without changing its name, simply specify the new path in the renameTo method:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const folder = _app.folder("test/other")
folder.renameTo("another")
folder = _app.folder("test/other")
folder.renameTo("another")
folder = _app.folder("test/other")
folder.renameTo("another")
val folder = _app.folder("test/other")
folder.renameTo("another")
final folder = _app.folder("test/other")
folder.renameTo("another")
Saving Content to Files
Generating content into files is done using the output method, which provides an object of type OutputStream.
To write the data to the output, we use the printAndClose method, which prints the content to the file and closes the file, saving the content.
Write Text File
Here's an example of how to create a file with text content:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
_app.path("temp").mkdir()
const writer = _app.path("temp/file.txt").output()
writer.printAndClose("My text here...")
_app.path("temp").mkdir()
writer = _app.path("temp/file.txt").output()
writer.printAndClose("My text here...")
_app.path("temp").mkdir()
writer = _app.path("temp/file.txt").output()
writer.printAndClose("My text here...")
_app.path("temp").mkdir()
val writer = _app.path("temp/file.txt").output()
writer.printAndClose("My text here...")
_app.path("temp").mkdir()
final writer = _app.path("temp/file.txt").output()
writer.printAndClose("My text here...")
Whenever we use
output, a new file is generated, so if you run the code again, the file will be recreated.
Write JSON file
Here's how we can save JSON data to files:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
_app.path("temp").mkdir()
const writer = _app.path("temp/client.json").output()
writer.printAndClose(
_val.map()
.set("name", "Mary Joanna")
.set(
"register",
_val.list()
.add(1).add(2).add(3)
)
.toJSON()
)
_app.path("temp").mkdir()
writer = _app.path("temp/client.json").output()
writer.printAndClose(
_val.map()
.set("name", "Mary Joanna")
.set(
"register",
_val.list()
.add(1).add(2).add(3)
)
.toJSON()
)
_app.path("temp").mkdir()
writer = _app.path("temp/client.json").output()
writer.printAndClose(
_val.map()
.set("name", "Mary Joanna")
.set(
"register",
_val.list()
.add(1).add(2).add(3)
)
.toJSON()
)
_app.path("temp").mkdir()
val writer = _app.path("temp/client.json").output()
writer.printAndClose(
_val.map()
.set("name", "Mary Joanna")
.set(
"register",
_val.list()
.add(1).add(2).add(3)
)
.toJSON()
)
_app.path("temp").mkdir()
final writer = _app.path("temp/client.json").output()
writer.printAndClose(
_val.map()
.set("name", "Mary Joanna")
.set(
"register",
_val.list()
.add(1).add(2).add(3)
)
.toJSON()
)
To generate indented JSON, that is, formatted across multiple lines and tabbed, we can pass the number of spaces
that will be tabbed, for example .toJSON(4).
More details about the toJSON in Values method.
Read Content in Files
Retrieving content from files is done through the input method, which provides an object of type
InputStream.
To read the data from the input we use the method readAllAndClose,
which processes the reading of the content in the file and closes the file.
Read Text File
Here's an example of how to read a file and retrieve its text content:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const file = _app.file("temp/file.txt")
const reader = file.input()
_log.info(reader.readAllAndClose())
file = _app.file("temp/file.txt")
reader = file.input()
_log.info(reader.readAllAndClose())
file = _app.file("temp/file.txt")
reader = file.input()
_log.info(reader.readAllAndClose())
val file = _app.file("temp/file.txt")
val reader = file.input()
_log.info(reader.readAllAndClose())
final file = _app.file("temp/file.txt")
final reader = file.input()
_log.info(reader.readAllAndClose())
Read JSON file
Here's how we can process JSON data obtained from files:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const file = _app.file("temp/file.txt")
const reader = file.input()
const data = _val.fromJSON(reader.readAllAndClose())
_log.info("File Data:", data)
file = _app.file("temp/file.txt")
reader = file.input()
data = _val.fromJSON(reader.readAllAndClose())
_log.info("File Data:", data)
file = _app.file("temp/file.txt")
reader = file.input()
data = _val.fromJSON(reader.readAllAndClose())
_log.info("File Data:", data)
val file = _app.file("temp/file.txt")
val reader = file.input()
val data = _val.fromJSON(reader.readAllAndClose())
_log.info("File Data:", data)
final file = _app.file("temp/file.txt")
final reader = file.input()
final data = _val.fromJSON(reader.readAllAndClose())
_log.info("File Data:", data)
More details about the fromJSON do recurso Val method of the Val resource.
Storage Specifics
The storage feature has several methods for direct use.
For example, we can access it through storage:
This means that we don't need to get the file or path to work with input or output.
Write Text File to Storage
When initializing storage for a file, we can perform writing using the output method, which obtains an instance of the OutputStream object that allows processing and reading the data.
So with OutputStream the method printAndClose,
writes text (string) to the file and closes it.
See this example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const txt = _storage.filesystem("server", "temp", "file.txt")
txt.ensurePath()
txt.output().printAndClose("My text here...")
txt = _storage.filesystem("server", "temp", "file.txt")
txt.ensurePath()
txt.output().printAndClose("My text here...")
txt = _storage.filesystem("server", "temp", "file.txt")
txt.ensurePath()
txt.output().printAndClose("My text here...")
val txt = _storage.filesystem("server", "temp", "file.txt")
txt.ensurePath()
txt.output().printAndClose("My text here...")
final txt = _storage.filesystem("server", "temp", "file.txt")
txt.ensurePath()
txt.output().printAndClose("My text here...")
Read Text File in Storage
When initializing storage for a file, we can read it using the input method, which obtains an instance of the InputStream object that allows processing and reading the data.
So with InputStream the method readAllAndClose,
reads the entire file and closes it, returning the data as text (string).
See this example:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const txt = _storage.filesystem("server", "temp", "file.txt")
_log.info(txt.input().readAllAndClose())
txt = _storage.filesystem("server", "temp", "file.txt")
_log.info(txt.input().readAllAndClose())
txt = _storage.filesystem("server", "temp", "file.txt")
_log.info(txt.input().readAllAndClose())
val txt = _storage.filesystem("server", "temp", "file.txt")
_log.info(txt.input().readAllAndClose())
final txt = _storage.filesystem("server", "temp", "file.txt")
_log.info(txt.input().readAllAndClose())
Create a random file in Storage.
The _storage resource allows you to generate random filenames using the newRandomFile method.
You must initialize a storage instance for a folder path, and when executing the newRandomFile method, the desired file extension is passed.
The method returns a new instance of the storage for the automatically generated random file to be used in the initial folder.
See how to generate a file with the TXT extension with a random name:
- JavaScript
- Python
- Ruby
- Kotlin
- Groovy
const folder = _storage.filesystem("server", "temp")
const file = folder.newRandomFile("txt")
file.output().printAndClose("My text here...")
folder = _storage.filesystem("server", "temp")
file = folder.newRandomFile("txt")
file.output().printAndClose("My text here...")
folder = _storage.filesystem("server", "temp")
file = folder.newRandomFile("txt")
file.output().printAndClose("My text here...")
val folder = _storage.filesystem("server", "temp")
val file = folder.newRandomFile("txt")
file.output().printAndClose("My text here...")
final folder = _storage.filesystem("server", "temp")
final file = folder.newRandomFile("txt")
file.output().printAndClose("My text here...")
Conclusion
With Netuno's low-code polyglot framework, we can perform all the main folder and file operations directly.
By using the specific resources to manipulate files and folders in:
_app- Application_storage- Application Storage_os- Operating System
For best practices and organizational reasons, we should prioritize the use of storage; exceptions should be only for specific and strictly necessary cases.
Netuno automatically closes inputs and outputs at the end of service processing, but as a best practice, we should always try to close them.