我正在使用
fid = fopen('fgfg.txt');
打开一个文件。
有时在我设法关闭文件之前发生错误。在关闭Matlab之前,我无法对该文件做任何事情。
如果发生错误,如何关闭文件?
答案 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上面的类的通用版本。 (顺便说一句,对于像打外部数据源这样的复杂任务,定制类肯定是要走的路。)
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);
%假设您要关闭所有打开的文件句柄