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

Lee*_*Lee 30 file-io matlab

我在用

fid = fopen('fgfg.txt');
Run Code Online (Sandbox Code Playgroud)

打开一个文件.

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

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

And*_*ein 49

首先,您可以使用该命令

fclose all
Run Code Online (Sandbox Code Playgroud)

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

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

还有第三种方法,它要好得多.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
Run Code Online (Sandbox Code Playgroud)

删除操作员利用Matlab自动调用.(你需要包装更多的功能,(fread,fseek等)).

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

像这样使用它:

f = safefopen('myFile.txt','wt')
fprintf(f,'Hello world!');
Run Code Online (Sandbox Code Playgroud)

而且无需关闭.

编辑: 我只想到包装fclose()什么都不做.它可能对向后兼容性很有用 - 对于使用文件ID的旧函数.

编辑(2):关注@AndrewJanke好评,我想通过在fclose()上抛出错误来改进删除方法

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

  • +1很好用的删除.一个问题:这是缓冲的I/O,因此失败的写入可能只会出现在fclose()调用中; 就像在这里,他们会被默默地忽略.可以测试fclose()的返回值并在失败时调用error().在"删除"中,错误将变为警告.可能希望包含一个可选的fclose()方法,以便调用者可以将错误公开为异常或处理它,并且如果delete()仍然打开则将其关闭.可能还想在构造函数中测试fopen()失败; 它会隐藏一个无效的fid,然后在fwrite()或delete()上进行操作时出错. (5认同)
  • 我认为这是[我的想法](http://stackoverflow.com/a/9024064/21322);)无论如何,我会确保`delete`方法是无异常的.唯一可能导致`fclose`失败的是`this.fid`是无效的文件句柄; 在这种情况下,您不需要关闭该文件. (2认同)

Mar*_*arc 29

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

帮助:

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

   functionThatMayError(fid);
end   % c executes fclose(fid) here
Run Code Online (Sandbox Code Playgroud)

基本上,你给它一个函数句柄(在这种情况下@()fclose(fid))它在超出范围时运行.

您的清理代码在抛出错误或正常退出时执行,因为您退出fileOpenSafelyc超出范围.

不需要try/catch或有条件的代码.

  • +1 onCleanup很棒.但实际上,文件I/O*是*击中外部数据源的复杂任务之一.Matlab的文件句柄I/O主要使用状态代码而不是抛出错误,因此每次调用fopen(),fread(),fclose()等都需要伴随检查返回值或者ferror()完全正确.它很烦人,所以没有人在他们的代码中真正做到这一点.它非常适合包装它们的自定义类,并添加状态检查,以便在失败时调用error()调用. (3认同)