Skip to main content

File and Folder Manipulation

Introduction​

In Netuno platform's polyglot backend code, we can manipulate any file or folder.

Manipulation consists of being able to create, rename and delete files and folders, change the content of files and list the contents of folders. In general these are the operations we usually need to do programmatically.

In the Netuno platform there are low-code programming resources that allow manipulating the folders and files internal to the application, but also any files and folders of the system in general, that is, outside of the application.

It is useful when we need to automate some process that needs to touch some file, let's see how.

The low-code polyglot programming resources that allow manipulating files are:

Through these resources we have the methods to:

  • .file - Existing file.
  • .folder - Existing folder.
  • .path - Generic path, which can be either a file or a folder, that exists or does not exist.

With these methods we obtain an object of type File, which provides all the means to manipulate files, folders and paths in general, which allows performing 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​

Guarantees that an existing folder is obtained, for example:

const myFolder = _app.folder("my/folder")

Files in the Application​

Guarantees that an existing file is obtained, for example:

const myFile = _app.file("my/folder/file.txt")

Paths in the Application​

Obtains a file or folder path, regardless of whether it exists or not, for example:

const newFile = _app.path("my/folder/new-file.txt")

Storage​

To perform the main file and folder manipulation operations inside the application's 📁 storage folder, we use the _storage resource:

Folders in Storage​

Guarantees that an existing folder is obtained, for example:

// The real folder path will be:
// storage/filesystem/server/my/folder
const storageMyFolder = _storage.filesystem("server", "my/folder")
const myFolder = storageMyFolder.folder()

Files in Storage​

Guarantees that an existing file is obtained, for example:

// The real file path will be:
// storage/filesystem/server/my/folder/file.txt
const storageFile = _storage.filesystem("server", "my/folder", "file.txt")
const file = storageFile.file()

Paths in Storage​

Obtains a file or folder path, regardless of whether it exists or not, for example:

// The real path of the new folder will be:
// storage/filesystem/server/my/new-folder
const storageFolder = _storage.filesystem("server", "my/new-folder")
const folder = storageFolder.path()

// The real path of the new file will be:
// storage/filesystem/server/my/folder/new-file.txt
const storageFile = _storage.filesystem("server", "my/folder", "new-file.txt")
const file = storageFile.path()

Operating System​

To perform the main file and folder manipulation operations anywhere on the operating system, we use the _os resource:

Folders in the Operating System​

Guarantees that an existing folder is obtained, for example:

const myFolder = _os.folder("/tmp/my/folder")

Files in the Operating System​

Guarantees that an existing file is obtained, for example:

const myFile = _os.file("/tmp/my/folder/file.txt")

Paths in the Operating System​

Obtains a file or folder path, regardless of whether it exists or not, for example:

const newFile = _os.path("/tmp/my/folder/new-file.txt")

Creating Folders​

The mkdir method creates a folder.

In the following example it creates the specific folder at the application root:

const folder = _app.path("temp")
folder.mkdir()

To create a subfolder inside the existing folder, indicate the full path separating the folder hierarchy with /:

const subfolder = _app.path("temp/other")
subfolder.mkdir()

On the other hand, mkdirs creates the previous folders and/or the subfolders if they do not exist, so it allows creating a folder structure in the application, for example:

const folderPath = _app.path("temp/a/b/c")
folderPath.mkdirs()

The _storage resource has the ensurePath method which checks if the path exists, and if it does not exist then creates it:

const file = _storage.filesystem(
"public",
"temp/subfolder",
"file.txt"
)
// Creates the folder structure if it does not exist:
file.ensurePath()

Therefore ensurePath guarantees that the folder structure exists.

Deleting Files and Folders​

With the delete method we can remove both folders and files, and the folders must be empty, see the example:

// Removes an empty folder:
const emptyFolder = _app.folder("folder/empty")
emptyFolder.delete()

// Removes a file:
const file = _app.file("folder/file.txt")
file.delete()

// Removes a path, an empty folder or a file:
const path = _app.path("folder1/file-or-empty-folder")
path.delete()

With deleteAll you can delete everything, that is, all files, folders and subfolders recursively:

// Removes the folder and all contents recursively:
const emptyFolder = _app.folder("folder/example")
emptyFolder.deleteAll()

// Removes a folder path and all its internal content,
// including subfolders and files:
const path = _app.path("path/folder")
path.deleteAll()

To delete only the files inside the folder and not delete anything in the subfolders, we have deleteFiles, which allows receiving an extension if you want to remove only files with a specific extension:

// Removes the files only inside the folder:
const folder = _app.folder("folder/example")
folder.deleteFiles()

// Removes the files with the JPG extension only inside the folder:
const path = _app.path("path/folder")
path.deleteFiles("jpg")

To delete only the files recursively and keep the folder structure, we have deleteAllFiles, which also allows receiving an extension if you want to remove only a specific file type, see these two examples:

// Removes all files inside the folder and subfolders:
const folder = _app.folder("folder/example")
folder.deleteAllFiles()

// Removes all files with the JPG extension inside the folder and subfolders:
const path = _app.path("path/folder")
path.deleteAllFiles("jpg")

Renaming or Moving​

To move a folder is the same as renaming it:

const folder = _app.folder("temp")
folder.renameTo("test")

To rename a folder and change its level in the folder hierarchy is the same as moving the folder:

const folder = _app.folder("temp/a/b")
folder.renameTo("test/z")

And to move a subfolder without changing its name, just indicate the new path in the renameTo method:

const folder = _app.folder("test/other")
folder.renameTo("another")

Saving Contents to Files​

The generation of contents in files is done through 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.

Writing a Text File​

See the example of how to create a file with text content:

_app.path("temp").mkdir()
const write = _app.path("temp/file.txt").output()
write.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.

Writing a JSON File​

See how we can save JSON data to files:

_app.path("temp").mkdir()
const write = _app.path("temp/client.json").output()
write.printAndClose(
_val.map()
.set("name", "Mary Jane")
.set(
"records",
_val.list()
.add(1).add(2).add(3)
)
.toJSON()
)

To generate the indented JSON, that is, formatted over several lines and tabulated, we can pass the number of spaces that will be used for the tabulation, for example .toJSON(4).

More details about the toJSON method in Values.

Reading Contents from Files​

Obtaining contents from files is done through the input method which provides an object of type InputStream.

To read the data in the input we use the readAllAndClose method, which processes the reading of the content in the file and closes the file.

Reading a Text File​

See the example of how to read a file and obtain the text content:

const file = _app.file("temp/file.txt")
const read = file.input()
_log.info(read.readAllAndClose())

Reading a JSON File​

See how we can process JSON data obtained from files:

const file = _app.file("temp/file.txt")
const read = file.input()
const data = _val.fromJSON(read.readAllAndClose())
_log.info("File Data:", data)

More details about the fromJSON method of the Val resource.

Storage Specifics​

The storage resource has some methods for direct use.

For example, we can access through storage:

This means that we do not need to obtain the file or path to work with input or output.

Writing a Text File in Storage​

When starting a storage for a file we can perform the write using the output method, which obtains an instance of the OutputStream object which allows processing and reading the data.

Then with the OutputStream the printAndClose method, writes text (string) to the file and closes it.

See this example:

const txt = _storage.filesystem("server", "temp", "file.txt")
txt.ensurePath()
txt.output().printAndClose("My text here...")

Reading a Text File in Storage​

When starting a storage for a file we can perform the read using the input method, which obtains an instance of the InputStream object which allows processing and reading the data.

Then with the InputStream the readAllAndClose method, reads the entire file and closes it, returning the data as text (string).

See this example:

const txt = _storage.filesystem("server", "temp", "file.txt")
_log.info(txt.input().readAllAndClose())

Creating a Random File in Storage​

The _storage resource allows generating random file names, with the newRandomFile method.

You should start a storage for a folder path, and when executing the newRandomFile method, the extension of the desired file is passed.

The method returns a new storage instance for the random file automatically generated to be used in the initial folder.

See how to generate a file with the TXT extension with a random name:

const folder = _storage.filesystem("server", "temp")
const file = folder.newRandomFile("txt")
file.output().printAndClose("My text here...")

Conclusion​

With Netuno's polyglot low-code framework we can perform all the main folder and file operations directly.

When using the specific resources to manipulate files and folders in the:

  • _app - Application
  • _storage - Application Storage
  • _os - Operating System

For the purposes of best practices and organization we should prioritize the use of storage, the exceptions should be only specific cases and strictly necessary.

Netuno handles the automatic closing of inputs and outputs at the end of the service processing, but for best practices we should try to always close them.