I call a function (containing fopen and fclose) from the Command Window and then after MATLAB encounters an error that I fix (the runtime of the program stops after I save my corrections), I want to delete the file it created, in order to repeat the process. However, MATLAB, somehow, still has the file open and typing in fclose(f), in the Command Window does not make MATLAB let go of the file.
function something(something)
f = fopen('something.txt', 'w');
%statments with fprintf
fclose(f);
end
You may not have access to the handle f from outside the function, in which case you can try fclose('all') from the Matlab command window.
Generally it is best practice to use a try .. catch ... statement around code that uses a file, so that you always call fclose and release the handle if an error occurs.
If you are still unable to delete the file, and assuming it is not locked by another process (for example if you are viewing it externally in Windows Notepad), it may be that you are calling library functions from Matlab and that the shared library maintains the file lock. In this case, try reloading the library using the unloadlibrary and loadlibrary commands.
Using an onCleanup object can be very useful in this case.
Here's your code rewritten to use onCleanup - the fclose will now get called when the function terminates whether normally, or because of an error.
function something(something)
f = fopen('something.txt', 'w');
closer = onCleanup( #()fclose(f) );
% statements with fprintf
end
The documentation also includes an example for exactly this case.
Related
I want to find all dependencies of my script (and/or all subfunctions/subscripts), but not only functions that are called but also external files that are loaded or touched (fopen). matlab.codetools.requiredFilesAndProducts (documentation here) doesn't capture the touched filenames, my next idea, shadow the fopen function using something like below (to copy the filename to a log file), resulted in an unexpected recursive loop.
failed because of (unexpected) recursive loop, where somehow the 'builtin' fopen is not called, rather this function itself:
function varargout=fopen(varargin)
%write opened filename to log file somewhere
varargout=builtin('fopen',varargin{:}); %attempt to call built-in fopen() as usual
end
I also checked Mathworks depencey reports etc, to no use. Any ideas? Thank you.
Background
Say I compile the following simple function in MATLAB
function foo(path_to_m_file)
disp([' Running ' path_to_m_file])
run(path_to_m_file);
end
The function foo just takes a path to an .m file and tries to run it.
However, when I actually try to run foo after compiling it:
./run_foo.sh $path_to_run_time $path_to_m_file
where path_to_m_file is a simple .m file with a statement such as:
a = 2;
I get the following error:
Error using ==> run
MATLAB:run:FileNotFound
However, I know that foo gets the correct path. For example, if I try replacing the line with run by the following two lines in foo
fID = fopen(conf_file, 'rt');
first_line = textscan(fID, '%s', Inf, 'Delimiter', '\n');
foo reads the corresponding line of the .m file. So the .m file is there, and the MATLAB engine can "see" it. Indeed I can even run eval on strings read with textscan.
So my questions are:
Why do I get the error above? Why doesn't foo run the .m file?
Update: See #strictlyrude27's answer below for what seems to be an answer to this question.
If the above doesn't work. Is there a way to get a MATLAB-compiled function to run an .m file that may have changed after compiling the original function?
The motivation for my second question:
I would like to have the ability to "update" an .m file that is part of the project without having to re-compile the full project. Any ideas for this would be greatly appreciated.
From the MATLAB Compiler's documentaton:
Compiled Applications Do Not Process MATLAB Files at Runtime
The MATLAB Compiler was designed so that you can deploy locked down functionality. Deployable MATLAB files are suspended or frozen at the time MATLAB Compiler encrypts them—they do not change from that point onward. This does not mean that you cannot deploy a flexible application—it means that you must design your application with flexibility in mind. If you want the end user to be able to choose between two different methods, for example, they both must be compiled in.
The MCR only works on MATLAB code that was encrypted when the component was built. Any function or process that dynamically generates new MATLAB code will not work against the MCR.
Some MATLAB toolboxes, such as the Neural Network Toolbox™ product, generate MATLAB code dynamically. Because the MCR only executes encrypted MATLAB files, and the Neural Network Toolbox generates unencrypted MATLAB files, some functions in the Neural Network Toolbox cannot be deployed.
Similarly, functions that need to examine the contents of a MATLAB function file cannot be deployed. HELP, for example, is dynamic and not available in deployed mode. You can use LOADLIBRARY in deployed mode if you provide it with a MATLAB function prototype.
Instead of compiling the function that generates the MATLAB code and attempting to deploy it, perform the following tasks:
Run the code once in MATLAB to obtain your generated function.
Compile the MATLAB code with MATLAB Compiler, including the generated function.
Tip: Another alternative to using EVAL or FEVAL is using anonymous function handles.
If you require the ability to create MATLAB code for dynamic run time processing, your end users must have an installed copy of MATLAB.
You can read read an m file, line by line and execute each line with the eval() function. There are restrictions on the format of the m file (no line breaks for example, each line must contain a complete MATLAB statement) but it does work and can add to your run time environment inside the compiled application. I use this technique to allow users to define configuration and data files for a compiled application I have developed.
Clearly, if your end user provides a poorly formed m file to evaluate, you will end up with difficult to resolve bugs.
Is it possible to save workspace variables from a function that I am calling and cannot explicitly edit without file I/O?
I know I can use the save function to save all of the variable names in a workspace, but what if I wanted to save the workspace variables from a function that I am calling, like a built in function (mean, sum, etc).
I would like to save all of the variables from a function's workspace before it returns back to the function I am writing, and I would like to do it without opening the file each time and adding an extra line of code; is this possible?
In case anyone is interested:
I have yet to find a solution to the exact question I asked, but I found a solution that works well enough with a little extra file tracking.
Using the function onCleanup, you can specify that all the variables be saved right before the function returns to the caller. Using this and a little file parsing, you can open the code in question as a simple text file, and insert the onCleanup code anywhere in the file (easier than inserting save as the last line). Then, you can run the code and track the new .mat file using the previous file name or any naming method you choose.
That will enable you to save all the variables in a workspace just before the function exits, but it does require file parsing, see simple example below:
readFile = fopen('filename.m');
writeFile = fopen(['filename_new.m']);
%Ignore the first line (hopefully the function header, may need extra parsing if not)
functionHeader = fgets(readFile);
%Print the function header
fprintf(writeFile,functionHeader);
%Print the clean-up code
%NOTE: This can go anywhere in the file
fprintf(writeFile,sprintf('onCleanup(#()save(''%s.mat''))\n',filename)));
nextLine = fgets(readFile);
while ischar(nextLine)
fprintf(writeFile,nextLine);
nextLine = fgets(readFile);
end
With the above, a new file is created (filename_new.m) which needs to be run, and will create a mat file (filename.mat) with all of the workspace variables in it.
eval(newFileName(1:end-2));
Now, by tracking the .mat file, you can do whatever is necessary after this point. For my purposes, I was interested in the memory used by the said function, which is available by accessing the mat object of the .mat file.
matObj = matfile('filename.mat');
stats = whos(matObj);
fileSize = sum([stats.bytes]);
Try the "save" function.
Add this line in your called function:
save('filename')
Here is my sample code:
a=10; b=6;
c=addition(a,b);
And the function is defined as:
function [out]=addition(a,b)
out=a+b;
temp1=a;
temp2=b;
temp3=a-b;
save('C:\data.mat');
end
Background
Say I compile the following simple function in MATLAB
function foo(path_to_m_file)
disp([' Running ' path_to_m_file])
run(path_to_m_file);
end
The function foo just takes a path to an .m file and tries to run it.
However, when I actually try to run foo after compiling it:
./run_foo.sh $path_to_run_time $path_to_m_file
where path_to_m_file is a simple .m file with a statement such as:
a = 2;
I get the following error:
Error using ==> run
MATLAB:run:FileNotFound
However, I know that foo gets the correct path. For example, if I try replacing the line with run by the following two lines in foo
fID = fopen(conf_file, 'rt');
first_line = textscan(fID, '%s', Inf, 'Delimiter', '\n');
foo reads the corresponding line of the .m file. So the .m file is there, and the MATLAB engine can "see" it. Indeed I can even run eval on strings read with textscan.
So my questions are:
Why do I get the error above? Why doesn't foo run the .m file?
Update: See #strictlyrude27's answer below for what seems to be an answer to this question.
If the above doesn't work. Is there a way to get a MATLAB-compiled function to run an .m file that may have changed after compiling the original function?
The motivation for my second question:
I would like to have the ability to "update" an .m file that is part of the project without having to re-compile the full project. Any ideas for this would be greatly appreciated.
From the MATLAB Compiler's documentaton:
Compiled Applications Do Not Process MATLAB Files at Runtime
The MATLAB Compiler was designed so that you can deploy locked down functionality. Deployable MATLAB files are suspended or frozen at the time MATLAB Compiler encrypts them—they do not change from that point onward. This does not mean that you cannot deploy a flexible application—it means that you must design your application with flexibility in mind. If you want the end user to be able to choose between two different methods, for example, they both must be compiled in.
The MCR only works on MATLAB code that was encrypted when the component was built. Any function or process that dynamically generates new MATLAB code will not work against the MCR.
Some MATLAB toolboxes, such as the Neural Network Toolbox™ product, generate MATLAB code dynamically. Because the MCR only executes encrypted MATLAB files, and the Neural Network Toolbox generates unencrypted MATLAB files, some functions in the Neural Network Toolbox cannot be deployed.
Similarly, functions that need to examine the contents of a MATLAB function file cannot be deployed. HELP, for example, is dynamic and not available in deployed mode. You can use LOADLIBRARY in deployed mode if you provide it with a MATLAB function prototype.
Instead of compiling the function that generates the MATLAB code and attempting to deploy it, perform the following tasks:
Run the code once in MATLAB to obtain your generated function.
Compile the MATLAB code with MATLAB Compiler, including the generated function.
Tip: Another alternative to using EVAL or FEVAL is using anonymous function handles.
If you require the ability to create MATLAB code for dynamic run time processing, your end users must have an installed copy of MATLAB.
You can read read an m file, line by line and execute each line with the eval() function. There are restrictions on the format of the m file (no line breaks for example, each line must contain a complete MATLAB statement) but it does work and can add to your run time environment inside the compiled application. I use this technique to allow users to define configuration and data files for a compiled application I have developed.
Clearly, if your end user provides a poorly formed m file to evaluate, you will end up with difficult to resolve bugs.
Is there a way to save MATLAB error messages to a file?
This may be a simple issue, but Google couldn't give me an answer. I've compiled a GUI executable for use without a MATLAB license, and occasionally it freezes. For aesthetic purposes, I suppressed the command window normally accompanying such an executable, so I can't get an error message out through the command prompt. I'd like to be able to create an error log which can be emailed to me for debugging.
Thanks!
Use try...catch statements around the code. In the catch block, you can write out the error including stack information. Using sendmail, you can even have the code notify you of errors by mail (ideally with a popup that lets users decide whether they want to share the crash information with you)
try
% your code here
catch err
%open file
fid = fopen('logFile','a+');
% write the error to file
% first line: message
fprintf(fid,'%s\n',err.message);
% following lines: stack
for e=1:length(err.stack)
fprintf(fid,'%sin %s at %i\n',txt,err.stack(e).name,err.stack(e).line);
end
% close file
fclose(fid)
end
Edited to be a bit more explicit on how to write error message to file
Use the "diary" command to create a log file. This will make Matlab write a copy of all the command line output to a file, including warnings, error messages, and the stack traces for unhandled exceptions. Sendmail() can then send it to you on errors. If you want to save space, you can have the program delete its log file on a normal (no error) program exit.
IMHO this is preferable to using the "try ... catch; write errors; end" because:
It will capture all uncaught errors, including Java exceptions raised from the AWT thread and errors from M-code callbacks in your GUI, which can be hard to get try/catches around.
If Matlab is crashing hard, like with a segfault, the M-code level try/catch won't catch it. But the diary file may still record the segfault dump.
You can emit progress messages, debug info, and warnings to give more information on your program's behavior leading up to the errors, and they'll all be captured.
I like to keep code in catch blocks minimal.
There's also a command line option that does the equivalent; I don't know how to invoke that for compiled Matlab.
For older versions of MATLAB you can use the LASTERROR function to get information about the most recent error issued by MATLAB. However, this function will be phased out in newer MATLAB versions.
For newer versions of MATLAB, I would suggest making use of the MException class to capture error information. You can catch an MException object using a try-catch block as Jonas suggested, or you could potentially use the static MException.last method to get the last uncaught exception (depending on how you run your code):
%# OPTION 1:
%# --------
try
my_code();
catch ME
%# Save data in ME to file
end
%# OPTION 2:
%# --------
my_code();
ME = MException.last;
%# Save data in ME to file
Whichever way you capture the MException object, you can use the MException.getReport method to display a formatted message string including the information contained in the MException object:
msgString = getReport(ME,'basic'); %# Displays the higher level error
msgString = getReport(ME,'extended'); %# Displays the error and the stack
You can then write the message string to a file.
try
% your code here
catch err
fid = fopen('errorFile','a+');
fprintf(fid, '%s', err.getReport('extended', 'hyperlinks','off'))
fclose(fid)
end
For exact formatting style like from Matlab command window, use:
rep = getReport(exception, 'extended', 'hyperlinks', 'off');
name = strcat('Data\', name, '.txt');
fid = fopen(name, 'w+t','n');
fprintf(fid, 'Error message\n-------------\n\n');
fprintf(fid, '%s\n', rep);
fclose('all');