Passa al contenuto principale

Se avete mai provato a utilizzare programmi basati su POSIX per elaborare file strutturati VOS, potreste aver riscontrato alcune limitazioni o osservato comportamenti che non avete compreso. In questo post cercherò di spiegare cosa succede.

VOS supporta 4 tipi di file: sequenziali, relativi, fissi e stream. I primi 3 formati sono chiamati file "strutturati" perché il file system tiene traccia dei confini dei record. Le operazioni I/O disponibili leggono e scrivono interi record. L'ultimo formato è chiamato "non strutturato" perché i confini dei record sono impliciti; il carattere di nuova riga delimita i record. Le operazioni I/O disponibili leggono e scrivono sequenze di byte.

Un ambiente conforme allo standard POSIX, come quello presente nei sistemi Unix® o Linux©, ha un solo tipo di file nativo, denominato "file regolare". L'organizzazione dei file stream VOS è equivalente a quella dei file regolari POSIX.

L'ambiente di runtime VOS POSIX classifica tutti e 4 i tipi di file come file regolari POSIX. Quindi, almeno in teoria, qualsiasi programma POSIX può leggere o scrivere uno qualsiasi dei 4 tipi di file. Tuttavia, non è così semplice.

Poiché l'API POSIX definisce tutte le operazioni di I/O in termini di sequenze di byte, mentre VOS definisce le operazioni di I/O (su file strutturati) in termini di sequenze di record, il runtime VOS POSIX media la differenza bufferizzando il record corrente nello spazio utente, eseguendo le operazioni di I/O POSIX sul buffer e quindi riscrivendo il record bufferizzato nei punti appropriati.

Se il programma POSIX conosce la dimensione di ciascun record (ad esempio, per un file fisso) e se legge e scrive il numero esatto di byte, la presenza del buffer non influisce sull'operazione e la mappatura dei due tipi di operazioni I/O è facile da comprendere ed efficiente.

Ma se il programma POSIX si limita a leggere o scrivere un flusso di byte senza tener conto della dimensione del record sottostante, allora la mappatura della semantica POSIX alla semantica VOS, sebbene ben definita, non è generalmente molto utile e spesso risulta piuttosto inefficiente. Alcune operazioni, come la ricerca di una posizione di byte o la riscrittura di una sequenza di byte che si estende oltre il confine di un record, sono nel migliore dei casi inefficienti e nel peggiore dei casi impossibili.

C'è poi la questione della gestione dei caratteri di nuova riga.

Sia i file regolari POSIX che i file stream VOS utilizzano il carattere di nuova riga per distinguere i confini dei record. Tuttavia, i record VOS nei file strutturati in genere non contengono caratteri di nuova riga. Ad esempio, quando un editor VOS (ad esempio edit, emacs o line_edit) crea un nuovo file sequenziale, ogni record contiene una riga di testo. Ma il record non termina con un carattere di nuova riga. Per convenzione, tutti i programmi presumono che un file sequenziale contenente testo abbia un carattere di nuova riga implicito alla fine di ogni record. Lo stesso vale per i file relativi e fissi. Ma ecco un punto importante: nessun attributo di alcun file (VOS, Unix, strutturato o non strutturato) registra se il file contiene testo o dati binari. La distinzione è lasciata ai programmi che accedono al file.

Questa situazione crea una sorta di dilemma per il runtime VOS POSIX. Esso deve sapere se un file strutturato VOS contiene testo o dati per poter decidere se aggiungere o meno un carattere di nuova riga a ciascun record. Se il file contiene testo, deve aggiungere un carattere di nuova riga. Se contiene dati, non deve aggiungere alcun carattere di nuova riga.

La risposta è che il runtime VOS POSIX dipende dal chiamante per fornire queste informazioni. Per impostazione predefinita, il runtime POSIX tratta i file strutturati come se contenessero testo e aggiunge un carattere di nuova riga; un chiamante può richiedere esplicitamente questo comportamento fornendo la modalità di apertura O_TEXT. Un chiamante che desidera trattare un file strutturato VOS come contenente dati deve fornire la modalità di apertura O_BINARY. Queste due modalità sono mutuamente esclusive; se si specifica una delle due, non è possibile specificare l'altra. Queste modalità non sono necessarie per i file di flusso e quindi in questo caso vengono ignorate.

Per gli esperti di linguaggi che stanno leggendo questo post, vorrei sottolineare che sia O_TEXT che O_BINARY sono estensioni dello standard POSIX; non sono definiti dallo standard POSIX stesso. In genere sono presenti solo su sistemi operativi che distinguono tra file di testo e file binari (come VOS) o che hanno una convenzione speciale di fine riga (come Windows, che utilizza CR-LF).

Per politica aziendale, quando Stratus software basato su POSIX su OpenVOS, lo modifichiamo per escludere l'uso di file FIXED e RELATIVE e limitiamo i file SEQUENTIAL all'accesso in sola lettura. Partiamo inoltre dal presupposto che tutti i file sequenziali contengano testo. In base alla nostra esperienza, queste regole rendono pratico l'uso di file STREAM o SEQUENTIAL come input per i programmi POSIX, evitando al contempo le inefficienze intrinseche nel tentativo di eseguire operazioni orientate ai byte su file di output SEQUENTIAL.

In sintesi, l'approccio migliore consiste nell'utilizzare esclusivamente file STREAM (per input o output) e file SEQUENTIAL (solo per input di testo) con programmi basati su POSIX. Se si dispone di dati binari in un file strutturato, scrivere un piccolo programma per copiarli in un file stream, quindi utilizzare la versione stream del file con i programmi POSIX. Se si dispone di dati di testo in un file FIXED o RELATIVE che si desidera elaborare con programmi POSIX, copiare prima il file in un file STREAM.