Arquivos
Integração por diretório: o CMS lê arquivos que a origem deposita numa pasta (FILE_WATCH) e grava
arquivos numa pasta para quem só consome arquivo (FILE_WRITE). É o caminho para balança,
cromatógrafo, espectrômetro, LIMS, SPC e sistemas legados que exportam CSV/TXT/XML.
Conexão
Cadastre o diretório em Conexões Externas com o tipo Arquivo:
| Campo | Papel |
|---|---|
| Diretório Base | Caminho como o servidor do CMS o enxerga — em container, o ponto de montagem do volume |
| Validar escrita | O teste de conexão e o Keep Alive também gravam/apagam um arquivo temporário |
O CMS não fala SMB/NFS: um compartilhamento de rede é montado pelo sistema operacional (ou pelo
volume do container) e daí em diante é caminho local. O docker-compose.yml monta uma raiz única
em /data/arquivos (variável CMS_FILES_ROOT); cada conexão aponta uma subpasta dela, então criar
uma integração nova não exige mexer no compose.
Todo caminho configurado na Coleta e na Entrega é relativo ao Diretório Base, e sair dele com
.. é bloqueado — inclusive quando o nome do arquivo vem de um {{alias}} do payload.
Você vê o caminho completo
Como você digita só o trecho relativo, cada campo de pasta ou de arquivo mostra logo abaixo o caminho completo no servidor, com o Diretório Base em cinza e o trecho que você controla em destaque. É o mesmo padrão da prévia de URL da Entrega HTTP.
A listagem faz o mesmo com os três caminhos de uma Coleta — pasta monitorada, pasta de
processados e pasta de erro. Os dois últimos são relativos ao Diretório Base, e não à pasta
monitorada: é assim que o servidor os resolve, e era justamente o que ninguém tinha como adivinhar.
Em branco, valem processados e erro.
Se a Conexão de arquivo da Aplicação não tiver Diretório Base preenchido, a prévia dá lugar a um aviso — sem a raiz não há caminho completo, e a leitura ou gravação vai falhar na primeira execução.
Coleta — FILE_WATCH
A varredura roda a cada Intervalo de Varredura, filtrando por Máscara (*.csv;*.txt, aceita
* e ?). Cada arquivo elegível vira uma ou várias mensagens na fila da coleta.
| Campo | Para que serve |
|---|---|
| Estabilidade (ms) | O arquivo só é lido depois de ficar esse tempo sem mudar de tamanho — evita ler algo ainda em gravação |
| Tamanho Máximo (KB) | Acima disso o arquivo vai direto para a pasta de erro, com alerta de Erro de Coleta |
| Modo de Emissão | Arquivo inteiro (1 mensagem, conteúdo cru) ou Uma mensagem por linha (com metadados de origem) |
| Codificação | UTF-8, Latin-1, UTF-16 LE, ASCII ou Binário (Base64) |
| Ação Após Leitura | Mover, Renomear, Apagar ou Nenhuma |
No modo uma mensagem por linha o payload é sempre um envelope JSON:
{ "arquivo": "lote.csv", "caminho": "/data/arquivos/laboratorio/entrada/lote.csv", "linha": 42,
"conteudo": "A;B;C",
"modificadoEm": "2026-08-21T10:00:00.000Z", "recebidoEm": "2026-08-21T10:00:03.120Z" }No modo arquivo inteiro, o payload é o conteúdo cru (XML/JSON chegam prontos ao Transformador), a menos que Incluir metadados esteja ligado.
A ação Nenhuma mantém o controle do que já foi lido apenas na memória do CMS: reiniciar o serviço recoleta todos os arquivos ainda presentes na pasta. Use só em teste — nas demais ações é o próprio filesystem que garante que nada é coletado duas vezes.
Não há parser de CSV/XML nativo: converta com um Transformador, como no resto do CMS.
Detectar a partir de um arquivo
O botão Detectar a partir de um arquivo lê uma amostra de um arquivo que já está na pasta e preenche encoding, modo de leitura, cabeçalho e máscara. Nada é alterado no arquivo.
É a mesma detecção usada pelo catálogo de pastas, e vale pelo mesmo motivo: encoding e delimitador são exatamente os campos que ninguém acerta de primeira e que só falham no primeiro arquivo de verdade.
Concorrência e falhas
Antes de ler, o arquivo é renomeado para <nome>.cms-processando — um rename atômico que impede duas
instâncias do CMS apontando para a mesma pasta de coletarem o mesmo arquivo. Se a leitura ou a
gravação da mensagem falhar, o arquivo vai para a Pasta de Erro e dispara ERRO_COLETA. Diretório
inacessível marca a coleta como desconectada e dispara CONEXAO_ARQUIVO_PERDIDA, sem parar as demais
coletas.
Entrega — FILE_WRITE
O Caminho/Nome do Arquivo é o campo URI Post Message da Definição, relativo ao Diretório Base e
aceitando {{alias}} do payload — o mesmo mecanismo do tópico MQTT:
saida/{{numeroOrdem}}.json| Campo | Papel |
|---|---|
| Modo de Escrita | Criar novo (falha se já existir), Sobrescrever ou Anexar |
| Criar diretório | Cria a pasta de destino quando ela ainda não existe |
| Escrita atômica | Grava num .tmp e renomeia no fim, para o consumidor nunca ler arquivo pela metade |
Modelo de Conteúdo
Define o que vai dentro do arquivo. Vazio, grava o payload da mensagem como ele chegou. Preenchido,
grava aquele texto com cada {{alias}} substituído pelo valor do payload — e aqui há uma sutileza que
vale conhecer:
| Campo | Resolve contra |
|---|---|
| Caminho/Nome do Arquivo | O payload original, antes do Transformador |
| Modelo de Conteúdo | O payload já transformado, ou seja, a saída do Transformador |
Use os filtros de escape sempre que o valor cair dentro de uma string: {{alias|json}},
{{alias|csv}}, {{alias|xml}}. Sem eles, uma aspa ou uma quebra de linha no dado quebra o arquivo
gerado — e o defeito só aparece depois, no sistema legado que for lê-lo.
A opção Validar conteúdo gerado (ligada por padrão) confere, antes de gravar, se o resultado ainda
é um documento válido do Content-Type da Entrega (JSON ou XML). Não sendo, a entrega falha com erro
claro e entra em retentativa, em vez de gravar um arquivo corrompido em silêncio. Content-Type
text/plain não tem o que validar.
No modo Anexar, termine o modelo com uma quebra de linha para cada mensagem virar uma linha do arquivo.
O retorno gravado em payloadRetorno é {"caminho": "<caminho completo do arquivo>", "bytes": N} —
JSON (e não texto puro) porque esse retorno pode ser encaminhado e lido por um Transformador como
{{caminho}}.