# File

> I valori che un altro programma scrive in un file di una cartella locale o di rete (il CSV di una macchina di prova, il registro di un datalogger, un risultato in JSON o XML) letti come tag, e righe o file interi scritti per un altro programma: le schede Cartella e file, Testo del file e Scrittura, cosa legge un tag in ogni formato, la cartella di arrivo, la scansione che propone un tag per colonna o per campo, tre esempi completi e cosa il driver non fa.

Il driver **File** legge i valori che un altro programma scrive in un file: il CSV a cui una macchina
di prova aggiunge una riga dopo ogni campione, il registro di un datalogger, un file di risultato in
JSON o XML, un file di testo che contiene solo un codice di lotto. Ogni tag legge un valore del file, e
i suoi valori arrivano dove arrivano quelli di ogni altro tag: in Logic, sulle dashboard, nelle prove di
un banco di collaudo di [Process](process). Dove il dispositivo lo consente, il driver scrive anche per
un altro programma: una riga aggiunta a un file, oppure un file intero sostituito.

La lettura è l'uso principale, e chiede tre risposte: la cartella, il file e il suo formato. Il modo in
cui si legge il testo del file (la codifica, il separatore di colonna, il separatore decimale) viene
letto dal file stesso finché resta su rilevare, la scansione propone un tag per colonna o per campo, e
ogni tag nasce in sola lettura. Ciò che riguarda la scrittura compare solo dopo che la scrittura è stata
attivata per il dispositivo.

Un dispositivo di questo driver è una cartella e il file che vi legge: due file della stessa cartella
sono due dispositivi. La cartella è un'unità e una cartella (`C:\TestMachine\Logs`) oppure una
condivisione di rete e una cartella al suo interno (`\\lab-pc\results`), e la stazione la raggiunge con
i permessi Windows dell'account con cui gira. I dispositivi stanno sotto il driver e possono essere
archiviati in cartelle, **Driver → Cartella → Dispositivo → Tag**, come sotto ogni driver senza linea
seriale né broker.

## La pagina del driver {#the-drivers-page}

La riga sotto l'intestazione dice « Ogni dispositivo legge un file, oppure i file che arrivano in una cartella. Aggiungere un dispositivo, inserire la cartella, il file e il formato, poi scansionarlo per aggiungerne i valori come tag. »
Per Configurare il connector, la pagina porta la scheda Ambito della scansione propria del driver, con
il file che la scansione legge (vedi [Rilevamento](#discovery)). Sotto si trova la tabella
**Dispositivi** di ogni driver (vedi [La tabella dei dispositivi](connector-drivers#the-device-table)),
che cresce con **Aggiungi dispositivo**, a destra del suo titolo; vuota, dice « Nessun dispositivo. » La
barra del driver porta **Rileva**, in grigio finché la scheda Ambito della scansione non è completa. Il
driver sta sotto **File e database**, la categoria che si trova tra Web e API e Prove in ogni elenco di
driver.

## Dispositivo {#device}

Un dispositivo di questo driver non ha la scheda Connessione: al suo posto c'è la scheda
**Cartella e file**, seguita dalla scheda **Testo del file** e, su un dispositivo che legge un solo
file, dalla scheda **Scrittura**. L'**Intervallo di interrogazione (ms)** della scheda Dispositivo, 1000
per impostazione predefinita, dice ogni quanto i tag leggono il file, e ogni tag può sostituirlo come in
ogni driver.

Un dispositivo nuovo non ha una cartella: dice « Cartella non ancora inserita », la sua pagina dice « La stazione non legge questo dispositivo finché non ha una cartella, quindi non ne viene ancora letto nulla e non c'è alcun errore da mostrare. Inserire la cartella nella scheda Cartella e file qui sotto e la stazione inizia a leggerlo. »
e non viene letto nulla finché la cartella non è inserita. L'URI di base che mostra l'intestazione è
l'indirizzo di esecuzione, con la cartella e il nome scritti in forma di URI, e dopo di loro ciò che non
è su rilevare:
`file://single?folder=C%3A%5CTestMachine%5CLogs&name=Log_%7Byyyy-MM-dd%7D.csv&format=delimited`, oppure
`file://inbox?...` per una cartella di arrivo.

### La scheda Cartella e file {#the-folder-and-file-card}

| Campo | Significato | Predefinito |
| --- | --- | --- |
| **Percorso della cartella** | « Un'unità e una cartella, oppure una condivisione di rete. La cartella si raggiunge con i permessi Windows dell'account con cui gira la stazione. » La casella mostra `C:\TestMachine\Logs` come suggerimento. | vuoto |
| **Nome del file** | Su un dispositivo che legge un solo file: « Un nome all'interno della cartella. Le parti tra parentesi graffe sono la data e l'ora della stazione: Log_{yyyy-MM-dd}.csv è un file nuovo ogni giorno. » Una sottocartella della cartella può far parte del nome (`results\last.csv`). | vuoto |
| **File da leggere** | La stessa casella su una cartella di arrivo: « I file da leggere, direttamente nella cartella: * sta per qualsiasi sequenza di caratteri e ? per uno solo, come Test_*.csv. » | vuoto |
| **Leggere da** | **Un solo file**: « Il file viene riletto ogni volta che cambia. Un file che cresce viene letto da dove si è fermata l'ultima lettura. » **Cartella di arrivo**: « Ogni nuovo file viene letto una volta, in ordine di arrivo, e spostato nella sottocartella Processed. Non viene eliminato nulla. » | **Un solo file** |
| **Formato del file** | **CSV e testo a colonne**, **Testo libero**, **JSON** o **XML**: come un tag trova il suo valore nel file (vedi [Indirizzamento del tag](#tag-addressing)). | **CSV e testo a colonne** |

Un nome con una parte di data si scrive tra parentesi graffe con un formato .NET di data e ora,
sull'orologio della stazione: `Log_{yyyy-MM-dd}.csv` è `Log_2026-10-03.csv` oggi e il file del giorno
dopo passata la mezzanotte, e `Data_{yyyy-MM}.txt` cambia ogni mese. Sotto la casella, la scheda mostra
quale file è adesso: « Oggi: Log_2026-10-03.csv ». Le parentesi graffe raddoppiate `{{` e `}}` sono
parentesi del nome. Una parte di data non scrive mai i due punti, che nessun nome di file ammette:
`{HH-mm}`, non `{HH:mm}`.

Quando il dispositivo è in funzione, la scheda dice quale file legge:

| La scheda dice | Quando |
| --- | --- |
| « In lettura ora: Log_2026-10-03.csv » | Il file in uso, come il dispositivo lo legge adesso. |
| « In lettura ora: Log_2026-10-03.csv (non ancora presente) » | Il file non esiste ancora: i suoi tag attendono e il dispositivo resta online. |
| « Un tag ha scritto questo nome. Dopo un riavvio il dispositivo torna a leggere il file configurato. » | Un tag che legge il nome del file è stato scritto e punta il dispositivo su un altro file (vedi [Scrittura](#writing)). |
| « 3 file in attesa nella cartella di arrivo » | Una cartella di arrivo, con i file che corrispondono al suo pattern ancora da leggere (« 1 file in attesa nella cartella di arrivo » per uno solo). |

Un'impostazione che la scheda non può accettare viene indicata sotto le schede, e il dispositivo non
viene salvato finché non è corretta:

| Si inserisce | La scheda dice |
| --- | --- |
| Una cartella che non è un percorso completo, come `Logs` | « La cartella è un percorso completo: un'unità e una cartella (C:\Test), oppure una condivisione di rete e una cartella al suo interno (\\server\tests). » |
| Una cartella con un carattere che nessun nome di cartella ammette, oppure una condivisione senza cartella al suo interno (`\\server`) | « La cartella contiene un carattere che nessun nome di cartella ammette, oppure è una condivisione di rete senza una cartella al suo interno. » |
| Nessun nome di file | Nessun rifiuto: il dispositivo viene salvato e attende, « Nome del file non ancora inserito » (« File da leggere non ancora inseriti » su una cartella di arrivo), finché non si inserisce un nome. |
| Un percorso completo come nome, come `C:\Logs\last.csv` | « Il nome del file è un nome all'interno della cartella, non un percorso completo: la cartella va nella casella Percorso della cartella. » |
| Un nome con `..`, come `..\other\last.csv` | « Il nome del file esce dalla cartella con "..". Il driver non lascia mai la sua cartella. » |
| Un nome con `:` o un altro carattere che nessun nome di file ammette, oppure una parte che termina con un punto o uno spazio | « Il nome del file contiene un carattere che nessun nome di file ammette (come : o \|), oppure una sua parte termina con un punto o uno spazio. Una parte di data non deve scrivere i due punti: usare {HH-mm}, non {HH:mm}. » |
| Un nome che Windows riserva a un dispositivo, come `CON` o `COM1` | « Windows riserva questo nome a un dispositivo (CON, NUL, COM1 e simili). Sceglierne un altro. » |
| `*` o `?` su un dispositivo che legge un solo file | « Solo il pattern di una cartella di arrivo accetta * o ?. Indicare il nome di un solo file, oppure leggere da una cartella di arrivo. » |
| Una sottocartella nel pattern di una cartella di arrivo | « Una cartella di arrivo è la cartella stessa: mettere la sottocartella nella casella Percorso della cartella e lasciare qui solo il pattern. » |
| Una parte di data non chiusa, o che non è un formato di data | « Una parte di data del nome non è chiusa o non è un formato di data. Scriverla tra parentesi graffe, come Log_{yyyy-MM-dd}.csv. » |

Il salvataggio rispetta le stesse regole, e il registro delle azioni lo dice quando ne rifiuta una:
« Il dispositivo 'Tensile tester' ha un'impostazione di file che il suo driver non può usare. Aprirlo e correggere il campo che il pannello segnala. »

### La scheda Testo del file {#the-text-of-the-file-card}

Come si leggono i caratteri, le colonne e i numeri del file. Ogni impostazione parte da
**Rilevare dal file**, e il driver la legge dal file in uso. Sotto un'impostazione lasciata così, dopo
che il dispositivo ha letto il file, una riga dice cosa ha trovato, come « Trovato nel file: UTF-8 ».
Ogni impostazione si può fissare scegliendola, per un file le cui prime righe non lo dicono.

| Campo | Mostrato | Scelte | Predefinito |
| --- | --- | --- | --- |
| **Codifica** | sempre | **Rilevare dal file**, `UTF-8`, `Windows-1252 (ANSI)` (la codifica dei vecchi programmi Windows) | **Rilevare dal file** |
| **Separatore di colonna** | CSV | **Rilevare dal file**, **Punto e virgola (;)**, **Virgola (,)**, **Tabulazione** | **Rilevare dal file** |
| **Separatore decimale** | sempre | **Rilevare dal file**, **Punto decimale (12.5)**, **Virgola decimale (12,5)** | **Rilevare dal file** |
| **Riga di intestazione** | CSV | Da 0 a 1000: « La riga che contiene i nomi delle colonne, contata da 1. 0 se il file non ne ha. » Le righe che la precedono vengono saltate. | 1 |

| Impostazione | Cosa legge il rilevamento |
| --- | --- |
| Codifica | Un indicatore dell'ordine dei byte all'inizio del file, che prevale su qualsiasi scelta; altrimenti UTF-8 quando i byte sono UTF-8 valido; altrimenti Windows-1252. |
| Separatore di colonna | Il primo tra tabulazione, punto e virgola e virgola che divide le prime righe nello stesso numero di colonne; una prima riga che non ne contiene nessuno è un file di una sola colonna. |
| Separatore decimale | La virgola quando più numeri del file hanno una virgola che un punto tra le cifre; altrimenti il punto. I numeri JSON hanno sempre il punto; l'impostazione vale per i numeri scritti come testo. |

### La scheda Scrittura {#the-writing-card}

Un dispositivo che legge un solo file porta la scheda **Scrittura**; una cartella di arrivo viene solo
letta e non ce l'ha.

| Campo | Mostrato | Significato | Predefinito |
| --- | --- | --- | --- |
| **Consentire la scrittura** | sempre | Disattivato: « Il dispositivo legge soltanto. Attivare la scrittura per aggiungere righe, sostituire il file o passare a un altro file mentre la stazione è in funzione. » Attivato: « I tag di questo dispositivo possono scrivere nel file. Ogni tag continua a leggere soltanto finché il suo accesso non dice altro. » | disattivato |
| **Testo di intestazione** | scrittura attiva, CSV o testo libero | « Scritto per primo in un file creato da una scrittura, come Time;Pressure. » Una riga, senza a capo. | vuoto |
| **Fine riga** | scrittura attiva | **Rilevare dal file** (quella del file stesso, CR LF in un file nuovo), **CR LF, come su Windows** o **LF**. | **Rilevare dal file** |

La scrittura si disattiva solo quando nessun tag del dispositivo scrive più. Finché qualche tag scrive,
l'interruttore resta disegnato e in grigio, e dice perché: « 2 tag di questo dispositivo scrivono nel file. Impostarli in sola lettura prima di disattivare la scrittura. »
(« Un tag di questo dispositivo scrive nel file. Impostarlo in sola lettura prima di disattivare la scrittura. » per uno solo).

### Online, in attesa e offline {#online-waiting-and-offline}

| Situazione | Cosa fanno il dispositivo e i suoi tag |
| --- | --- |
| Nessuna cartella inserita | Il dispositivo attende: « Cartella non ancora inserita », punto grigio, nulla letto e nessun errore. |
| Cartella inserita, nessun nome di file | Il dispositivo attende: « Nome del file non ancora inserito », punto grigio, nulla letto e nessun errore; la sua pagina dice « La stazione non legge questo dispositivo finché non ha un nome di file, quindi non ne viene ancora letto nulla e non c'è alcun errore da mostrare. Inserire il nome del file nella scheda Cartella e file qui sotto e la stazione inizia a leggerlo. » |
| Cartella di arrivo, cartella inserita, nessun file da leggere | Il dispositivo attende: « File da leggere non ancora inseriti », punto grigio, nulla letto e nessun errore; la sua pagina dice « La stazione non legge questo dispositivo finché non sa quali file leggere, quindi non ne viene ancora letto nulla e non c'è alcun errore da mostrare. Inserire i file in File da leggere, nella scheda Cartella e file qui sotto (come Test_*.csv), e la stazione inizia a leggerli. » |
| La cartella non si raggiunge (una condivisione ferma, un'unità sparita, un account senza accesso) | Il dispositivo è offline e i suoi tag falliscono la lettura; la cartella viene guardata di nuovo al massimo ogni secondo, e il dispositivo si connette appena torna. |
| La cartella si raggiunge, il file non esiste ancora | Il dispositivo resta online. I tag che leggono valori non hanno lettura e attendono; **Il file esiste** legge falso. |
| Un altro programma tiene il file senza condividerlo | Nessuna lettura questa volta; la lettura successiva riprova. Il tag mantiene la sua ultima lettura, e una più vecchia del suo intervallo di interrogazione più 10 s conta come lettura fallita, come in ogni driver. |
| Un valore non c'è, o non entra nel tipo del tag | Lettura fallita di quel tag, con il motivo; il dispositivo continua a leggere gli altri tag. |

## Indirizzamento del tag {#tag-addressing}

### Cosa legge un tag {#what-a-tag-reads}

Un tag di questo driver non ha una casella di indirizzo propria: la sua scheda **Sorgente** chiede cosa
legge e, per un valore, dove si trova il valore nel formato del dispositivo.

| **Legge** | Cosa mostra il tag | Tipo di dato |
| --- | --- | --- |
| **Valore** | Un valore all'interno del file, trovato con i campi del formato del dispositivo più sotto. | Boolean, Int32, Int64, Float, Double o String; Double per un tag nuovo |
| **File intero** | Tutto il contenuto, senza i fine riga finali: un file che contiene solo un codice di lotto o uno stato. Al massimo 4 MiB. | gli stessi; String per un tag nuovo |
| **Il file esiste** | Se il file in uso esiste adesso. | Boolean |
| **Dimensione del file** | La dimensione del file in byte. | Int64 |
| **Ultima modifica** | Quando il file è stato scritto l'ultima volta: vederla cambiare è il modo in cui Logic sa che sono arrivati dati nuovi. | DateTime |
| **Nome del file** | Il nome del file in uso, all'interno della cartella. Scritto, indica un altro file (vedi [Scrittura](#writing)). | String |
| **Numero di righe** | « Conta tutte le righe del file, comprese la riga di intestazione e le righe vuote. » | Int64 |

Un tipo con cui la sorgente non si legge viene rifiutato con quelli con cui si legge: « Scegliere uno dei tipi di dato con cui questo si legge: Int64. »
Scegliere un'altra sorgente porta il suo tipo. Il testo preso da un file si legge nel tipo del tag come
il [driver Generic serial and TCP](driver-generic-serial-tcp#tag-addressing) legge un messaggio, con il
separatore decimale del file: un Boolean legge `1`, `true`, `on` o `yes` e `0`, `false`, `off` o `no`,
un intero legge un numero intero, e uno String prende i caratteri come sono, così un codice come `0412`
mantiene lo zero iniziale solo come String.

Ogni tag nasce in **Sola lettura**, e su un dispositivo che non consente la scrittura il campo
**Accesso** non offre altro. Quando il dispositivo consente la scrittura, un tag che legge **Valore** o
**File intero** può essere in **Lettura e scrittura** o in **Sola scrittura**, e un tag che legge
**Nome del file** in **Lettura e scrittura**; i dati del file (esistenza, dimensione, ultima modifica,
numero di righe) non si scrivono mai: « Un dato del file non si può scrivere. Lasciare il tag in sola lettura. »

### CSV e testo a colonne {#csv-and-text-in-columns}

| Campo | Mostrato | Significato | Predefinito |
| --- | --- | --- | --- |
| **Colonna** | Legge Valore | « Il nome della colonna nella riga di intestazione, oppure il suo numero contato da 1. » Un testo di sole cifre è un numero; un nome ignora maiuscole e minuscole e gli spazi attorno. Su un file senza riga di intestazione: « Il numero della colonna, contato da 1. Il file non ha una riga di intestazione, quindi le sue colonne non hanno nome. » | vuoto |
| **Riga da leggere** | Legge Valore | **Ultima**, **Per numero** o **Per contenuto**. « Le righe si contano dopo la riga di intestazione. Per contenuto legge l'ultima riga la cui colonna chiave contiene il valore chiave. » | **Ultima** |
| **Numero di riga** | Per numero | La riga di dati, contata da 1 dopo l'intestazione. | vuoto |
| **Colonna chiave** | Per contenuto | La colonna il cui valore sceglie la riga, per nome o per numero. | vuoto |
| **Valore chiave** | Per contenuto | Il valore che la colonna chiave contiene nella riga da leggere, come `0412`. | vuoto |

Un campo tra virgolette doppie può contenere il separatore; un campo che contiene un a capo non viene
letto. Un tag i cui campi non possono funzionare non viene salvato, e la sua pagina dice cosa manca:

| Si lascia o si inserisce | La pagina del tag dice |
| --- | --- |
| Nessuna colonna | « Inserire la colonna, con il suo nome nella riga di intestazione o con il suo numero. » |
| La colonna 0 | « Le colonne si contano da 1. » |
| Una colonna per nome su un file senza riga di intestazione | « Il file non ha una riga di intestazione, quindi una colonna si indica con il suo numero. » |
| Per numero, senza numero di riga | « Inserire il numero, contato da 1. » |
| Per contenuto, senza colonna chiave | « Inserire la colonna chiave: la colonna il cui valore sceglie la riga. » |
| Per contenuto, senza valore chiave | « Inserire ciò che contiene la riga. » |

La riga in sola lettura **Indirizzo di origine (bus)** mostra cosa riceve il driver: `column?name=Force`
per il Force dell'ultima riga, `column?number=3&row=number&rowNumber=5` per la terza colonna della
quinta riga, `column?name=Force&row=match&key=Sample&equals=0412` per la riga del campione 0412.

### Testo libero {#free-text}

| Campo | Mostrato | Significato | Predefinito |
| --- | --- | --- | --- |
| **Riga da leggere** | Legge Valore | **Ultima** (l'ultima riga non vuota), **Per numero** o **Per contenuto**. « Le righe si contano dall'inizio del file. Per contenuto legge l'ultima riga che contiene il testo. » | **Ultima** |
| **Numero di riga** | Per numero | La riga, contata da 1 dall'inizio del file. | vuoto |
| **La riga contiene** | Per contenuto | Un testo che la riga da leggere contiene, come `Result`. | vuoto |
| **Il valore è** | Legge Valore | « Le stesse scelte del driver Generic serial and TCP: l'intera riga, una posizione fissa, un campo tra separatori o un'espressione regolare. » Le scelte sono quelle di quel driver, con la prima chiamata come la riga: **L'intera riga**, **Posizione fissa** (**Primo carattere** e **Lunghezza**), **Campo tra separatori** (**Separatore** e **Numero del campo**) e **Gruppo di cattura di un pattern** (**Pattern di ricerca**). | **L'intera riga** |

Posizioni e campi si contano da 1, un pattern è un'espressione regolare .NET con esattamente un gruppo
di cattura attorno al valore, e una riga che richiede più di 250 ms per essere letta non viene letta. I
rifiuti sono quelli del driver generico stesso, come « Indicare il primo carattere del valore, contando da 1. » o « Il pattern deve avere esattamente un gruppo di cattura, attorno al valore. »
L'indirizzo di bus si scrive `line` seguito da ciò che si applica, per esempio
`line?row=match&contains=Result&extract=regex&pattern=...`.

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

| Campo | Formato | Significato |
| --- | --- | --- |
| **Percorso JSON** | JSON | « Membri separati da punti e posizioni tra parentesi quadre a partire da 0, come result.force o items[0].value. » Un membro il cui nome contiene un punto si scrive `['flow.rate']`. |
| **Percorso XML** | XML | « Elementi dalla radice separati da barre, una posizione a partire da 1 dove un elemento si ripete, e un attributo alla fine, come Result/Force o Result/@unit. » I nomi si confrontano per nome locale, ignorando il prefisso dello spazio dei nomi. |

Un numero JSON, `true` o `false` si prende così com'è, e una stringa si legge nel tipo del tag; un
oggetto o una lista si leggono solo come String, il loro JSON. Un documento JSON o XML si legge intero
quando è cambiato, al massimo 4 MiB, e non viene letta alcuna DTD. L'indirizzo di bus è
`json?path=result.force` o `xml?path=Result%2FForce`.

| Si lascia o si inserisce | La pagina del tag dice |
| --- | --- |
| Nessun percorso | « Inserire il percorso del valore. Per leggere il file intero, scegliere File intero. » |
| Un percorso JSON che non si legge | « Questo non è un percorso JSON: membri separati da punti e posizioni tra parentesi quadre, come result.items[0].value. » |
| Un percorso XML che non si legge | « Questo non è un percorso XML: elementi separati da barre, una posizione come Item[2] e un attributo alla fine, come @unit. » |

## Lettura {#reading}

A ogni lettura il driver chiede a Windows la dimensione e le date del file, il che funziona anche su una
condivisione di rete, dove gli avvisi di modifica di Windows non funzionano, e apre il file solo quando
una di esse è cambiata. Lo apre sempre condividendo lettura, scrittura ed eliminazione, così il
programma che scrive il file non viene mai bloccato.

| Il file | Cosa fa la lettura |
| --- | --- |
| È cresciuto, e comincia e finisce ancora dove lo faceva | Si legge solo ciò che è stato aggiunto, mai di nuovo l'intero file: un registro di molti megabyte costa quanto le sue righe nuove. |
| È diventato più corto, è stato riscritto o ricreato | Riletto dall'inizio. |
| Termina con una riga che nessun fine riga chiude ancora | Quella riga attende, così un valore non viene mai letto scritto a metà; quando il file è rimasto 2 s senza cambiare, viene letta come ultima riga. |
| JSON, XML, o un tag che legge il file intero | Letto intero quando è cambiato, al massimo 4 MiB; un documento che non si legge mentre è cambiato da meno di 2 s viene considerato ancora in scrittura, e i tag attendono. |
| Ha una riga di più di 1 MiB | Non è testo in righe: i suoi tag falliscono la lettura. |

Ogni lettura è datata con l'ultima modifica del file, non con il momento in cui è stata fatta, così il
registro della prova colloca un campione quando l'altro programma lo ha scritto.

## La cartella di arrivo {#the-inbox-folder}

**Leggere da** **Cartella di arrivo** serve per la macchina che scrive un file per campione
(`Test_0412.json`, `Test_0413.json`...): ogni nuovo file che corrisponde al pattern viene letto una
volta, in ordine di arrivo.

| Passo | Cosa succede |
| --- | --- |
| Arriva un file | Viene preso dopo essere rimasto 1 s con la stessa dimensione e la stessa data e senza che alcun programma lo tenga aperto per scriverlo. |
| Quale per primo | Quello creato per primo, poi quello scritto per primo, poi per nome. Due file che arrivano insieme vengono letti in due passate: nessuno viene saltato. |
| La sua lettura | Ogni tag del dispositivo legge quel file, e il file è una lettura, datata con la data del file: il registro della prova le registra tutte. **Nome del file** dice da quale file vengono i valori. |
| Quando ogni tag lo ha letto | Viene spostato nella sottocartella `Processed`, che il driver crea e il cui nome è lo stesso in ogni lingua, perché altri programmi possono cercarla; un nome già occupato lì diventa `name (2).json`. I suoi valori restano la lettura dei tag fino al file successivo. |
| Uno spostamento che fallisce | Ritentato a ogni lettura; il file non viene riletto nel frattempo. |
| La stazione si riavvia prima dello spostamento | Il file viene riletto: una lettura contata due volte piuttosto che una persa. |

Non viene mai eliminato nulla: la sottocartella `Processed` cresce finché qualcuno non la svuota. In
una cartella di arrivo non si scrive mai.

## Scrittura {#writing}

Su un dispositivo che legge un solo file e consente la scrittura, un tag che legge **Valore** o
**File intero** e il cui accesso scrive dice cosa fa una scrittura:

| Campo | Mostrato | Significato | Predefinito |
| --- | --- | --- | --- |
| **Una scrittura** | il tag scrive | **Aggiungere una riga**: « Aggiunge una riga alla fine del file. Ogni scrittura conta: nessuna viene scartata per una più recente. » **Sostituire il file**: « Sostituisce l'intero file con il valore, tramite un file temporaneo, così nessun programma lo legge scritto a metà. » | **Aggiungere una riga** |
| **Modello di riga** | Aggiungere una riga | « Vuoto: il valore scritto è l'intera riga. {value} è il valore, {datetime} il momento della scrittura, ciascuno con un formato dopo i due punti se serve, come {value:0.00}. » La casella mostra `{datetime};{value}` come suggerimento. | vuoto |

| Il modello | Scrivere 12.5 aggiunge |
| --- | --- |
| vuoto | `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}` accetta un formato numerico .NET, `{datetime:FORMAT}` un formato .NET di data e ora,
sull'orologio della stazione, `yyyy-MM-dd HH:mm:ss` quando non ne viene dato nessuno. Un numero si scrive
con il separatore decimale del file, così lo stesso modello scrive `12,50` in un file che usa la
virgola. Il modello di un tag Boolean può omettere `{value}`: scritto a vero, aggiunge la riga, come un
comando. Un modello che il driver non riesce a riempire viene rifiutato sulla pagina del tag:

| Si inserisce | La pagina del tag dice |
| --- | --- |
| Una parte che non è né `{value}` né `{datetime}`, o una parentesi non chiusa | « Il modello di riga accetta {value} e {datetime}, ciascuno con un formato dopo i due punti se serve. {{ e }} sono parentesi graffe della riga. » |
| Nessun `{value}` su un tag che non è Boolean | « Il modello di riga non contiene {value}, quindi il valore scritto non arriverebbe mai nel file. Solo un tag booleano può ometterlo: scritto a vero, aggiunge la riga. » |
| Un a capo | « Il modello di riga è una sola riga, senza a capo. » |
| Un tag che scrive, su un dispositivo che non consente la scrittura | « Il dispositivo non consente la scrittura. Attivare la scrittura nel dispositivo oppure lasciare il tag in sola lettura. » |

| Una scrittura | Come avviene |
| --- | --- |
| Aggiungere una riga | La riga parte in una sola scrittura e viene scaricata sul disco prima che la scrittura conti come fatta. Un file che la scrittura crea riceve per primo il **Testo di intestazione**, e un file la cui ultima riga non ha un fine riga ne riceve prima uno, così la riga è intera. Un valore che contiene un a capo viene rifiutato. Ogni scrittura conta: una scrittura che attende ancora nella coda del dispositivo non viene mai scartata per una più recente verso lo stesso tag, come non lo è mai un comando. |
| Sostituire il file | Il valore va in un file temporaneo accanto al file, scaricato sul disco, che prende il posto del file in un solo passo. Un valore più recente che attende ancora sostituisce uno più vecchio, come per qualsiasi setpoint. |
| Il nome del file | Un tag che legge **Nome del file**, in **Lettura e scrittura**, scritto con un altro nome, punta il dispositivo su quel file della stessa cartella da quel momento: « Scrivere qui un nome fa sì che il dispositivo legga e scriva da quel momento quel file della stessa cartella. Un nome fuori dalla cartella viene rifiutato. » Un percorso completo, `..`, `:` o un nome che Windows riserva viene rifiutato. Quando il dispositivo si riconnette, riavvio compreso, torna a leggere il file configurato. |
| Testo | Nella codifica, nel fine riga e nel separatore decimale del file stesso, letti dal file dove il dispositivo li lascia su rilevare. Un file nuovo è UTF-8 senza indicatore dell'ordine dei byte, con CR LF e il punto decimale, salvo che il dispositivo dica altro. |
| Risposta | Fatta, oppure rifiutata con la causa: il dispositivo non consente la scrittura, l'account non ha il permesso, il file è contrassegnato come di sola lettura (togliere quell'attributo lascia passare la scrittura successiva), il disco è pieno, oppure il file è aperto in un altro programma. Una sostituzione è rifiutata finché un programma qualsiasi ha il file aperto, un'aggiunta di riga solo finché un programma lo tiene senza condividerlo; non appena quel programma chiude il file, la scrittura successiva riesce. |

La cartella e le sottocartelle a cui punta un nome vengono create quando una scrittura ne ha bisogno,
sempre all'interno della cartella del dispositivo.

## Rilevamento {#discovery}

### La scheda Ambito della scansione {#the-scan-scope-card}

Per Configurare il connector, la pagina del driver porta la sua scheda **Ambito della scansione**,
sotto la riga
« Legge un file e propone un tag per ogni colonna o campo che trova, e per i dati del file. Scegliere un dispositivo per leggerne il file, oppure scrivere una cartella, un file e un formato. »

| Campo | Significato | Predefinito |
| --- | --- | --- |
| **File da scansionare** | **Un file scritto qui**, oppure un dispositivo del driver per nome. Il file di un dispositivo si legge con le impostazioni del dispositivo come sono salvate, e una modifica del dispositivo che attende ancora di essere salvata viene salvata prima. | **Un file scritto qui** |
| **Percorso della cartella** | Un file scritto: la cartella, come su un dispositivo. | vuoto |
| **Nome del file** o **File da leggere** | Un file scritto: il nome, oppure il pattern di una cartella di arrivo. | vuoto |
| **Leggere da** | Un file scritto: **Un solo file** o **Cartella di arrivo**. | **Un solo file** |
| **Formato del file** | Un file scritto: il formato. Ogni impostazione di testo di un file scritto viene rilevata, compresa la riga di intestazione: la prima riga è un'intestazione quando nessuno dei suoi campi è un numero e la riga successiva ne ha uno. | **CSV e testo a colonne** |

Ciò che manca ancora all'ambito viene detto in rosso sotto la scheda, e Rileva resta in grigio finché non
è completo:

| L'ambito | La scheda dice |
| --- | --- |
| Un file scritto senza cartella | « Scrivere la cartella in cui si trova il file. » |
| Una cartella scritta che non è un percorso completo | « 'Logs' non è una cartella che questa stazione può leggere. Scrivere un percorso completo, per esempio C:\Test o \\server\tests. » |
| Un nome scritto che non è un file della cartella | « '..\last.csv' non è il nome di un file all'interno della cartella. » |
| Un dispositivo che non esiste più | « Il dispositivo scelto per la scansione non esiste più. Scegliere un altro file da scansionare. » |
| Un dispositivo senza la sua cartella o il suo file | « Il dispositivo 'Tensile tester' non ha ancora una cartella o un file, oppure ha un'impostazione che il suo driver non può usare. Completare prima la sua scheda Cartella e file. » |

Quando il dispositivo da scansionare ha una modifica che non si può salvare, la scansione non parte:
« Il rilevamento non è partito perché non è stato possibile salvare la modifica del dispositivo da scansionare. »

### Cosa offre la scansione {#what-the-scan-offers}

La scansione legge il file che un dispositivo di un solo file legge adesso, oppure il file più recente
di una cartella di arrivo, che non sposta; un file che non c'è, una cartella che non si raggiunge e un
documento che non si legge chiudono la scansione con il motivo. Propone un candidato, con i valori
trovati come tag candidati, tutti in **Sola lettura**:

| Formato | Tag candidati |
| --- | --- |
| CSV | Uno per colonna, che legge l'ultima riga, con il nome dalla sua intestazione (con il suo numero dove l'intestazione non gli dà un nome o lo dà due volte), tipizzato secondo i valori delle sue prime righe: Double quando ogni valore è un numero, Boolean quando ognuno è true o false, String altrimenti. Un codice con uno zero iniziale, come `0412`, resta uno String. |
| Testo libero | L'ultima riga, uno String. |
| JSON, XML | Uno per valore, con nome e indirizzo dati dal suo percorso, al massimo 500; una lista JSON propone i suoi primi 20 elementi, e il percorso scende di 8 livelli. |
| Ogni formato | I dati del file: **Il file esiste**, **Dimensione del file**, **Ultima modifica**, **Nome del file** e **Numero di righe**. |

Una scansione offre al massimo 500 valori, colonne di un file CSV comprese. Una scansione interrotta
lì lo dice nella riga che la chiude e sopra i suoi risultati:
« La scansione di result.json si è fermata prima. Una scansione offre al massimo 500 valori: aggiungere gli altri come tag tramite la colonna, il percorso JSON o il percorso XML. »

Il candidato di un file scritto prende il nome del file (`run` per `run.csv`), oppure quello della
cartella per un nome con una parte di data o una cartella di arrivo. Un candidato la cui cartella, il cui
nome e il cui **Leggere da** un dispositivo del driver legge già (il dispositivo scansionato, o un altro
uguale) è segnato **Già configurato**: la sua scheda elenca solo i valori che nessun tag di quel
dispositivo legge ancora, spuntati, e **Aggiungi i tag**, prima di **Apri**, aggiunge quelli spuntati a
quel dispositivo, in sola lettura. Il resto del comportamento della scansione è in
[Rilevamento](connector-discovery).

La pagina stessa di un dispositivo fa lo stesso senza la pagina del suo driver: **Rileva tag**, nell'intestazione della sua scheda **Tag**, legge il file di quel dispositivo così com'è salvato e offre solo i valori per cui non ha ancora un tag (vedere [Rilevare i tag di un dispositivo](connector-discovery#discovering-a-devices-tags)).

## Esempio: il CSV giornaliero di una macchina di prova {#example-a-test-machines-daily-csv}

Una macchina di trazione scrive un CSV al giorno in `C:\TestMachine\Logs`, chiamato
`Log_2026-10-03.csv`, con una riga di intestazione `Sample;Force;Elongation` e una riga come
`0412;12,5;3,1` dopo ogni campione. Leggerlo con il percorso semplice:

1. Nella pagina del driver, **Aggiungi dispositivo**; chiamarlo `Tensile tester`.
2. Nella scheda **Cartella e file** inserire **Percorso della cartella** `C:\TestMachine\Logs` e
   **Nome del file** `Log_{yyyy-MM-dd}.csv`; mantenere **Un solo file** e **CSV e testo a colonne**. La
   scheda mostra « Oggi: Log_2026-10-03.csv », e quando il dispositivo lo legge,
   « In lettura ora: Log_2026-10-03.csv ». Lasciare la scheda **Testo del file** su
   **Rilevare dal file**: trova il punto e virgola e la virgola decimale.
3. Nella pagina del driver, scegliere `Tensile tester` in **File da scansionare** e **Rileva**. Il
   candidato è **Già configurato** ed elenca `Sample` (String, che mantiene lo zero di `0412`), `Force`
   ed `Elongation` (Double), e i dati del file. **Aggiungi i tag**.

Ogni tag legge l'ultima riga; **Ultima modifica** cambia a ogni nuovo campione, ed è così che un'azione
di Logic sa che ne è arrivato uno. A mezzanotte il dispositivo passa al file del giorno dopo, e finché la
macchina non lo scrive, i valori non hanno lettura e **Il file esiste** legge falso. Un agente fa lo
stesso con gli strumenti:

```
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
```

## Esempio: una cartella di arrivo di file di risultato JSON {#example-an-inbox-of-json-result-files}

Una cella di prova deposita un file di risultato per campione in `C:\Results\Inbox`, come
`Test_0413.json` che contiene `{"sample":"0413","result":{"force":12.5,"ok":true}}`:

1. **Aggiungi dispositivo**; chiamarlo `Results`, **Percorso della cartella** `C:\Results\Inbox`,
   **Leggere da** **Cartella di arrivo**, **File da leggere** `Test_*.json`, **Formato del file**
   **JSON**.
2. **Aggiungi tag** `Force`, **Percorso JSON** `result.force`, Double; **Aggiungi tag** `Pass`,
   **Percorso JSON** `result.ok`, Boolean; **Aggiungi tag** `Sample`, **Percorso JSON** `sample`,
   String.
3. **Aggiungi tag** `Source file`, **Legge** **Nome del file**: mostra da quale file vengono i valori.

Ogni file viene letto una volta, dopo essere rimasto fermo 1 s senza che alcun programma lo tenga aperto
per scriverlo, nell'ordine in cui i file sono arrivati; ognuno è una lettura a sé, datata con la data
del file; quando ogni tag lo ha letto, passa in `C:\Results\Inbox\Processed`. Non viene eliminato nulla.
Con gli strumenti:

```
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
```

## Esempio: aggiungere una riga per un altro programma {#example-appending-a-line-for-another-program}

Un altro programma legge `D:\Records\run.csv`, una riga al secondo con l'ora e la pressione:

1. **Aggiungi dispositivo**; chiamarlo `Run log`, **Percorso della cartella** `D:\Records`,
   **Nome del file** `run.csv`.
2. Nella scheda **Scrittura** attivare **Consentire la scrittura** e inserire **Testo di intestazione**
   `Time;Pressure`.
3. **Aggiungi tag** `Line`, Double, **Accesso** **Sola scrittura**, **Una scrittura**
   **Aggiungere una riga**, **Modello di riga** `{datetime};{value:0.00}`.

Scrivere 12.5 su `Line` aggiunge `2026-10-03 14:05:12;12.50`, con la virgola dove il file ne usa già una
o dove **Separatore decimale** dice **Virgola decimale (12,5)**; un file che la scrittura crea riceve per
primo `Time;Pressure`. Le scritture che si susseguono rapidamente vengono tutte mantenute, in ordine. Per
scrivere un file per prova, aggiungere un tag `File`, **Legge** **Nome del file**, in
**Lettura e scrittura**: Logic scrive il numero di serie seguito da `.csv` quando inizia una prova, e le
righe vanno in quel file. Con gli strumenti:

```
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
```

## Strumenti dell'agente {#agent-tools}

`driver_capabilities` descrive questo driver sotto `file`: il percorso semplice, ogni campo del
dispositivo, la regola della cartella e il confinamento in essa, le forme del nome del file, i due modi
di leggere, i formati con la grammatica di indirizzo di ciascuno, le sorgenti e i loro tipi, le
impostazioni di testo, il comportamento di letture e scritture, il rilevamento e tre esempi completi.
`device_upsert driver=File` accetta `fileFolder`, `fileName`, `fileMode` (`SingleFile`, il predefinito,
o `Inbox`), `fileFormat` (`Delimited`, il predefinito, `Text`, `Json` o `Xml`), `fileEncoding`
(`Automatic`, `Utf8` o `Windows1252`), `fileSeparator` (`Automatic`, `Semicolon`, `Comma` o `Tab`),
`fileDecimal` (`Automatic`, `Point` o `Comma`), `fileHeaderRow` (da 0 a 1000), `fileWrites` e, con la
scrittura attiva, `fileHeaderText` e `fileLineEnd` (`Automatic`, `CrLf` o `Lf`); un dispositivo che
restituisce porta `file`, con `fileStatus`, ciò che il driver in funzione ha trovato: il file in uso, se
esiste, la codifica, i separatori e il fine riga che ha letto, e i file in attesa in una cartella di
arrivo. `tag_upsert` accetta `fileSource` (`Value`, `WholeFile`, `Exists`, `Size`, `Modified`, `Name` o
`Lines`), `fileRow` (`Last`, `Number` o `Matching`), `fileRowNumber`, `fileKeyColumn`,
`fileMatchText`, `fileWriteMode` (`AppendLine` o `ReplaceFile`) e `fileLineTemplate`; la colonna o il
percorso è l'`address`, un valore di testo libero prende `valueExtraction`, `valueStart`,
`valueLength`, `valueSeparator`, `valueField` e `valuePattern` del driver generico, e un tag nuovo è in
sola lettura e prende il tipo proprio della sorgente, salvo che `opcUaType` dica altro.
`device_discover driver=File` legge `fileDevice`, il nome di un dispositivo del driver, oppure
`fileFolder`, `fileName`, `fileMode` e `fileFormat` scritti per la scansione; i tag che mancano a un
dispositivo configurato si aggiungono con `tag_upsert`. `connector_browse` restituisce `fileFolder`,
`fileName`, `fileMode` e `fileFormat` di ogni dispositivo. Gli altri strumenti sono in
[Strumenti dell'agente](agent-tools).

## Limiti da conoscere {#limits-worth-knowing}

- Le cartelle di lavoro di Excel non vengono lette: una cartella di lavoro si legge dopo che il suo
  programma l'ha salvata come CSV.
- Il driver non elimina mai un file. Una cartella di arrivo sposta ciò che ha letto in `Processed`, e
  solo il file temporaneo di una sostituzione fallita viene mai rimosso.
- « Il file più recente della cartella » non è un modo di leggere: perde i file che arrivano insieme e
  può mostrare i valori del campione precedente. Una macchina che scrive un file per campione si legge
  con una cartella di arrivo.
- Un valore non viene cambiato sul posto all'interno di un file (una cella di un CSV, un membro del JSON
  di un altro programma): una scrittura aggiunge una riga o sostituisce l'intero file, perché due
  programmi che scrivono lo stesso file possono perdere l'uno la modifica dell'altro.
- Una condivisione di rete si raggiunge con i permessi Windows dell'account con cui gira la stazione: il
  dispositivo non conserva né utente né password, quindi la condivisione deve far entrare
  quell'account (per leggere, e per scrivere e spostare su un dispositivo che scrive o una cartella di
  arrivo).
- Il driver non tocca mai nulla fuori dalla sua cartella: un nome che punta altrove viene rifiutato dove
  viene inserito e dove viene scritto.
- Il file viene guardato a ogni lettura: una modifica si vede alla lettura successiva, mai nell'istante
  in cui l'altro programma la scrive.
- Un campo CSV che contiene un a capo non viene letto, e un tag JSON, XML o di file intero legge al
  massimo 4 MiB.
