如何关闭错误后保持打开的文件?

时间:2012-01-13 08:40:21

标签: matlab file-io

我正在使用

fid = fopen('fgfg.txt');

打开一个文件。

有时在我设法关闭文件之前发生错误。在关闭Matlab之前,我无法对该文件做任何事情。

如果发生错误,如何关闭文件?

4 个答案:

答案 0 :(得分:49)

首先,您可以使用命令

fclose all

其次,您可以使用 try-catch 块并关闭文件句柄

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

还有第三种方法,它要好得多。 Matlab现在是一个带垃圾收集器的面向对象语言。您可以定义一个自动处理其生命周期的包装器对象。

因为在Matlab中可以用这种方式调用对象方法:

  

myObj.method()

以这种方式:

  

方法(MyObj中)

您可以定义一个模仿所有相关文件命令的类,并封装生命周期。

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

Matlab会自动调用删除运算符。 (你需要包装更多的功能,(fread,fseek等))。

所以现在你有了安全句柄,无论你是否丢失了文件的范围或发生了错误,都会自动关闭文件。

像这样使用:

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

无需关闭。

修改 我只想把fclose()包裹起来什么都不做。它可能对向后兼容性很有用 - 对于使用文件ID的旧函数。

编辑(2):关注@AndrewJanke好评,我想通过在 fclose()

上抛出错误来改进删除方法
    function delete(this)          
        [msg,errorId] = fclose(this.fid);
        if errorId~=0
            throw(MException('safefopen:ErrorInIO',msg));
        end
    end

答案 1 :(得分:29)

你可以尝试一个名为onCleanup的ML添加的非常整洁的“功能”。 Loren Shure在添加时有一个完整的writeup。它是一个用清理代码实例化的类,然后当它超出范围时执行 - 即当它出错时,或者函数结束。使代码非常干净。这是Andrey上面的类的通用版本。 (顺便说一句,对于像打外部数据源这样的复杂任务,定制类肯定是要走的路。)

来自the help:

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

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

基本上,你给它一个function handle(在这种情况下是@()fclose(fid))它在超出范围时运行。

您的清理代码会在抛出错误或正常退出时执行,因为您退出fileOpenSafely并且c超出范围。

不需要try/catch或条件代码。

答案 2 :(得分:4)

Andrey的解决方案above确实是解决此问题的最佳方法。我只想补充一点,如果处理delete()个对象的数组,在方法safefopen中抛出异常可能会有问题。在销毁这样一个数组的过程中,MATLAB会在每个数组元素上调用delete(),如果有任何delete()抛出,那么你最终可能会得到剩余的打开文件句柄。如果你真的需要知道在破坏期间是否出现了问题,那么发出警告将是更好的选择恕我直言。

对于那些懒得将所有转发方法写入每个使用文件句柄的MATLAB内置的人,您可以考虑为类subsref重载方法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

这个替代方案使用了有些丑陋的feval,但是即使MATLAB人员(或你自己)决定添加涉及文件句柄的新函数,或者输入参数的数量/顺序,它也具有工作的优势。给定的功能变化。如果您决定使用subsref替代方案,则应使用此类safefopen

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

编辑: subsref解决方案的一个缺点是它忽略了所有输出参数。如果你需要输出参数,那么你将不得不引入更多的丑陋:

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

然后你可以做以下事情:

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

答案 3 :(得分:1)

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

%假设您要关闭所有打开的文件句柄