Domanda Come posso chiudere i file che rimangono aperti dopo un errore?


sto usando

fid = fopen('fgfg.txt');

per aprire un file.

A volte si verifica un errore prima che riesca a chiudere il file. Non posso fare nulla con quel file fino a quando non chiudo Matlab.

Come posso chiudere un file se si verifica un errore?


29
2018-01-13 08:40


origine


risposte:


Prima di tutto, puoi usare il comando

fclose all

In secondo luogo, puoi usare prova a prendere blocca e chiude i tuoi handle di file

 try
     f = fopen('myfile.txt','r')
     % do something
     fclose(f);
 catch me
     fclose(f);
     rethrow(me);
 end

C'è un terzo approccio, che è molto meglio. Matlab è ora un linguaggio orientato agli oggetti con Garbage Collector. È possibile definire un oggetto wrapper che si occuperà automaticamente del suo ciclo di vita.

Poiché in Matlab è possibile chiamare i metodi oggetto in questo modo:

myObj.method ()

e in questo modo:

Metodo (myObj)

È possibile definire una classe che simula tutto il comando file pertinente e incapsula il ciclo di vita.

classdef safefopen < handle
    properties(Access=private)
        fid;
    end

    methods(Access=public)
        function this = safefopen(fileName,varargin)            
            this.fid = fopen(fileName,varargin{:});
        end

        function fwrite(this,varargin)
            fwrite(this.fid,varargin{:});
        end

        function fprintf(this,varargin)
            fprintf(this.fid,varargin{:});
        end

        function delete(this)
            fclose(this.fid);
        end
    end

end

Il Elimina l'operatore è chiamato automaticamente da Matlab. (Ci sono più funzioni che è necessario avvolgere, (fread, fseek, ecc.)).

Così ora hai maniglie sicure che chiudono automaticamente il file se ne hai perso l'ambito o si è verificato un errore. 

Usalo in questo modo:

f = safefopen('myFile.txt','wt')
fprintf(f,'Hello world!');

E non c'è bisogno di chiudere.

Modificare: Ho solo pensato di avvolgere fclose() non fare niente. Potrebbe essere utile per la retrocompatibilità - per le vecchie funzioni che usano gli id ​​di file.

Edit (2): Seguendo il buon commento di @AndrewJanke, vorrei migliorare il metodo di eliminazione generando errori fclose ()

    function delete(this)          
        [msg,errorId] = fclose(this.fid);
        if errorId~=0
            throw(MException('safefopen:ErrorInIO',msg));
        end
    end

49
2018-01-13 08:41



Puoi provare una "funzione" molto accurata aggiunta da ML chiamata onCleanup. Loren Shure ha avuto un completo Scrivilo su di esso quando è stato aggiunto. È una classe che si istanzia con il tuo codice di pulizia, quindi viene eseguita quando esce dall'ambito di applicazione, ad esempio quando si verifica un errore o la funzione termina. Rende il codice molto pulito. Questa è una versione generica della classe Andrey avuto sopra. (A proposito, per attività complesse come la ricerca di fonti di dati esterne, le classi personalizzate sono sicuramente la strada da percorrere).

a partire dal l'aiuto:

function fileOpenSafely(fileName)
   fid = fopen(fileName, 'w');
   c = onCleanup(@()fclose(fid));

   functionThatMayError(fid);
end   % c executes fclose(fid) here

Fondamentalmente, lo dai a maniglia della funzione (in questo caso @()fclose(fid)) che gira quando esce dal campo di applicazione.

Il codice di pulizia viene eseguito quando viene generato un errore OPPURE quando esce normalmente, perché si esce fileOpenSafely e c va fuori dal campo di applicazione.

No try/catch o codice condizionale necessario.


29
2018-01-13 14:00



AndreyLa soluzione sopra è davvero il miglior approccio a questo problema. Volevo solo aggiungere che lanciare un'eccezione nel metodo delete() potrebbe essere problematico, se gestisci array di safefopen oggetti. Durante la distruzione di un tale array, MATLAB chiamerà delete() su ogni elemento dell'array e, se presente delete() getta, quindi potresti finire con gli handle di file aperti rimanenti. Se davvero hai bisogno di sapere se qualcosa è andato storto durante la distruzione, emettere un avvertimento sarebbe una scelta migliore.

Per coloro che si sentono pigri a scrivere tutti i metodi di inoltro per ogni built-in MATLAB che utilizza handle di file, si può considerare la semplice alternativa del metodo di overloading subsrefper classe safefopen:

methods(Access=public)
    function varargout = subsref(this, s)            
        switch s(1).type                
            case '.'                    
                if numel(s) > 1,
                    feval(s(1).subs, this.fid, s(2).subs{:});
                else
                    feval(s(1).subs, this.fid);
                end
                % We ignore outputs, but see below for an ugly solution to this
                varargout = {};
            otherwise                    
                varargout{1} = builtin('subsref', this, s);                    
        end      

    end
end

Questa alternativa usa un po 'brutto feval, ma ha il vantaggio di funzionare anche se i ragazzi di MATLAB (o te stesso) decidono di aggiungere nuove funzioni che coinvolgono handle di file, o se il numero / ordine degli argomenti di input per una data funzione cambia. Se decidi di andare per il subsref alternativa allora dovresti usare la classe safefopen come questo:

myFile = safefopen('myfile.txt', 'w');
myFile.fprintf('Hello World!');

MODIFICARE: Uno svantaggio del subsref la soluzione è che trascura tutti gli argomenti di output. Se hai bisogno degli argomenti di output, dovrai introdurre un po 'più di bruttezza:

methods(Access=public)
function varargout = subsref(this, s)                   
        if nargout > 0,
            lhs = 'varargout{%d} ';
            lhs = repmat(lhs, 1, nargout);
            lhs = ['[' sprintf(lhs, 1:nargout) ']='];   
        else
            lhs = '';
        end            
        switch s(1).type                
            case '.'                    
                if numel(s) > 1,                        
                    eval(...
                        sprintf(...
                        '%sfeval(''%s'', this.fid,  s(2).subs{:});', ...
                        lhs, s(1).subs) ...
                        );                        
                else                        
                    eval(...
                        sprintf('%sfeval(''%s'', this.fid);', ...
                        lhs, s(1).subs) ...
                        );                        
                end                 

            otherwise                    
                varargout{1} = builtin('subsref', this, s);

        end            
end
end

E poi potresti fare cose come:

myFile = safefopen('myfile.txt', 'w');
count = myFile.fprintf('Hello World!'); 
[filename,permission,machineformat,encoding] = myFile.fopen();

4
2017-09-24 16:50



fids=fopen('all');
fclose(fids);

% assumendo che tu voglia chiudere tutti i filehandle aperti


1
2018-02-28 09:57