# File

> Valores que outro programa grava num arquivo de uma pasta local ou de rede (o CSV de uma máquina de ensaio, o registro de um datalogger, um resultado em JSON ou XML) lidos como tags, e linhas ou arquivos inteiros gravados para outro programa ler: os cartões Pasta e arquivo, Texto do arquivo e Escrita, o que uma tag lê em cada formato, a pasta de entrada, a varredura que oferece uma tag por coluna ou campo, três exemplos completos e o que o driver não faz.

O driver **File** lê os valores que outro programa grava num arquivo: o CSV em que uma máquina de
ensaio acrescenta uma linha depois de cada amostra, o registro de um datalogger, um arquivo de
resultado em JSON ou XML, um arquivo de texto que só traz o código de um lote. Cada tag lê um valor
do arquivo, e os valores chegam onde chegam os de toda outra tag: no Logic, nos dashboards, nas
execuções de uma bancada de teste do [Process](process). Onde o dispositivo permite, o driver também
grava para outro programa ler: uma linha acrescentada a um arquivo, ou um arquivo inteiro substituído.

Ler é o uso principal, e pede três respostas: a pasta, o arquivo e o formato dele. Como o texto do
arquivo se lê (a codificação, o separador de colunas, o separador decimal) vem do próprio arquivo
enquanto fica em detectar, a varredura oferece uma tag por coluna ou campo, e toda tag nasce somente
leitura. O que é de escrita só aparece depois que a escrita é ligada no dispositivo.

Um dispositivo deste driver é uma pasta e o arquivo que ele lê nela: dois arquivos da mesma pasta são
dois dispositivos. A pasta é uma unidade e uma pasta (`C:\TestMachine\Logs`) ou um compartilhamento de
rede e uma pasta dentro dele (`\\lab-pc\results`), e a estação a acessa com as permissões do Windows
da conta em que roda. Os dispositivos ficam sob o driver e podem ser arquivados em pastas,
**Driver → Pasta → Dispositivo → Tag**, como em todo driver sem linha serial nem broker.

## A página do driver {#the-drivers-page}

A linha sob o cabeçalho diz "Cada dispositivo lê um arquivo, ou os arquivos que chegam a uma pasta. Acrescente um dispositivo, informe a pasta, o arquivo e o formato, e depois varra-o para acrescentar os valores como tags."
Para Configurar Connector, a página traz o cartão Escopo da varredura próprio do driver, com o arquivo
que a varredura lê (veja [Descoberta](#discovery)). Abaixo dele fica a tabela **Dispositivos** de
qualquer driver (veja [A tabela de dispositivos](connector-drivers#the-device-table)), que cresce com
**Acrescentar dispositivo**, à direita do título; vazia, diz "Nenhum dispositivo ainda." A barra do
driver traz **Descobrir**, cinza até o cartão Escopo da varredura estar completo. O driver aparece em
**Arquivos e bancos de dados**, a categoria que fica entre Web e APIs e Teste em toda lista de drivers.

## Dispositivo {#device}

Um dispositivo deste driver não tem cartão Conexão: o cartão **Pasta e arquivo** fica no lugar dele,
seguido do cartão **Texto do arquivo** e, num dispositivo que lê um arquivo, do cartão **Escrita**. O
**Intervalo de leitura (ms)** do cartão Dispositivo, 1000 por padrão, diz de quanto em quanto tempo as
tags leem o arquivo, com cada tag podendo sobrescrevê-lo como em qualquer driver.

Um dispositivo novo não tem pasta: diz "Pasta ainda não informada", a página dele diz "A estação não lê este dispositivo enquanto ele não tiver uma pasta, então nada é lido dele ainda e não há erro a mostrar. Informe a pasta no cartão Pasta e arquivo abaixo e a estação começa a lê-lo."
e nada é lido até a pasta ser informada. A Base URI que o cabeçalho mostra é o endereço de runtime,
com a pasta e o nome escritos em forma de URI, e depois deles o que não está em detectar:
`file://single?folder=C%3A%5CTestMachine%5CLogs&name=Log_%7Byyyy-MM-dd%7D.csv&format=delimited`, ou
`file://inbox?...` para uma pasta de entrada.

### O cartão Pasta e arquivo {#the-folder-and-file-card}

| Campo | Significado | Padrão |
| --- | --- | --- |
| **Caminho da pasta** | "Uma unidade e uma pasta, ou um compartilhamento de rede. A pasta é acessada com as permissões do Windows da conta em que a estação roda." A caixa mostra `C:\TestMachine\Logs` como dica. | vazio |
| **Nome do arquivo** | Num dispositivo que lê um arquivo: "Um nome dentro da pasta. As partes entre chaves são a data e a hora da estação: Log_{yyyy-MM-dd}.csv é um arquivo novo a cada dia." Uma subpasta da pasta pode fazer parte do nome (`results\last.csv`). | vazio |
| **Arquivos a ler** | A mesma caixa numa pasta de entrada: "Os arquivos a ler, diretamente na pasta: * vale por quaisquer caracteres e ? por um só, como Test_*.csv." | vazio |
| **Ler de** | **Um arquivo**: "O arquivo é lido de novo sempre que muda. Um arquivo que cresce é lido a partir de onde a última leitura parou." **Pasta de entrada**: "Cada arquivo novo é lido uma vez, na ordem de chegada, e movido para a subpasta Processed. Nada é excluído." | **Um arquivo** |
| **Formato do arquivo** | **CSV e texto em colunas**, **Texto livre**, **JSON** ou **XML**: como uma tag encontra o valor dela no arquivo (veja [Endereçamento de tags](#tag-addressing)). | **CSV e texto em colunas** |

Um nome com uma parte de data é escrito entre chaves com um formato .NET de data e hora, no relógio da
própria estação: `Log_{yyyy-MM-dd}.csv` é `Log_2026-10-03.csv` hoje e o arquivo do dia seguinte depois
da meia-noite, e `Data_{yyyy-MM}.txt` muda todo mês. Abaixo da caixa, o cartão mostra qual arquivo é
esse agora: "Hoje: Log_2026-10-03.csv". Chaves dobradas `{{` e `}}` são chaves do nome. Uma parte de
data nunca escreve dois-pontos, que nenhum nome de arquivo aceita: `{HH-mm}`, não `{HH:mm}`.

Quando o dispositivo roda, o cartão diz qual arquivo ele lê:

| O cartão diz | Quando |
| --- | --- |
| "Lendo agora: Log_2026-10-03.csv" | O arquivo em uso, como o dispositivo o lê agora. |
| "Lendo agora: Log_2026-10-03.csv (ainda não existe)" | O arquivo ainda não existe: as tags dele esperam e o dispositivo continua online. |
| "Uma tag escreveu este nome. Depois de reiniciar, o dispositivo volta a ler o arquivo configurado." | Uma tag que lê o nome do arquivo foi escrita e aponta o dispositivo para outro arquivo (veja [Escrita](#writing)). |
| "3 arquivos aguardando na pasta de entrada" | Uma pasta de entrada, com os arquivos que casam com o padrão ainda a ler ("1 arquivo aguardando na pasta de entrada" para um). |

Uma configuração que o cartão não aceita é dita abaixo dos cartões, e o dispositivo não é salvo até
ela ser corrigida:

| Você informa | O cartão diz |
| --- | --- |
| Uma pasta que não é um caminho completo, como `Logs` | "A pasta é um caminho completo: uma unidade e uma pasta (C:\Test), ou um compartilhamento de rede e uma pasta dentro dele (\\server\tests)." |
| Uma pasta com um caractere que nenhum nome de pasta aceita, ou um compartilhamento sem pasta dentro dele (`\\server`) | "A pasta contém um caractere que nenhum nome de pasta aceita, ou é um compartilhamento de rede sem uma pasta dentro dele." |
| Nenhum nome de arquivo | Não é recusado: o dispositivo é salvo e aguarda, "Nome do arquivo ainda não informado" ("Arquivos a ler ainda não informados" numa pasta de entrada), até um nome ser informado. |
| Um caminho completo como nome, como `C:\Logs\last.csv` | "O nome do arquivo é um nome dentro da pasta, não um caminho completo: a pasta vai na caixa Caminho da pasta." |
| Um nome com `..`, como `..\other\last.csv` | "O nome do arquivo sai da pasta com "..". O driver nunca sai da sua pasta." |
| Um nome com `:` ou outro caractere que nenhum nome de arquivo aceita, ou uma parte que termina em ponto ou espaço | "O nome do arquivo contém um caractere que nenhum nome de arquivo aceita (como : ou \|), ou uma parte dele termina em ponto ou espaço. Uma parte de data não pode escrever dois-pontos: use {HH-mm}, não {HH:mm}." |
| Um nome que o Windows reserva para um dispositivo, como `CON` ou `COM1` | "O Windows reserva este nome para um dispositivo (CON, NUL, COM1 e semelhantes). Escolha outro." |
| `*` ou `?` num dispositivo que lê um arquivo | "Só o padrão de uma pasta de entrada aceita * ou ?. Informe o nome de um único arquivo, ou leia de uma pasta de entrada." |
| Uma subpasta no padrão de uma pasta de entrada | "Uma pasta de entrada é a própria pasta: coloque a subpasta na caixa Caminho da pasta e deixe aqui só o padrão." |
| Uma parte de data não fechada, ou que não é um formato de data | "Uma parte de data do nome não está fechada ou não é um formato de data. Escreva-a entre chaves, como Log_{yyyy-MM-dd}.csv." |

O salvamento segue as mesmas regras, e o feed diz quando recusa uma:
"O dispositivo 'Tensile tester' tem uma configuração de arquivo que o driver não consegue usar. Abra-o e corrija o campo que o painel marca."

### O cartão Texto do arquivo {#the-text-of-the-file-card}

Como se leem os caracteres, as colunas e os números do arquivo. Toda configuração começa em
**Detectar pelo arquivo**, e o driver a lê do arquivo em uso. Abaixo de uma configuração deixada
assim, depois que o dispositivo leu o arquivo, uma linha diz o que ele encontrou, como
"Encontrado no arquivo: UTF-8". Qualquer configuração pode ser fixada escolhendo-a, para um arquivo
cujas primeiras linhas não dizem.

| Campo | Mostrado | Opções | Padrão |
| --- | --- | --- | --- |
| **Codificação** | sempre | **Detectar pelo arquivo**, `UTF-8`, `Windows-1252 (ANSI)` (a codificação de programas antigos do Windows) | **Detectar pelo arquivo** |
| **Separador de colunas** | CSV | **Detectar pelo arquivo**, **Ponto e vírgula (;)**, **Vírgula (,)**, **Tabulação** | **Detectar pelo arquivo** |
| **Separador decimal** | sempre | **Detectar pelo arquivo**, **Ponto decimal (12.5)**, **Vírgula decimal (12,5)** | **Detectar pelo arquivo** |
| **Linha de cabeçalho** | CSV | De 0 a 1000: "A linha que contém os nomes das colunas, contada a partir de 1. 0 quando o arquivo não tem." As linhas antes dela são puladas. | 1 |

| Configuração | O que a detecção lê |
| --- | --- |
| Codificação | Uma marca de ordem de bytes no começo do arquivo, que vence qualquer escolha; senão UTF-8 quando os bytes são UTF-8 válido; senão Windows-1252. |
| Separador de colunas | O primeiro entre tabulação, ponto e vírgula e vírgula que divide as primeiras linhas no mesmo número de colunas; uma primeira linha sem nenhum deles é um arquivo de uma coluna. |
| Separador decimal | A vírgula quando mais números do arquivo têm uma vírgula do que um ponto entre os dígitos; senão o ponto. Números JSON sempre têm o ponto; a configuração vale para números escritos como texto. |

### O cartão Escrita {#the-writing-card}

Um dispositivo que lê um arquivo traz o cartão **Escrita**; uma pasta de entrada só é lida e não tem
esse cartão.

| Campo | Mostrado | Significado | Padrão |
| --- | --- | --- | --- |
| **Permitir escrita** | sempre | Desligado: "O dispositivo só lê. Ligue a escrita para acrescentar linhas, substituir o arquivo ou trocar para outro arquivo enquanto a estação roda." Ligado: "As tags deste dispositivo podem escrever no arquivo. Cada tag continua só lendo até que o acesso dela diga outra coisa." | desligado |
| **Texto do cabeçalho** | escrita ligada, CSV ou texto livre | "Escrito primeiro em um arquivo que uma escrita cria, como Time;Pressure." Uma linha, sem quebra de linha. | vazio |
| **Fim de linha** | escrita ligada | **Detectar pelo arquivo** (o do próprio arquivo, CR LF num arquivo novo), **CR LF, como no Windows** ou **LF**. | **Detectar pelo arquivo** |

A escrita só é desligada quando nenhuma tag do dispositivo escreve. Enquanto alguma ainda escreve, o
interruptor continua desenhado e cinza, e diz por quê: "2 tags deste dispositivo escrevem no arquivo. Deixe-as somente leitura antes de desligar a escrita."
("Uma tag deste dispositivo escreve no arquivo. Deixe-a somente leitura antes de desligar a escrita." para uma).

### Online, aguardando e offline {#online-waiting-and-offline}

| Situação | O que o dispositivo e as tags dele fazem |
| --- | --- |
| Nenhuma pasta informada | O dispositivo aguarda: "Pasta ainda não informada", ponto cinza, nada lido e nenhum erro. |
| Pasta informada, sem nome de arquivo | O dispositivo aguarda: "Nome do arquivo ainda não informado", ponto cinza, nada lido e nenhum erro; a página dele diz "A estação não lê este dispositivo enquanto ele não tiver um nome de arquivo, então nada é lido dele ainda e não há erro a mostrar. Informe o nome do arquivo no cartão Pasta e arquivo abaixo e a estação começa a lê-lo." |
| Pasta de entrada, pasta informada, sem arquivos a ler | O dispositivo aguarda: "Arquivos a ler ainda não informados", ponto cinza, nada lido e nenhum erro; a página dele diz "A estação não lê este dispositivo enquanto não souber quais arquivos ler, então nada é lido dele ainda e não há erro a mostrar. Informe os arquivos em Arquivos a ler, no cartão Pasta e arquivo abaixo (como Test_*.csv), e a estação começa a lê-los." |
| A pasta não pode ser acessada (um compartilhamento fora do ar, uma unidade que sumiu, uma conta sem acesso) | O dispositivo fica offline e as tags dele falham a leitura; a pasta é olhada de novo no máximo a cada segundo, e o dispositivo conecta assim que ela volta. |
| A pasta é acessada, o arquivo ainda não existe | O dispositivo continua online. As tags que leem valores ficam sem leitura e aguardam; **O arquivo existe** lê falso. |
| Outro programa segura o arquivo sem compartilhá-lo | Nenhuma leitura desta vez; a leitura seguinte tenta de novo. A tag mantém a última leitura, e uma mais velha que o intervalo de leitura dela mais 10 s conta como leitura que falhou, como em todo driver. |
| Um valor não está lá, ou não cabe no tipo da tag | Leitura que falhou daquela tag, com o motivo; o dispositivo continua lendo as outras tags. |

## Endereçamento de tags {#tag-addressing}

### O que uma tag lê {#what-a-tag-reads}

Uma tag deste driver não tem caixa de endereço própria: o cartão **Origem** dela pergunta o que ela lê
e, para um valor, onde o valor está no formato do dispositivo.

| **Lê** | O que a tag mostra | Tipo de dado |
| --- | --- | --- |
| **Valor** | Um valor dentro do arquivo, encontrado pelos campos do formato do dispositivo abaixo. | Boolean, Int32, Int64, Float, Double ou String; Double numa tag nova |
| **Arquivo inteiro** | O conteúdo inteiro, sem os fins de linha do final: um arquivo que só traz o código de um lote ou um status. No máximo 4 MiB. | os mesmos; String numa tag nova |
| **O arquivo existe** | Se o arquivo em uso existe agora. | Boolean |
| **Tamanho do arquivo** | O tamanho do arquivo em bytes. | Int64 |
| **Última alteração** | Quando o arquivo foi gravado pela última vez: ver isso mudar é como o Logic sabe que chegou dado novo. | DateTime |
| **Nome do arquivo** | O nome do arquivo em uso, dentro da pasta. Escrito, ele aponta outro arquivo (veja [Escrita](#writing)). | String |
| **Contagem de linhas** | "Conta todas as linhas do arquivo, incluindo a linha de cabeçalho e as linhas em branco." | Int64 |

Um tipo em que a origem não é lida é recusado com os tipos em que ela é: "Escolha um dos tipos de dado em que isto é lido: Int64."
Escolher outra origem traz o tipo dela. O texto tirado de um arquivo é lido no tipo da tag do jeito
que o [driver serial e TCP genérico](driver-generic-serial-tcp#tag-addressing) lê uma mensagem, com o
separador decimal do arquivo: um Boolean lê `1`, `true`, `on` ou `yes` e `0`, `false`, `off` ou `no`,
um inteiro lê um número inteiro, e um String pega os caracteres como estão, então um código como
`0412` só mantém o zero da frente como String.

Toda tag nasce **Somente leitura**, e num dispositivo que não permite escrita o campo **Acesso** não
oferece outra coisa. Quando o dispositivo permite escrita, uma tag que lê **Valor** ou
**Arquivo inteiro** pode ser **Leitura e escrita** ou **Somente escrita**, e uma tag que lê
**Nome do arquivo** **Leitura e escrita**; os dados do arquivo (existe, tamanho, última alteração,
contagem de linhas) nunca são escritos: "Um dado do arquivo não pode ser escrito. Deixe a tag somente leitura."

### CSV e texto em colunas {#csv-and-text-in-columns}

| Campo | Mostrado | Significado | Padrão |
| --- | --- | --- | --- |
| **Coluna** | Lê Valor | "O nome da coluna na linha de cabeçalho, ou o número dela contado a partir de 1." Um texto só de dígitos é um número; um nome ignora maiúsculas e os espaços em volta. Num arquivo sem linha de cabeçalho: "O número da coluna, contado a partir de 1. O arquivo não tem linha de cabeçalho, então as colunas não têm nome." | vazio |
| **Linha a ler** | Lê Valor | **Última**, **Pelo número** ou **Pelo conteúdo**. "As linhas são contadas depois da linha de cabeçalho. Pelo conteúdo lê a última linha cuja coluna-chave contém o valor-chave." | **Última** |
| **Número da linha** | Pelo número | A linha de dados, contada a partir de 1 depois do cabeçalho. | vazio |
| **Coluna-chave** | Pelo conteúdo | A coluna cujo valor escolhe a linha, pelo nome ou pelo número. | vazio |
| **Valor-chave** | Pelo conteúdo | O valor que a coluna-chave tem na linha a ler, como `0412`. | vazio |

Um campo entre aspas duplas pode conter o separador; um campo que contém uma quebra de linha não é
lido. Uma tag cujos campos não funcionam não é salva, e a página dela diz o que falta:

| Você deixa ou informa | A página da tag diz |
| --- | --- |
| Nenhuma coluna | "Informe a coluna, pelo nome dela na linha de cabeçalho ou pelo número." |
| Coluna 0 | "As colunas são contadas a partir de 1." |
| Uma coluna pelo nome num arquivo sem linha de cabeçalho | "O arquivo não tem linha de cabeçalho, então uma coluna é indicada pelo número." |
| Pelo número, sem número de linha | "Informe o número, contado a partir de 1." |
| Pelo conteúdo, sem coluna-chave | "Informe a coluna-chave: a coluna cujo valor escolhe a linha." |
| Pelo conteúdo, sem valor-chave | "Informe o que a linha contém." |

A linha somente leitura **Endereço de origem (barramento)** mostra o que o driver recebe:
`column?name=Force` para o Force da última linha, `column?number=3&row=number&rowNumber=5` para a
terceira coluna da quinta linha, `column?name=Force&row=match&key=Sample&equals=0412` para a linha da
amostra 0412.

### Texto livre {#free-text}

| Campo | Mostrado | Significado | Padrão |
| --- | --- | --- | --- |
| **Linha a ler** | Lê Valor | **Última** (a última linha que não está em branco), **Pelo número** ou **Pelo conteúdo**. "As linhas são contadas desde o início do arquivo. Pelo conteúdo lê a última linha que contém o texto." | **Última** |
| **Número da linha** | Pelo número | A linha, contada a partir de 1 no início do arquivo. | vazio |
| **A linha contém** | Pelo conteúdo | Um texto que a linha a ler contém, como `Result`. | vazio |
| **O valor é** | Lê Valor | "As mesmas opções do driver Generic serial and TCP: a linha inteira, uma posição fixa, um campo entre separadores ou uma expressão regular." As opções são as daquele driver, com a primeira nomeada pela linha: **A linha inteira**, **Posição fixa** (**Primeiro caractere** e **Tamanho**), **Campo entre separadores** (**Separador** e **Número do campo**) e **Grupo de captura de um padrão** (**Padrão**). | **A linha inteira** |

Posições e campos contam a partir de 1, um padrão é uma expressão regular .NET com exatamente um grupo
de captura em volta do valor, e uma linha que ele leva mais de 250 ms para ler não é lida. As recusas
são as do próprio driver genérico, como "Informe o primeiro caractere do valor, contando a partir de 1." ou "O padrão precisa de exatamente um grupo de captura, em volta do valor."
O endereço de barramento diz `line` seguido do que se aplica, por exemplo
`line?row=match&contains=Result&extract=regex&pattern=...`.

### JSON e XML {#json-and-xml}

| Campo | Formato | Significado |
| --- | --- | --- |
| **Caminho JSON** | JSON | "Membros separados por pontos e posições entre colchetes a partir de 0, como result.force ou items[0].value." Um membro cujo nome tem um ponto é escrito `['flow.rate']`. |
| **Caminho XML** | XML | "Elementos a partir da raiz separados por barras, uma posição a partir de 1 onde um elemento se repete, e um atributo por último, como Result/Force ou Result/@unit." Os nomes casam pelo nome local, sem o prefixo de namespace. |

Um número JSON, `true` ou `false` é pego como está, e uma string é lida no tipo da tag; um objeto ou
uma lista só se lê como String, o JSON dele. Um documento JSON ou XML é lido inteiro quando mudou, no
máximo 4 MiB, e nenhuma DTD é lida. O endereço de barramento é `json?path=result.force` ou
`xml?path=Result%2FForce`.

| Você deixa ou informa | A página da tag diz |
| --- | --- |
| Nenhum caminho | "Informe o caminho até o valor. Para ler o arquivo inteiro, escolha Arquivo inteiro." |
| Um caminho JSON que não se lê | "Isto não é um caminho JSON: membros separados por pontos e posições entre colchetes, como result.items[0].value." |
| Um caminho XML que não se lê | "Isto não é um caminho XML: elementos separados por barras, uma posição como Item[2] e um atributo por último, como @unit." |

## Leitura {#reading}

A cada leitura o driver pergunta ao Windows o tamanho e as horas do arquivo, o que funciona num
compartilhamento de rede, onde os avisos de mudança do Windows falham, e só abre o arquivo quando um
deles mudou. Ele sempre o abre compartilhando leitura, escrita e exclusão, então o programa que grava
o arquivo nunca é bloqueado.

| O arquivo | O que a leitura faz |
| --- | --- |
| Cresceu, e ainda começa e termina onde começava e terminava | Só o que entrou é lido, nunca o arquivo inteiro de novo: um registro de muitos megabytes custa o que as linhas novas custam. |
| Ficou menor, foi gravado de novo ou criado de novo | Lido de novo desde o começo. |
| Termina com uma linha que nenhum fim de linha fecha ainda | Essa linha espera, para um valor nunca ser lido pela metade; depois que o arquivo fica 2 s sem mudar, ela é lida como a última linha. |
| JSON, XML, ou uma tag que lê o arquivo inteiro | Lido inteiro quando mudou, no máximo 4 MiB; um documento que não se lê e mudou há menos de 2 s é tomado como ainda sendo gravado, e as tags esperam. |
| Tem uma linha com mais de 1 MiB | Não é texto em linhas: as tags dele falham a leitura. |

Toda leitura é datada pela última alteração do arquivo, não pelo momento em que foi lida, então o
registro da execução coloca uma amostra no momento em que o outro programa a gravou.

## A pasta de entrada {#the-inbox-folder}

**Ler de** **Pasta de entrada** é para a máquina que grava um arquivo por amostra (`Test_0412.json`,
`Test_0413.json`...): cada arquivo novo que casa com o padrão é lido uma vez, na ordem de chegada.

| Passo | O que acontece |
| --- | --- |
| Um arquivo chega | Ele é pego depois de ficar 1 s com o mesmo tamanho e a mesma hora e sem nenhum programa o mantendo aberto para gravar. |
| Qual vem primeiro | O criado primeiro, depois o gravado primeiro, depois pelo nome. Dois arquivos que chegam juntos são lidos em duas passadas: nenhum é pulado. |
| A leitura dele | Toda tag do dispositivo lê esse arquivo, e o arquivo é uma leitura, datada pela hora do arquivo: o registro da execução grava cada uma. **Nome do arquivo** diz de qual arquivo os valores vieram. |
| Depois que toda tag o leu | Ele é movido para a subpasta `Processed`, que o driver cria e cujo nome é o mesmo em toda língua, porque outros programas podem procurá-la; um nome já ocupado lá vira `name (2).json`. Os valores dele continuam sendo a leitura das tags até o arquivo seguinte. |
| Uma movimentação que falha | Tentada de novo a cada leitura; o arquivo não é lido de novo enquanto isso. |
| A estação reinicia antes da movimentação | O arquivo é lido de novo: uma leitura contada duas vezes em vez de uma perdida. |

Nada é excluído nunca: a subpasta `Processed` cresce até alguém esvaziá-la. Uma pasta de entrada
nunca é escrita.

## Escrita {#writing}

Num dispositivo que lê um arquivo e permite escrita, uma tag que lê **Valor** ou **Arquivo inteiro**
cujo acesso escreve diz o que uma escrita faz:

| Campo | Mostrado | Significado | Padrão |
| --- | --- | --- | --- |
| **Uma escrita** | a tag escreve | **Acrescentar uma linha**: "Acrescenta uma linha no fim do arquivo. Toda escrita conta: nenhuma é descartada por uma mais nova." **Substituir o arquivo**: "Substitui o arquivo inteiro pelo valor, por meio de um arquivo temporário, para que nenhum programa o leia pela metade." | **Acrescentar uma linha** |
| **Modelo de linha** | Acrescentar uma linha | "Vazio: o valor escrito é a linha inteira. {value} é o valor e {datetime} o momento da escrita, cada um com um formato depois de dois-pontos se preciso, como {value:0.00}." A caixa mostra `{datetime};{value}` como dica. | vazio |

| O modelo | Escrever 12.5 acrescenta |
| --- | --- |
| vazio | `12.5` |
| `{datetime};{value}` | `2026-10-03 14:05:12;12.5` |
| `{datetime:dd/MM/yyyy HH:mm};{value:0.00}` | `03/10/2026 14:05;12.50` |

`{value:FORMAT}` aceita um formato numérico .NET, `{datetime:FORMAT}` um formato .NET de data e hora,
no relógio da estação, `yyyy-MM-dd HH:mm:ss` quando nenhum é dado. Um número é escrito com o separador
decimal do arquivo, então o mesmo modelo escreve `12,50` num arquivo que usa a vírgula. O modelo de
uma tag Boolean pode deixar `{value}` de fora: escrita como verdadeiro, ela acrescenta a linha, como um
comando. Um modelo que o driver não consegue preencher é recusado na página da tag:

| Você informa | A página da tag diz |
| --- | --- |
| Uma parte que não é `{value}` nem `{datetime}`, ou uma chave não fechada | "O modelo de linha aceita {value} e {datetime}, cada um com um formato depois de dois-pontos se preciso. {{ e }} são chaves da linha." |
| Nenhum `{value}` numa tag que não é Boolean | "O modelo de linha não tem {value}, então o valor escrito nunca chegaria ao arquivo. Só uma tag booleana pode omiti-lo: escrita como verdadeiro, ela acrescenta a linha." |
| Uma quebra de linha | "O modelo de linha é uma única linha, sem quebra de linha." |
| Uma tag que escreve, num dispositivo que não permite escrita | "O dispositivo não permite escrita. Ligue a escrita no dispositivo ou deixe a tag somente leitura." |

| Uma escrita | Como acontece |
| --- | --- |
| Acrescentar uma linha | A linha vai numa só escrita e é descarregada no disco antes de a escrita contar como feita. Um arquivo que a escrita cria recebe primeiro o **Texto do cabeçalho**, e um arquivo cuja última linha não tem fim de linha recebe um antes, para a linha ficar inteira. Um valor que contém uma quebra de linha é recusado. Toda escrita conta: uma escrita que ainda espera na fila do dispositivo nunca é descartada por uma mais nova para a mesma tag, como um comando nunca é. |
| Substituir o arquivo | O valor vai para um arquivo temporário ao lado do arquivo, descarregado, que toma o lugar do arquivo num só passo. Um valor mais novo que ainda espera substitui um mais velho, como para qualquer setpoint. |
| O nome do arquivo | Uma tag que lê **Nome do arquivo**, **Leitura e escrita**, escrita com outro nome, aponta o dispositivo para esse arquivo da mesma pasta dali em diante: "Escrever um nome aqui faz o dispositivo ler e escrever, a partir daí, esse arquivo da mesma pasta. Um nome fora da pasta é recusado." Um caminho completo, `..`, `:` ou um nome que o Windows reserva é recusado. Quando o dispositivo conecta de novo, reinício incluído, ele volta a ler o arquivo configurado. |
| Texto | Na codificação, no fim de linha e no separador decimal do próprio arquivo, lidos dele onde o dispositivo os deixa em detectar. Um arquivo novo é UTF-8 sem marca de ordem de bytes, com CR LF e o ponto decimal, a menos que o dispositivo diga outra coisa. |
| Resposta | Feita, ou recusada com a causa: o dispositivo não permite escrita, a conta não tem permissão, o arquivo está marcado como somente leitura (retirar esse atributo deixa a próxima escrita passar), o disco está cheio, ou o arquivo está aberto em outro programa. Uma substituição é recusada enquanto qualquer programa tiver o arquivo aberto, e um acréscimo só enquanto um programa o prende sem compartilhá-lo; assim que esse programa fecha o arquivo, a próxima escrita passa. |

A pasta e as subpastas para as quais um nome aponta são criadas quando uma escrita precisa delas,
sempre dentro da pasta do dispositivo.

## Descoberta {#discovery}

### O cartão Escopo da varredura {#the-scan-scope-card}

Para Configurar Connector, a página do driver traz o cartão **Escopo da varredura** dele, sob a linha
"Lê um arquivo e oferece uma tag para cada coluna ou campo que encontra, e para os dados do arquivo. Escolha um dispositivo para ler o arquivo dele, ou digite uma pasta, um arquivo e um formato."

| Campo | Significado | Padrão |
| --- | --- | --- |
| **Arquivo a varrer** | **Um arquivo digitado aqui**, ou um dispositivo do driver pelo nome. O arquivo de um dispositivo é lido com as configurações do dispositivo como estão salvas, e uma edição do dispositivo que ainda espera para ser salva é salva antes. | **Um arquivo digitado aqui** |
| **Caminho da pasta** | Um arquivo digitado: a pasta, como num dispositivo. | vazio |
| **Nome do arquivo** ou **Arquivos a ler** | Um arquivo digitado: o nome, ou o padrão de uma pasta de entrada. | vazio |
| **Ler de** | Um arquivo digitado: **Um arquivo** ou **Pasta de entrada**. | **Um arquivo** |
| **Formato do arquivo** | Um arquivo digitado: o formato. Toda configuração de texto de um arquivo digitado é detectada, a linha de cabeçalho incluída: a primeira linha é um cabeçalho quando nenhum dos campos dela é um número e a linha seguinte tem um. | **CSV e texto em colunas** |

O que ainda falta no escopo é dito em vermelho abaixo do cartão, e o Descobrir fica cinza até ele
estar completo:

| O escopo | O cartão diz |
| --- | --- |
| Um arquivo digitado sem pasta | "Digite a pasta em que o arquivo está." |
| Uma pasta digitada que não é um caminho completo | "'Logs' não é uma pasta que esta estação consegue ler. Escreva um caminho completo, por exemplo C:\Test ou \\server\tests." |
| Um nome digitado que não é um arquivo da pasta | "'..\last.csv' não é o nome de um arquivo dentro da pasta." |
| Um dispositivo que não existe mais | "O dispositivo escolhido para varrer não existe mais. Escolha outro arquivo a varrer." |
| Um dispositivo sem a pasta ou sem o arquivo | "O dispositivo 'Tensile tester' ainda não tem pasta ou arquivo, ou tem uma configuração que o driver não consegue usar. Complete primeiro o cartão Pasta e arquivo." |

Quando o dispositivo a varrer tem uma edição que não pode ser salva, a varredura não começa:
"A descoberta não começou porque a edição do dispositivo a varrer não pôde ser salva."

### O que a varredura oferece {#what-the-scan-offers}

A varredura lê o arquivo que um dispositivo de um arquivo lê agora, ou o arquivo mais novo de uma pasta
de entrada, que ela não move; um arquivo que não está lá, uma pasta que não pode ser acessada e um
documento que não se lê encerram a varredura com o motivo. Ela oferece um candidato, com os valores que
encontrou como tags candidatas, todas **Somente leitura**:

| Formato | Tags candidatas |
| --- | --- |
| CSV | Uma por coluna, lendo a última linha, com o nome do cabeçalho (pelo número onde o cabeçalho não dá nome ou dá o mesmo nome duas vezes), com o tipo dado pelos valores das primeiras linhas: Double quando todo valor é um número, Boolean quando todos são true ou false, String nos outros casos. Um código com zero na frente, como `0412`, continua String. |
| Texto livre | A última linha, uma String. |
| JSON, XML | Uma por valor, com nome e endereço dados pelo caminho, no máximo 500; uma lista JSON oferece os primeiros 20 itens, e o percurso desce 8 níveis. |
| Todo formato | Os dados do arquivo: **O arquivo existe**, **Tamanho do arquivo**, **Última alteração**, **Nome do arquivo** e **Contagem de linhas**. |

Uma varredura oferece no máximo 500 valores, as colunas de um arquivo CSV incluídas. Uma varredura
cortada ali diz isso na linha que a encerra e acima dos seus resultados:
"A varredura de result.json parou antes. Uma varredura oferece no máximo 500 valores: acrescente os outros como tags pela coluna, pelo caminho JSON ou pelo caminho XML."

O candidato de um arquivo digitado recebe o nome do arquivo (`run` para `run.csv`), ou o da pasta para
um nome com parte de data ou uma pasta de entrada. Um candidato cuja pasta, nome e **Ler de** um
dispositivo do driver já lê (o dispositivo varrido, ou outro igual) aparece como **Já configurado**: o
cartão dele lista só os valores que nenhuma tag daquele dispositivo lê ainda, marcados, e
**Acrescentar tags**, antes de **Abrir**, acrescenta os marcados àquele dispositivo, somente leitura. O
resto do comportamento da varredura está em [Descoberta](connector-discovery).

A própria página de um dispositivo faz o mesmo sem a página do driver: **Descobrir tags**, no cabeçalho do cartão **Tags** dele, lê o arquivo daquele dispositivo como ele está salvo e oferece só os valores para os quais ele ainda não tem tag (veja [Descobrir as tags de um dispositivo](connector-discovery#discovering-a-devices-tags)).

## Exemplo: o CSV diário de uma máquina de ensaio {#example-a-test-machines-daily-csv}

Uma máquina de tração grava um CSV por dia em `C:\TestMachine\Logs`, chamado `Log_2026-10-03.csv`, com
uma linha de cabeçalho `Sample;Force;Elongation` e uma linha como `0412;12,5;3,1` depois de cada
amostra. Leia-o pelo caminho simples:

1. Na página do driver, **Acrescentar dispositivo**; dê o nome `Tensile tester`.
2. No cartão **Pasta e arquivo** informe **Caminho da pasta** `C:\TestMachine\Logs` e
   **Nome do arquivo** `Log_{yyyy-MM-dd}.csv`; mantenha **Um arquivo** e **CSV e texto em colunas**.
   O cartão mostra "Hoje: Log_2026-10-03.csv", e quando o dispositivo o lê,
   "Lendo agora: Log_2026-10-03.csv". Deixe o cartão **Texto do arquivo** em
   **Detectar pelo arquivo**: ele encontra o ponto e vírgula e a vírgula decimal.
3. Na página do driver, escolha `Tensile tester` em **Arquivo a varrer** e **Descobrir**. O candidato
   aparece **Já configurado** e lista `Sample` (String, mantendo o zero de `0412`), `Force` e
   `Elongation` (Double), e os dados do arquivo. **Acrescentar tags**.

Cada tag lê a última linha; **Última alteração** muda a cada amostra nova, e é assim que uma ação do
Logic sabe que uma chegou. À meia-noite o dispositivo passa para o arquivo do dia seguinte, e até a
máquina gravá-lo, os valores ficam sem leitura e **O arquivo existe** lê falso. Um agente faz o mesmo
com as ferramentas:

```
device_upsert name="Tensile tester" driver=File fileFolder="C:\TestMachine\Logs" fileName="Log_{yyyy-MM-dd}.csv" fileFormat=Delimited
device_discover driver=File fileDevice="Tensile tester"
tag_upsert device="Tensile tester" name=Force address=Force opcUaType=Double
tag_upsert device="Tensile tester" name=Sample address=Sample opcUaType=String
tag_upsert device="Tensile tester" name="Last change" fileSource=Modified
```

## Exemplo: uma pasta de entrada de arquivos de resultado JSON {#example-an-inbox-of-json-result-files}

Uma célula de ensaio deixa um arquivo de resultado por amostra em `C:\Results\Inbox`, como
`Test_0413.json` com `{"sample":"0413","result":{"force":12.5,"ok":true}}`:

1. **Acrescentar dispositivo**; dê o nome `Results`, **Caminho da pasta** `C:\Results\Inbox`,
   **Ler de** **Pasta de entrada**, **Arquivos a ler** `Test_*.json`, **Formato do arquivo** **JSON**.
2. **Acrescentar tag** `Force`, **Caminho JSON** `result.force`, Double; **Acrescentar tag** `Pass`,
   **Caminho JSON** `result.ok`, Boolean; **Acrescentar tag** `Sample`, **Caminho JSON** `sample`,
   String.
3. **Acrescentar tag** `Source file`, **Lê** **Nome do arquivo**: ela mostra de qual arquivo vieram os
   valores.

Cada arquivo é lido uma vez, depois de ficar parado 1 s e sem nenhum programa o mantendo aberto para
gravar, na ordem em que os arquivos chegaram; cada um é uma leitura própria, datada pela hora do
arquivo; depois que toda tag o leu, ele vai para `C:\Results\Inbox\Processed`. Nada é excluído. Com as
ferramentas:

```
device_upsert name=Results driver=File fileFolder="C:\Results\Inbox" fileName="Test_*.json" fileMode=Inbox fileFormat=Json
tag_upsert device=Results name=Force address=result.force opcUaType=Double
tag_upsert device=Results name=Pass address=result.ok opcUaType=Boolean
tag_upsert device=Results name=Sample address=sample opcUaType=String
tag_upsert device=Results name="Source file" fileSource=Name
```

## Exemplo: acrescentar uma linha para outro programa {#example-appending-a-line-for-another-program}

Outro programa lê `D:\Records\run.csv`, uma linha por segundo com a hora e a pressão:

1. **Acrescentar dispositivo**; dê o nome `Run log`, **Caminho da pasta** `D:\Records`,
   **Nome do arquivo** `run.csv`.
2. No cartão **Escrita** ligue **Permitir escrita** e informe **Texto do cabeçalho** `Time;Pressure`.
3. **Acrescentar tag** `Line`, Double, **Acesso** **Somente escrita**, **Uma escrita**
   **Acrescentar uma linha**, **Modelo de linha** `{datetime};{value:0.00}`.

Escrever 12.5 em `Line` acrescenta `2026-10-03 14:05:12;12.50`, com a vírgula onde o arquivo já usa
uma ou onde **Separador decimal** diz **Vírgula decimal (12,5)**; um arquivo que a escrita cria recebe
`Time;Pressure` primeiro. Escritas que vêm uma atrás da outra são todas mantidas, em ordem. Para
gravar um arquivo por execução, acrescente uma tag `File`, **Lê** **Nome do arquivo**,
**Leitura e escrita**: o Logic escreve o número de série com `.csv` quando uma execução começa, e as
linhas vão para esse arquivo. Com as ferramentas:

```
device_upsert name="Run log" driver=File fileFolder="D:\Records" fileName=run.csv fileFormat=Delimited fileWrites=true fileHeaderText="Time;Pressure"
tag_upsert device="Run log" name=Line opcUaType=Double accessType=WriteOnly fileWriteMode=AppendLine fileLineTemplate="{datetime};{value:0.00}"
tag_upsert device="Run log" name=File fileSource=Name accessType=ReadAndWrite
```

## Ferramentas do agente {#agent-tools}

`driver_capabilities` descreve este driver em `file`: o caminho simples, cada campo do dispositivo, a
regra da pasta e o confinamento a ela, as formas do nome do arquivo, os dois jeitos de ler, os formatos
com a gramática de endereço de cada um, as origens e os tipos delas, as configurações de texto, como
leituras e escritas se comportam, a descoberta e três exemplos completos. `device_upsert driver=File`
aceita `fileFolder`, `fileName`, `fileMode` (`SingleFile`, o padrão, ou `Inbox`), `fileFormat`
(`Delimited`, o padrão, `Text`, `Json` ou `Xml`), `fileEncoding` (`Automatic`, `Utf8` ou
`Windows1252`), `fileSeparator` (`Automatic`, `Semicolon`, `Comma` ou `Tab`), `fileDecimal`
(`Automatic`, `Point` ou `Comma`), `fileHeaderRow` (de 0 a 1000), `fileWrites`, e com a escrita ligada
`fileHeaderText` e `fileLineEnd` (`Automatic`, `CrLf` ou `Lf`); um dispositivo que ele devolve traz
`file`, com `fileStatus`, o que o driver em execução encontrou: o arquivo em uso, se ele existe, a
codificação, os separadores e o fim de linha que leu, e os arquivos aguardando numa pasta de entrada.
`tag_upsert` aceita `fileSource` (`Value`, `WholeFile`, `Exists`, `Size`, `Modified`, `Name` ou
`Lines`), `fileRow` (`Last`, `Number` ou `Matching`), `fileRowNumber`, `fileKeyColumn`,
`fileMatchText`, `fileWriteMode` (`AppendLine` ou `ReplaceFile`) e `fileLineTemplate`; a coluna ou o
caminho é o `address`, um valor de texto livre usa os `valueExtraction`, `valueStart`, `valueLength`,
`valueSeparator`, `valueField` e `valuePattern` do driver genérico, e uma tag nova é somente leitura e
recebe o tipo próprio da origem, a menos que `opcUaType` diga outra coisa. `device_discover driver=File`
lê ou `fileDevice`, o nome de um dispositivo do driver, ou `fileFolder`, `fileName`, `fileMode` e
`fileFormat` digitados para a varredura; as tags que faltam a um dispositivo configurado são
acrescentadas com `tag_upsert`. `connector_browse` devolve `fileFolder`, `fileName`, `fileMode` e
`fileFormat` de cada dispositivo. As outras ferramentas estão em
[Ferramentas do agente](agent-tools).

## Limites que vale conhecer {#limits-worth-knowing}

- Pastas de trabalho do Excel não são lidas: uma pasta de trabalho é lida depois que o programa dela a
  salva como CSV.
- O driver nunca exclui um arquivo. Uma pasta de entrada move o que leu para `Processed`, e só o
  arquivo temporário de uma substituição que falhou é removido.
- "O arquivo mais novo da pasta" não é um jeito de ler: ele perde arquivos que chegam juntos e pode
  mostrar os valores da amostra anterior. Uma máquina que grava um arquivo por amostra é lida por uma
  pasta de entrada.
- Um valor não é mudado no lugar dentro de um arquivo (uma célula de um CSV, um membro do JSON de outro
  programa): uma escrita acrescenta uma linha ou substitui o arquivo inteiro, porque dois programas
  gravando o mesmo arquivo podem perder a mudança um do outro.
- Um compartilhamento de rede é acessado com as permissões do Windows da conta em que a estação roda:
  o dispositivo não guarda usuário nem senha, então o compartilhamento precisa deixar essa conta
  entrar (para ler, e para gravar e mover num dispositivo que escreve ou numa pasta de entrada).
- O driver nunca mexe em nada fora da pasta dele: um nome que aponta para outro lugar é recusado onde
  é digitado e onde é escrito.
- O arquivo é olhado a cada leitura: uma mudança é vista na leitura seguinte, nunca no instante em que
  o outro programa a grava.
- Um campo de CSV que contém uma quebra de linha não é lido, e uma tag JSON, XML ou de arquivo inteiro
  lê no máximo 4 MiB.
