2011-05-30 4 views
4

jusqu'à présent, chaque fois que je voulais créer un fichier sans écraser un existant, je l'ai fait quelque chose comme ceci:Comment créer un fichier enregistré sans écraser un fichier existant?

if not FileExists(filename) then 
    stream := TFileStream.Create(filename, fmCreate); 

Mais ce n'est pas threadsafe. Alors maintenant je cherche une version threadsafe.

Peut-être que je peux combiner certains modes de sorte que TFileStream.Create(filename, fmCreate +fm???); échoue si le fichier existe?

J'ai besoin de cela pour communiquer les verrous de répertoire avec les anciens programmes DOS. Mais les programmes DOS ne contiennent pas les fichiers ouverts. :-(

+0

-ce que les programmes DOS doivent verrouiller le fichier aussi? faire la Et nous ne parlons pas thread-safe d'application Delphi ne fera pas thread-safe programmes DOS. sur les threads, mais sur les processus ici. Etes-vous sûr que vous avez affaire à des programmes DOS, pas à des programmes en ligne de commande Win32? Pour être certain que nous vous fournissons une solution de travail, nous aurons besoin d'en savoir plus sur la partie "Programmes DOS" de votre ordinateur. chitecture: comment fonctionnent-ils? quelle application verrouille le répertoire? quel genre de machine d'état utilisez-vous pour le verrouillage? –

+0

quel est ce DOS dont vous parlez? Courez-vous sur Windows 98? –

+0

@David, AFAIK vous pouvez exécuter des programmes DOS sur toutes les versions 32 bits de Windows, y compris Windows 7 32 bits; Pas besoin de Windows 98! –

Répondre

7

constructeur de base nom de fichier TFileStream repose sur l'API WIndows appel CreateFile pour créer le descripteur de fichier qui va être utilisé pour accéder au fichier. l'API a lui-même plusieurs paramètres, et surtout intéressant pour vous est le Créer Disposition: si vous spécifiez CREATE_NEW, la fonction échoue si le fichier existe déjà Vous pouvez en profiter en appelant vous-même CreateFile, puis en utilisant la poignée renvoyée pour créer le TFileStream. Vous pouvez le faire car TFileStream hérite de THandleStream, hérite de son constructeur basé sur la poignée et possède le handle (appelle CloseHandle sur le handle que vous transmettez au constructeur).

Puisque ce repose sur la fonction fournie OS-CreateFile, il sera trehad-safe (aucune condition de course entre FileExists() et créer réellement le fichier. Il bloque également l'ancienne application d'accéder au nouveau fichier crearted jusqu'à ce que vous en fait à proximité la poignée.

var FH: NativeUInt; 

// ... 

    FH := CreateFile('FileName', GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_NEW, 0, 0); 
    if FH = INVALID_HANDLE_VALUE then 
    begin 
    // Creating the new file failed! I'm raizing an exception, but you can do something 
    // better-suited for your case, like trying a new file name. 
    RaiseLastOSError; 
    end; 
    // Create the stream using the prepared Handle 
    HS := TFileStram.Create(FH); 
+0

C'est la solution la plus élégante pour implémenter une création de fichier inter-processus. Mais j'ai découvert que la question était confuse: à quoi servent ces "programmes DOS"? Comment fonctionne le verrouillage? Votre solution ne fonctionnera pas avec les programmes DOS, mais seulement avec les programmes Win32 Delphi. –

+0

@ A.Bouchez, je m'attendrais à ce que la solution fonctionne aussi avec les programmes DOS, car cela se produirait au niveau de l'OS; Malheureusement, je n'ai plus aucune trace d'un programme DOS à tester! –

+0

@Cosmin L'API CreateFile est une API Win32, pas une API DOS. Si les programmes DOS attendent simplement que le * fichier de verrouillage * soit présent sur le disque et créé par Delphi, puis relâchez le verrou en supprimant le fichier, cela fonctionnera. Mais si le programme DOS doit également verrouiller le fichier, il ne fonctionnera pas s'il ne suit pas le même schéma que votre appel CreateFile. C'est pourquoi j'ai demandé plus de détails sur ces "programmes DOS" ... –

4

Je garderais le contrôle FileExists car il gère la plupart des cas sans compter sur la gestion des exceptions.Pour les cas de frontière, vous devez gérer les exceptions dans TFileStream constructeur correctement.Le deuxième thread essayant de créer le fichier devrait échouer si vous l'utiliser avec le mode de partage fmShareDenyWrite.

Questions connexes