Domanda

Nella mia applicazione miei utenti possono importare i file (PDF / xls / doc) a una tabella o esportarli in una cartella. Ora voglio aprire direttamente i file.

Finora sono in grado di: - ottenere un nome univoco - salvare il file blob nel file generato - aprirlo

Il problema è che non so come eliminare (o aggiornare) il file dopo che il file verrà chiuso dall'utente.

Sarò molto felice se qualcuno mi può aiutare su questo:)

Ecco un'istantanea del mio codice:

procedure OpenTemporaryFile(AFileExtension: String; AKey: Integer;
            AMyConnection: TMyConnection);
     Var
       qrDocuments : TMyQuery ;
       TmpName,ExtName: string;
       TempFileName: TFileStream;
    begin
       //Generate an unique tmp file located into user temp folder
       TmpName:=  FileGetTempName('~SI');
       ExtName:= ChangeFileExt(TmpName, AFileExtension);
       //Change files extension so that Shellexecute will be able to open the file
       RenameFile(TmpName,ExtName );
       //Creating the FileStream (data is fetched from an blob field)
       TempFileName := TFileStream.Create(ExtName, fmOpenReadWrite );

       qrDocuments := TMyQuery.create(nil);
       try
        qrDocuments.Connection := AMyConnection;
        qrDocuments.Close;
        qrDocuments.SQL.Clear;
        qrDocuments.SQL.Text:='Select Id,FileName,Data from files where Id = :prId And Data IS NOT NULL';
        qrDocuments.ParamByName('prId').AsInteger := AKey;
        qrDocuments.open;
        TBlobField(qrDocuments.FieldByName('Data')).SaveToStream(TempFileName);
       finally
          TempFileName.Free;
          qrDocuments.free;
       end;
       ShellExecute(Application.Handle, 'open', Pchar(ExtName), '', '', SW_SHOWNORMAL);
       DeleteFile( ExtName);
    end;
È stato utile?

Soluzione

Purtroppo ci sono 4 upvotes in questo momento per questa risposta da Remy Lebeau , quando la tecnica semplicemente non funziona con la maggior parte delle applicazioni. Forse uno dei upvoters puoiaffiggere un frammento di codice che consente di aprire un file PDF con Acrobat Reader mentre il file è ancora aperto con la bandiera FILE_FLAG_DELETE_ON_CLOSE?

In ogni caso, è possibile combinare alcuni dei suggerimenti qui per i migliori risultati:

  • Avere un elenco interno di file temporanei utilizza l'applicazione.
  • Il programma di spegnimento a piedi l'elenco dei file temporanei e cercare di eliminarli. Se questo non funziona per alcuni di loro (perché sono ancora aperte nella applicazione esterna) registrare questi per l'eliminazione al riavvio con il codice Gabr dato si .
  • Se ha bisogno di un nuovo file temporaneo, prima camminare il vostro elenco interno di file e cercare di riutilizzare uno di loro. Creare un nuovo file (e aggiungere il suo nome alla lista) solo se questo non riesce.

preferisco questo approccio alla registrazione di tutti i file per l'eliminazione al riavvio, perché io non sono sicuro di come molti file temporanei vostra applicazione potrebbe aprire - forse c'è un limite per il numero di file che può essere registrato con MOVEFILE_DELAY_UNTIL_REBOOT? E 'una risorsa a livello di sistema che avrei usato con parsimonia.

Altri suggerimenti

Una possibilità potrebbe essere quella di aggiungere ogni file temporaneo per l'elenco dei file che vengono eliminati durante l'avvio del sistema.

Sulla piattaforma Windows NT (a partire da Windows 2000), si può chiamare MoveFileEx funzione con un secondo parametro (destinazione) impostato a zero e con un MOVEFILE_DELAY_UNTIL_REBOOT bandiera.

Su Windows 9x, questo è molto più complicato. È necessario modificare il file% WINDIR% \ Wininit.ini e scrivere una voce nella sezione [Rinomina].

come spostare i file che sono attualmente in uso descrive entrambe le tecniche.

DSiMoveOnReboot funzione (parte del DSiWin32 biblioteca) gestisce entrambi i sistemi operativi. Se si passa una stringa vuota come secondo parametro, si eliminerà il file di origine al riavvio.

function DSiMoveOnReboot(const srcName, destName: string): boolean;
var
  wfile: string;
  winit: text;
  wline: string;
  cont : TStringList;
  i    : integer;
  found: boolean;
  dest : PChar;
begin
  if destName = '' then
    dest := nil
  else
    dest := PChar(destName);
  if DSiIsWinNT then
    Result := MoveFileEx(PChar(srcName), dest, MOVEFILE_DELAY_UNTIL_REBOOT)
  else
    Result := false;
  if not Result then begin
    // not NT, write a Rename entry to WININIT.INI
    wfile := DSiGetWindowsFolder+'\wininit.ini';
    if FileOpenSafe(wfile,winit,500,120{one minute}) then begin
      try
        cont := TStringList.Create;
        try
          Reset(winit);
          while not Eof(winit) do begin
            Readln(winit,wline);
            cont.Add(wline);
          end; //while
          if destName = '' then
            wline := 'NUL='+srcName
          else
            wline := destName+'='+srcName;
          found := false;
          for i := 0 to cont.Count - 1 do begin
            if UpperCase(cont[i]) = '[RENAME]' then begin
              cont.Insert(i+1,wline);
              found := true;
              break;
            end;
          end; //for
          if not found then begin
            cont.Add('[Rename]');
            cont.Add(wline);
          end;
          Rewrite(winit);
          for i := 0 to cont.Count - 1 do
            Writeln(winit,cont[i]);
          Result := true;
        finally cont.Free; end;
      finally Close(winit); end;
    end;
  end;
end; { DSiMoveOnReboot }

Utilizzare la funzione API Win32 CreateFile () per aprire il file, specificando il flag FILE_FLAG_DELETE_ON_CLOSE, e quindi passare il manico con conseguente a un oggetto THandleStream in modo che si può ancora utilizzare SaveToStream ().

Inoltre, c'è un bug nel codice - si sta passando il tipo sbagliato di maniglia per ShellExecute (). Si aspetta un handle di finestra, ma si passa un handle di file, invece, e peggio si accede l'handle di file dopo aver già liberato il TFileStream, chiudendo così la maniglia.

Forse è possibile memorizzare in alcuni ben noti per cartella (es sottocartella nella cartella TEMP con un nome del vostro app) e chiare contenuto di questa cartella whem utente la prossima volta carica l'app? Oppure si può installare l'utilità sereno Ulteriori e impostarlo per l'esecuzione in avvio automatico.
Un'altra idea di cancellare i file dopo il riavvio - è possibile cancellare tutto nella vostra sottocartella all'avvio, o fare un elenco dei file creati con l'ultima volta modificare, ultima dimensione, conservare questo elenco in file XML e successivamente eliminare o aggiornare il confronto contenuto del sottocartella Temp con dettagli di file da quella lista?

Se non ricordo male, v'è una bandiera per CreateFile che indica a Windows che dovrebbe eliminare il file una volta che l'ultima maniglia ad esso è stato chiuso. Quindi, creare il file normalmente, chiuderlo e riaprirlo con una quota di negare nessuno e la bandiera di cui sopra. Poi lasciare che l'applicazione esterna aprirlo e chiudere da soli. Ciò dovrebbe tradursi in Windows eliminare il file una volta che l'applicazione esterna chiude.

(non ho provato questo.)

in Unix-like sistemi operativi il solito trucco è quello di aprirlo ed eliminare immediatamente. non apparirà sulla directory, ma i dati sono ancora assegnata al processo (es) che lo tengono aperto. non appena viene chiuso (sia ben di morire dal processo), il file system dovrebbe recuperare lo spazio.

non è un hack, è documentato e sostenuto (una conseguenza di avere il file aperto gestisce conta come un 'riferimento' al file, proprio come le voci di directory).

forse c'è qualche trucco simile su Windows? Mi sembra di ricordare che NTFS supporta più riferimenti allo stesso file (no, le scorciatoie non sono quelle). in tal caso, l'eliminazione del file, ma ancora appeso al ultimo riferimento come risorsa effimera potrebbe funzionare.

Ovviamente, sto solo speculando qui ...

In realtà la nostra applicazione creare file de in una cartella temporanea especific. Quando l'applicazione Chiudere le FIE vengono eliminati. Se l'applicazione si chiude correttamente, l'esecuzione successiva (quando vicino) tutti i file vengono eliminati.

Inoltre, è possibile avviare un processo in background per eliminare i file che non sono più aperti. ShellExecute restituire un manico (associare internamente questa maniglia per un nome di file). Questo processo in background deve testare il manico del processo che non esiste ed eliminare i file associati.

scusa per il cattivo inglese. ; -)

Saluti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top