Skip to main content

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:

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:

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

Files in the Application

Ensures that a file that exists is retrieved, for example:

const 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:

const 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:

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

Files in Storage

Ensures that a file that exists is retrieved, for example:

// 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()

Paths in Storage

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

// 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()

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:

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

Files in the Operating System

Ensures that a file that exists is retrieved, for example:

const 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:

const 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:

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

To create a subfolder within an existing folder, specify the full path, separating the folder hierarchy with /:

const 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:

const 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.

const 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.

Eliminar Arquivos e Pastas

Com o método delete podemos tanto remover pastas como arquivos, sendo que as pastas devem estar vazias, veja o exemplo:

// Remove uma pasta vazia:
const pastaVazia = _app.folder("pasta/vazia")
pastaVazia.delete()

// Remove um caminho:
const arquivo = _app.file("pasta/arquivo.txt")
arquivo.delete()

// Remove um caminho, pasta vazia ou arquivo:
const caminho = _app.path("pasta1/arquivo-ou-pasta-vazia")
caminho.delete()

Com o deleteAll permite eliminar tudo, ou seja, todos os arquivos, pastas e subpastas recursivamente:

// Remove a pasta e todo o conteúdo recursivamente:
const pastaVazia = _app.folder("pasta/exemplo")
pastaVazia.deleteAll()

// Remove o caminho de uma pasta e todo o seu conteúdo interno,
// incluindo subpastas e arquivos:
const caminho = _app.path("caminho/pasta")
caminho.deleteAll()

Para eliminar apenas os arquivos dentro da pasta e não apagar nada nas subpastas, temos o deleteFiles, que permite receber uma extensão caso queira remover apenas arquivos com uma extensão específica:

// Remove os arquivos apenas dentro da pasta:
const pasta = _app.folder("pasta/exemplo")
pasta.deleteFiles()

// Remove os arquivos com a extensão JPG apenas dentro da pasta:
const caminho = _app.path("caminho/pasta")
caminho.deleteFiles("jpg")

Para eliminar apenas os arquivos recursivamente e manter a estrutura de pastas, temos o deleteAllFiles, que também permite receber uma extensão caso queira remover apenas um tipo de arquivo específico, veja estes dois exemplos:

// Remove todos os arquivos dentro da pasta e subpastas:
const pasta = _app.folder("pasta/exemplo")
pasta.deleteAllFiles()

// Remove todos os arquivos com a extensão JPG dentro da pasta e subpastas:
const caminho = _app.path("caminho/pasta")
caminho.deleteAllFiles("jpg")

Renomear ou Mover

Para mover uma pasta, é o mesmo que renomeá-la:

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

Para renomear uma pasta e mudá-la de nível na hierarquia de pastas, é o mesmo que mover a pasta:

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

E para mover uma subpasta sem mudar o seu nome, basta indicar o novo caminho no método renameTo:

const folder = _app.folder("test/outra")
folder.renameTo("outra")

Salvar Conteúdos em Arquivos

A geração de conteúdos em arquivos é feita através do método output que fornece um objeto do tipo OutputStream.

Para escrever os dados no output utilizamos o método printAndClose, que imprime o conteúdo no arquivo e fecha o arquivo salvando o conteúdo.

Escrever Arquivo de Texto

Veja o exemplo de como criar um arquivo com conteúdo de texto:

_app.path("temp").mkdir()
const escrita = _app.path("temp/arquivo.txt").output()
escrita.printAndClose("Meu texto aqui...")

Sempre que utilizamos o output é gerado um novo arquivo, portanto se executar o código novamente o arquivo será recriado.

Escrever arquivo JSON

Veja como podemos salvar dados JSON em arquivos:

_app.path("temp").mkdir()
const escrita = _app.path("temp/cliente.json").output()
escrita.printAndClose(
_val.map()
.set("nome", "Maria Joaquina")
.set(
"registros",
_val.list()
.add(1).add(2).add(3)
)
.toJSON()
)

Para gerar o JSON indentado, ou seja, formatado em várias linhas e tabulado, podemos passar o número de espaços que será feita a tabulação por exemplo .toJSON(4).

Mais detalhes sobre o método toJSON em Values.

Ler Conteúdos em Arquivos

A obtenção de conteúdos em arquivos é feita através do método input que fornece um objeto do tipo InputStream.

Para ler os dados no input utilizamos o método readAllAndClose, que processa a leitura do conteúdo no arquivo e fecha o arquivo.

Ler Arquivo de Texto

Veja o exemplo de como ler um arquivo e obter o conteúdo de texto:

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

Ler arquivo JSON

Veja como podemos processar dados JSON obtidos em arquivos:

const arquivo = _app.file("temp/arquivo.txt")
const leitura = arquivo.input()
const dados = _val.fromJSON(leitura.readAllAndClose())
_log.info("Dados do Arquivo:", dados)

Mais detalhes sobre o método fromJSON do recurso Val.

Particularidades do Storage

O recurso storage tem alguns métodos para utilização direta.

Por exemplo, podemos aceder através do storage:

Isto quer dizer que não precisamos obter o file ou path para trabalhar com o input ou output.

Escrever Arquivo de Texto no Storage

Ao iniciar um storage para um arquivo podemos realizar a escrita utilizando o método output, que obtém uma instância do objeto OutputStream que permite processar e ler os dados.

Então com o OutputStream o método printAndClose, faz a escrita de texto (string) no arquivo e fecha-o.

Veja este exemplo:

const txt = _storage.filesystem("server", "temp", "arquivo.txt")
txt.ensurePath()
txt.output().printAndClose("Meu texto aqui...")

Ler Arquivo de Texto no Storage

Ao iniciar um storage para um arquivo podemos realizar a leitura utilizando o método input, que obtém uma instância do objeto InputStream que permite processar e ler os dados.

Então com o InputStream o método readAllAndClose, faz a leitura de todo arquivo e fecha-o, retornando os dados como texto (string).

Veja este exemplo:

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

Criar arquivo aleatório no Storage

O recurso _storage permite gerar nomes de arquivos aleatórios, com o método newRandomFile.

Deve iniciar um storage para o caminho de uma pasta, e ao executar o método newRandomFile é passado a extensão do arquivo pretendido.

O método retorna uma nova instância do storge para o arquivo randômico gerado automaticamente para ser utilizado na pasta inicial.

Veja como gerar um arquivo com extensão TXT com nome randômico:

const pasta = _storage.filesystem("server", "temp")
const arquivo = pasta.newRandomFile("txt")
arquivo.output().printAndClose("Meu texto aqui...")

Conclusão

Com a framework low-code poliglota do Netuno podemos realizar todas as principais operações de pastas e arquivos diretamente.

Ao utilizar os recursos específicos para manipular arquivos e pastas na:

  • _app - Aplicação
  • _storage - Storage da Aplicação
  • _os - Sistema Operacional

Por questões de boas práticas e organização devemos priorizar a utilização do storage, as exceções devem ser apenas casos pontuais e estritamente necessários.

O Netuno processa o fecho automático dos inputs e outputs no fim do processamento dos serviços, mas por boas práticas devemos tentar fechá-los sempre.