Creazione e apertura di file

La funzione CreateFile può creare un nuovo file o aprire un file esistente. È necessario specificare il nome del file, le istruzioni di creazione e altri attributi. Quando un'applicazione crea un nuovo file, il sistema operativo lo aggiunge alla directory specificata.

Scelta dell'API file corretta

Scenario API consigliata Note
Lettura e scrittura semplice dei file in C/C++ fopen / fread / fwrite (CRT) o C++ std::ifstream/std::ofstream Portabile, gestisce automaticamente il buffering. Sufficiente per la maggior parte delle operazioni di I/O dei file a livello di applicazione.
Modifica ed enumerazione del percorso dei file C++17 std::filesystem C++, portatile e moderno. Usare per l'attraversamento della directory, le operazioni di percorso e i metadati di base dei file.
I/O sovrapposto (asincrono) CreateFile con FILE_FLAG_OVERLAPPED Necessario per le porte di completamento I/O, i server ad alte prestazioni e le operazioni sui file non bloccanti.
Condivisione o blocco con granularità fine CreateFile con dwShareMode Solo CreateFile fornisce il controllo sull'accesso simultaneo ai file tra processi.
File mappati alla memoria CreateFile + CreateFileMapping Obbligatorio per la memoria condivisa, l'accesso casuale a file di grandi dimensioni e la comunicazione tra processi.
Dispositivi, pipe, caselle postali o console CreateFile Le API della libreria standard e CRT non supportano questi tipi di oggetto Win32.
.NET applicazioni gestite System.IO.File / System.IO.FileStream Preferito per il codice .NET. Usa CreateFile internamente, ma fornisce la gestione degli errori basata su eccezioni e async/await.

Importante

Gestione degli errori: controllare sempre il valore restituito di CreateFile. In caso di errore, restituisce INVALID_HANDLE_VALUE (non NULL). Chiamare GetLastError immediatamente dopo che la chiamata non riesce a ottenere il codice di errore specifico. Gli errori comuni includono ERROR_FILE_NOT_FOUND, ERROR_ACCESS_DENIEDe ERROR_SHARING_VIOLATION.

Note

Problema comune: dwShareMode: l'impostazione di dwShareMode su 0 (accesso esclusivo) è sicura, ma può causare ERROR_SHARING_VIOLATION se un altro processo ha già aperto il file. Per i file di log o i file che altri processi possono leggere contemporaneamente, usare FILE_SHARE_READ. Evitare FILE_SHARE_WRITE a meno che non si disponga di un meccanismo di coordinamento: le scritture simultanee non coordinate possono danneggiare il contenuto dei file.

Uso dei file nell'applicazione

Il sistema operativo assegna un identificatore univoco, denominato handle, a ogni file aperto o creato tramite CreateFile. Un'applicazione può usare questo handle con funzioni che leggono, scrivono e descrivono il file. È valido fino a quando non vengono chiusi tutti i riferimenti a tale handle. All'avvio di un'applicazione, eredita tutti gli handle aperti dal processo che lo ha avviato se gli handle sono stati creati come ereditabili.

Un'applicazione deve controllare il valore dell'handle restituito da CreateFile prima di tentare di usare l'handle per accedere al file. Se si verifica un errore, il valore dell'handle verrà INVALID_HANDLE_VALUE e l'applicazione può usare la funzione GetLastError per informazioni estese sull'errore.

Quando un'applicazione usa CreateFile, deve usare il parametro dwDesiredAccess per specificare se intende leggere dal file, scrivere nel file, leggere e scrivere o nessuno dei due. Questa operazione è nota come richiesta di una modalità di accesso. L'applicazione deve anche usare il parametro dwCreationDisposition per specificare l'azione da eseguire se il file esiste già, noto come disposizione di creazione. Ad esempio, un'applicazione può chiamare CreateFile con dwCreationDisposition impostata su CREATE_ALWAYS per creare sempre un nuovo file, anche se esiste già un file con lo stesso nome (sovrascrivendo così il file esistente). L'esito positivo o negativo dipende da fattori come gli attributi e le impostazioni di sicurezza del file precedente (vedere le sezioni seguenti per altre informazioni).

Un'applicazione usa anche CreateFile per specificare se vuole condividere il file per la lettura, la scrittura, entrambe o nessuna delle due. Questa operazione è nota come modalità di condivisione. Non è possibile aprire di nuovo un file aperto non condiviso (dwShareMode impostato su zero) dall'applicazione che l'ha aperta o da un'altra applicazione fino alla chiusura del relativo handle. Si tratta anche di accesso esclusivo.

Quando un processo usa CreateFile per tentare di aprire un file già aperto in modalità di condivisione (dwShareMode impostato su un valore diverso da zero valido), il sistema confronta le modalità di accesso e condivisione richieste con quelle specificate all'apertura del file. Se si specifica una modalità di accesso o condivisione in conflitto con le modalità specificate nella chiamata precedente, CreateFile ha esito negativo.

La tabella seguente illustra le combinazioni valide di due chiamate a CreateFile usando varie modalità di accesso e modalità di condivisione (rispettivamente dwDesiredAccess, dwShareMode ). Non importa in quale ordine vengono effettuate le chiamate CreateFile . Tuttavia, tutte le operazioni di I/O di file successive su ogni handle di file saranno comunque vincolate dalle modalità di accesso e condivisione correnti associate a tale handle di file specifico.

Prima chiamata a CreateFile Chiamate valide a CreateFile
GENERIC_READ, FILE_SHARE_READ - GENERIC_READ, FILE_SHARE_READ
- GENERIC_READ, FILE_SHARE_READ, FILE_SHARE_WRITE
GENERIC_READ, FILE_SHARE_WRITE - GENERIC_WRITE, FILE_SHARE_READ
- GENERIC_WRITE, FILE_SHARE_READFILE_SHARE_WRITE
GENERIC_READ, FILE_SHARE_READ, FILE_SHARE_WRITE - GENERIC_READ, FILE_SHARE_READ
- GENERIC_READ, FILE_SHARE_READ, FILE_SHARE_WRITE
- GENERIC_WRITE, FILE_SHARE_READ
- GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE
- GENERIC_READGENERIC_WRITE, FILE_SHARE_READ
- GENERIC_READGENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE
GENERIC_WRITE, FILE_SHARE_READ - GENERIC_READ, FILE_SHARE_WRITE
- GENERIC_READ, FILE_SHARE_READ, FILE_SHARE_WRITE
GENERIC_WRITE, FILE_SHARE_WRITE - GENERIC_WRITE, FILE_SHARE_WRITE
- GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE
GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE - GENERIC_READ, FILE_SHARE_WRITE
- GENERIC_READ, FILE_SHARE_READ, FILE_SHARE_WRITE
- GENERIC_WRITE, FILE_SHARE_WRITE
- GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE
- GENERIC_READ, GENERIC_WRITE, FILE_SHARE_WRITE
- GENERIC_READ, GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE
GENERIC_READ, GENERIC_WRITE, FILE_SHARE_READ - GENERIC_READ, FILE_SHARE_READ, FILE_SHARE_WRITE
GENERIC_READ, GENERIC_WRITE, FILE_SHARE_WRITE - GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE
GENERIC_READ, GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE - GENERIC_READ, FILE_SHARE_READ, FILE_SHARE_WRITE
- GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE
- GENERIC_READ, GENERIC_WRITE, FILE_SHARE_READ, FILE_SHARE_WRITE

Oltre agli attributi di file standard, è anche possibile specificare gli attributi di sicurezza includendo un puntatore a una struttura SECURITY_ATTRIBUTES come quarto parametro di CreateFile. Tuttavia, il file system sottostante deve supportare la sicurezza per avere alcun effetto (ad esempio, il file system NTFS lo supporta, ma i vari file system FAT non lo supportano). Per altre informazioni sugli attributi di sicurezza, vedere Controllo di accesso.

Un'applicazione che crea un nuovo file può fornire un handle facoltativo a un file modello, da cui CreateFile accetta attributi di file e attributi estesi per la creazione del nuovo file.

Scenari di CreateFile

Esistono diversi scenari fondamentali per avviare l'accesso a un file usando la funzione CreateFile . Questi sono riepilogati come segue:

  • Creazione di un nuovo file quando un file con tale nome non esiste già.
  • Creazione di un nuovo file anche se esiste già un file con lo stesso nome, cancellando i dati e avviandolo vuoto.
  • Apertura di un file esistente solo se presente e solo intatto.
  • Apertura di un file esistente solo se esistente, troncandolo in modo che sia vuoto.
  • Apertura di un file sempre: così come è se esiste, crearne uno nuovo se non esiste.

Questi scenari sono controllati dall'uso appropriato del parametro dwCreationDisposition . Di seguito è riportata una spiegazione di come questi scenari si collegano ai valori di questo parametro e cosa succede quando vengono utilizzati.

Quando si crea o si apre un nuovo file quando un file con tale nome non esiste già (dwCreationDisposition impostato su CREATE_NEW, CREATE_ALWAYS o OPEN_ALWAYS), la funzione CreateFile esegue le azioni seguenti:

  • Combina gli attributi e i flag di file specificati da dwFlagsAndAttributes con FILE_ATTRIBUTE_ARCHIVE.
  • Imposta la lunghezza del file su zero.
  • Copia gli attributi estesi forniti dal file modello nel nuovo file se viene specificato il parametro hTemplateFile (sostituisce tutti i flag FILE_ATTRIBUTE_* specificati in precedenza).
  • Imposta il flag di ereditarietà specificato dal membro bInheritHandle e dal descrittore di sicurezza specificato dal membro lpSecurityDescriptor del parametro lpSecurityAttributes (struttura SECURITY_ATTRIBUTES ), se specificato.

Quando si crea un nuovo file anche se esiste già un file con lo stesso nome (dwCreationDisposition impostato su CREATE_ALWAYS), la funzione CreateFile esegue le azioni seguenti:

  • Controlla gli attributi del file correnti e le impostazioni di sicurezza per l'accesso in scrittura, fallendo se negato.
  • Combina gli attributi e i flag di file specificati da dwFlagsAndAttributes con FILE_ATTRIBUTE_ARCHIVE e gli attributi di file esistenti.
  • Imposta la lunghezza del file su zero, ovvero tutti i dati presenti nel file non sono più disponibili e il file è vuoto.
  • Copia gli attributi estesi forniti dal file modello nel nuovo file se viene specificato il parametro hTemplateFile (sostituisce tutti i flag FILE_ATTRIBUTE_* specificati in precedenza).
  • Imposta il flag di ereditarietà specificato dal membro bInheritHandle del parametro lpSecurityAttributes (struttura SECURITY_ATTRIBUTES ) se specificato, ma ignora il membro lpSecurityDescriptor della struttura SECURITY_ATTRIBUTES .
  • Se in caso contrario, CreateFile restituisce un handle valido, la chiamata a GetLastError restituirà il codice ERROR_ALREADY_EXISTS, anche se per questo particolare caso d'uso non si tratta effettivamente di un errore come tale (se si intende creare un file "nuovo" (vuoto) al posto di quello esistente.

Quando si apre un file esistente (dwCreationDisposition impostato su OPEN_EXISTING, OPEN_ALWAYS o TRUNCATE_EXISTING), la funzione CreateFile esegue le azioni seguenti:

  • Controlla gli attributi correnti del file e le impostazioni di sicurezza per l'accesso richiesto, fallendo se negato.
  • Combina i flag di file (FILE_FLAG_*) specificati da dwFlagsAndAttributes con gli attributi di file esistenti e ignora gli attributi di file (FILE_ATTRIBUTE_*) specificati da dwFlagsAndAttributes.
  • Imposta la lunghezza del file su zero solo se dwCreationDisposition è impostato su TRUNCATE_EXISTING; in caso contrario, la lunghezza del file corrente viene mantenuta e il file viene aperto così come è.
  • Ignora il parametro hTemplateFile .
  • Imposta il flag di ereditarietà specificato dal membro bInheritHandle del parametro lpSecurityAttributes (struttura SECURITY_ATTRIBUTES ) se specificato, ma ignora il membro lpSecurityDescriptor della struttura SECURITY_ATTRIBUTES .

Attributi e directory dei file

Gli attributi di file fanno parte dei metadati associati a un file o a una directory, ognuno con il proprio scopo e regole su come può essere impostato e modificato. Alcuni di questi attributi si applicano solo ai file e alcuni solo alle directory. Ad esempio, l'attributo FILE_ATTRIBUTE_DIRECTORY si applica solo alle directory: viene usato dal file system per determinare se un oggetto su disco è una directory, ma non può essere modificato per un oggetto file system esistente.

Alcuni attributi di file possono essere impostati per una directory, ma hanno un significato solo per i file creati in tale directory, che fungono da attributi predefiniti. Ad esempio, FILE_ATTRIBUTE_COMPRESSED può essere impostato su un oggetto directory, ma poiché l'oggetto directory stesso non contiene dati effettivi, non viene effettivamente compresso. Tuttavia, le directory contrassegnate con questo attributo indicano al file system di comprimere tutti i nuovi file aggiunti alla directory. Qualsiasi attributo di file che può essere impostato in una directory e verrà impostato anche per i nuovi file aggiunti a tale directory viene definito attributo ereditato.

La funzione CreateFile fornisce un parametro per l'impostazione di determinati attributi di file quando viene creato un file. In generale, questi attributi sono i più comuni per un'applicazione da usare in fase di creazione di file, ma non tutti gli attributi di file possibili sono disponibili per CreateFile. Alcuni attributi di file richiedono l'uso di altre funzioni, ad esempio SetFileAttributes, DeviceIoControl o DecryptFile dopo che il file esiste già. Nel caso di FILE_ATTRIBUTE_DIRECTORY, la funzione CreateDirectory è necessaria in fase di creazione perché CreateFile non può creare directory. Gli altri attributi di file che richiedono una gestione speciale sono FILE_ATTRIBUTE_REPARSE_POINT e FILE_ATTRIBUTE_SPARSE_FILE, che richiedono DeviceIoControl. Per altre informazioni, vedere SetFileAttributes.

Come indicato in precedenza, l'ereditarietà degli attributi dei file si verifica quando viene creato un file con attributi di file letti dagli attributi della directory in cui si trova il file. Nella tabella seguente vengono riepilogati questi attributi ereditati e il modo in cui sono correlati alle funzionalità CreateFile .

Stato dell'attributo della directory Capacità di sovrascrittura dell'ereditarietà di CreateFile per i nuovi file
FILE_ATTRIBUTE_COMPRESSED impostato . Nessun controllo. Usare DeviceIoControl per cancellare.
FILE_ATTRIBUTE_COMPRESSED non impostato. Nessun controllo. Usare DeviceIoControl per impostare.
FILE_ATTRIBUTE_ENCRYPTED impostato. Nessun controllo. Usare DecryptFile.
FILE_ATTRIBUTE_ENCRYPTED non impostato. Può essere impostato usando CreateFile.
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED impostato. Nessun controllo. Usare SetFileAttributes per cancellare.
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED non è impostato. Nessun controllo. Usare SetFileAttributes per impostare.

Controllo dell’accesso

CreateFile

DeviceIoControl

Costanti dell'attributo file

Compressione e decompressione dei file

Crittografia dei file

Funzioni di gestione file

Handle e oggetti

Gestire l'ereditarietà

Apertura di un file per la lettura o la scrittura

SetFileAttributes