Eccoci dunque arrivati a trattare le procedure/funzioni che interagiscono con il file system, ovvero che ci permetto nella fattispecie di creare/scrivere/leggere/cancellare un file.
Bisogna ricordare, che il tipo del puntatore alla struttura che descrive un file, sotto
AmigaDOS e` un BPTR (e non come potrebbe pensare qualcuno FILE *), ovvero una longword.
Perche` essendo un tempo programmato in BCPL, tutti i puntatori dovevano essere lw.
Vediamo dunque le procedure/funzioni che vedremo in questa puntata:
BPTR Open( STRPTR name, long accessMode );
LONG Close( BPTR file );
LONG Read( BPTR file, APTR buffer, long length );
LONG Write( BPTR file, APTR buffer, long length );
BPTR Input( void );
BPTR Output( void );
LONG Seek( BPTR file, long position, long offset );
LONG DeleteFile( STRPTR name );
LONG Rename( STRPTR oldName, STRPTR newName );
BPTR Lock( STRPTR name, long type ); void UnLock( BPTR lock );
BPTR DupLock( BPTR lock );
LONG Info( BPTR lock, struct InfoData *parameterBlock );
BPTR CreateDir( STRPTR name );
BPTR CurrentDir( BPTR lock );
LONG IoErr( void );
BPTR ParentDir( BPTR lock );/* Buffered File I/O */
BPTR SelectInput( BPTR fh );
BPTR SelectOutput( BPTR fh );
LONG FGetC( BPTR fh );
LONG FPutC( BPTR fh, long ch );
LONG FRead( BPTR fh, APTR block, unsigned long blocklen, unsigned long number );
LONG FWrite( BPTR fh, APTR block, unsigned long blocklen, unsigned long number );
STRPTR FGets( BPTR fh, STRPTR buf, unsigned long buflen );
LONG FPuts( BPTR fh, STRPTR str );
LONG Flush( BPTR fh );
Il primo blocco, sono funzioni non bufferizzate, il secondo blocco, sono funzioni bufferizzate.
Vediamole con ordine. Prima di tutto la Open, che ovviamente richiede il nome del file da aprire e la modalita` di accesso. Notare che un file, una volta aperto puo` indifferentemente letto o scritto a piacimento. Le varie modalita` sono:
MODE_OLDFILE Apre un file esistente posizionandosi all'inizio
MODE_NEWFILE Crea un file (cancellando quello vecchio) con lock esclusivo
MODE_READWRITE Apre un file esistente con un lock condiviso. Crea il file se non esiste.
Una volta aperto un file, possiamo leggerlo con la Read, scriverlo con la Write e chiuderlo con la Close. Possiamo anche utilizzare le procedure bufferizzate, a seconda dei nostri scopi.
Vediamo uno stralcio di programma:
#include <exec/types.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <proto/dos.h>
struct DosLibrary *DOSBase;
void main(void)
{
BPTR file;
struct Mia
{
int ver;
char data[6];
}mia;
if((DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",0)))
{
if((file = Open("RAM:temp",MODE_NEWFILE)))
{
mia.uno = 56;
strcpy(mia.due,"290798");
if(Write(file,&mia,sizeof(struct Mia) == -1)
PrintFault(IoErr(),"Impossibile scrivere sul file RAM:temp perche`");
Delay(50);
if(Read(file,&mia,sizeof(struct Mia) == -1)
PrintFault(IoErr(),"Impossibile leggere dal file RAM:temp perche`");
else
{
LONG param[2];
param[0] = (LONG)mia.ver;
param[1] = (long)mia.data;
VPrintf("Ho letto %ld e %s\n",param);
}
/* Se la versione e >= 36 possiamo controllare anche il valore di */
/* ritorno della Close */
if(DOSBase -> dl_lib.lib_Version >= 36)
{
if(!Close(file))
PrintFault(IoErr(),"Impossibile chiudere il file RAM:temp perche`");
}
else
Close(file);
}
else
{
PrintFault(IoErr(),"Impossibile aprire il file RAM:temp perche`");
}
CloseLibrary(struct Library *)DOSBase);
}
}
La funzione Seek, e` molto utile con i file di record, per saltare ad un determinato record ed eseguire quindi un accesso non sequenziale al file.
Per esempio, se il nostro file RAM:temp, contenesse dieci strutture di tipo Mia, per leggere la 5 basterebbe:
[...]
Seek(file,sizeof(struct Mia) * 4,OFFSET_BEGINNING);
Ovviamente, 4 e non 5 perche` con il valore zero si torna all'inizio del file.
Il terzo parametro puo` assumere i seguenti valori (come la fseek di unix):
OFFSET_BEGINNING spiazzamento relativo all'inizio del file
OFFSET_CURRENT spiazzamento relativo alla posizione attuale
OFFSET_END spiazzamento relativo alla fine del file
In questo modo possiamo saltare al terz'ultimo record di un file, oppure saltare ai prossimi cinque record, ai tre precedenti o altro, specificando anche valori negativi (che fanno tornare indietro il puntatore alla posizione).
Inutile dire che questi spiazzamenti devo essere fatti tutti all'interno del file, altrimenti non funzioneranno e saremo piazzati o all'inizio o alla fine del file.
Le funzioni Input, Output, SelectInput e SelectOutput, servono le prime due per ricevere il puntatore al file di standard input e standard output e le seconde due per impostarli su file di nostro interesse.
Per esempio, se nel nostro programma, avessimo chiamato:
[...]BPTR old_fh;
[...]
old_fh = SelectOutput(file);
[...]
SelectOutput(old_fh);
[...]
avremmo rediretto l'output del nostro programma sul file RAM:temp.
Una cosa del genere, puo` essere utile per creare file di log, per esempio.
Le funzioni DeleteFile e Rename servono per cancellare un file od una directory (a patto che sia vuota) e per rinominare un file od una directory.
Le funzioni Lock e la sua corrispettiva UnLock, servono per bloccare e sbloccare l'accesso ad altri processi ad un file che stiamo manipolando.
Le modalita` accettate dalla Lock sono:
ACCESS_READ crea un lock condiviso (altri processi possono leggere) ACCESS_WRITE crea un lock esclusivo (nessun processo puo` accedere)
LA funzione DupLock, serve per ottenere una copia di un lock (solo quelli condivisi).
Puo` essere utile in un sistema di produttori/consumatori.
La funzione Info, molto semplicemente restituisce una struttura
/* returned by Info(), must be on a 4 byte boundary */
struct InfoData {
LONG id_NumSoftErrors; /* number of soft errors on disk */
LONG id_UnitNumber; /* Which unit disk is (was) mounted on */
LONG id_DiskState; /* See defines below */
LONG id_NumBlocks; /* Number of blocks on disk */
LONG id_NumBlocksUsed; /* Number of block in use */
LONG id_BytesPerBlock;
LONG id_DiskType; /* Disk Type code */
BPTR id_VolumeNode; /* BCPL pointer to volume node */
LONG id_InUse; /* Flag, zero if not in use */
}; /* InfoData */
riempita con i valori del dispositivo che contiene il file passatole (il BPTR).
La funzione CreateDir serve per creare un cassetto.
Le funzioni CurrentDir e ParentDir, servono per ottenere la directory contenente il lock passato o il cassetto genitore.
Bene, nell'ottava puntata vedremo altre procedure della dos.library e nella nona, cominceremo a vedere intuition. Ovviamente, se avete qualcosa da chiedermi, sono a vostra disposizione.