Kill Excel process created in Matlab - matlab

Given that I write to a workbook, I currently kill all Excel processes so that my code works when I call it in a loop.
xlswrite(path,values);
system('taskkill /F /IM EXCEL.EXE');
This makes me unable to run the code while I am working in another Excel file. How do I make it so that Matlab terminates only the Excel processes that itself created?

This was a "feature" introduced somewhere around R2015b to speed up multiple writes to Excel... not very user/memory friendly!
The xlswrite documentation links to this MathWorks Support Answer to manually write to Excel using actxserver, you can then manually delete the COM object referencing Excel.
You can actually edit xlswrite and see that it uses matlab.io.internal.getExcelInstance, which does the same thing and creates a COM interface with actxserver.
A cheeky option would be to copy xlswrite, add the Excel variable it creates as an output, and Quit and delete it afterwards, as shown below. I don't advocate breaking any of The MathWorks' copyright ownership of that function.
A less cheeky option would be to create a comparable function based on the answer I linked above, for writing data only it would look something like this:
function xlswriteClean( File, Data, Range )
% XLSWRITECELAN writes data like XLSWRITE, but deletes the Excel instance!
% XLSWRITECELAN (FILE,DATA,RANGE) writes the variable in
% DATA to FILE, in the range specified by RANGE.
% RANGE is optional, defaults to "A1"
% Obtain the full path name of the file
% Could handle this more elegantly, i.e.
% this always assumes the current directory, but user might give a full path
file = fullfile(pwd, File);
% Open an ActiveX connection to Excel
h = actxserver('excel.application');
%Create a new work book (excel file)
wb = h.WorkBooks.Add();
% Select the appropriate range
if nargin < 3
Range = 'A1';
end
rng = h.Activesheet.get('Range', Range);
% Write the data to the range
rng.value = Data;
% Save the file with the given file name, close Excel
wb.SaveAs( File );
% Clean up - the point of this function
wb.Close;
h.Quit;
h.delete;
end
You can customise basically everything within the new Excel workbook using the COM object h, so you could add any functionality which you use in xlswrite like sheet naming etc.

You can start the excel process by powershell and get its process id then use the process id to kill the process:
[~, pid] = system('powershell (Start-Process excel.exe -passthru).Id');
% Do your work
% ...
system(['powershell Stop-Process -Id ' pid])

Related

How to append a file to an existing zip file/folder

Is there a way to append a file to an existing zip file/folder?
zip(zipfilename,filenames) would overwrite the original zipfilename.
I am using Windows 10 in case that makes a difference.
system(['powershell.exe -ExecutionPolicy Bypass Compress-Archive -update ',...
filename,' ',...
zipfilename]);
works.
Alternatively, as #Rotem pointed out, and in some situations more suitable, we can use Java's ZipOutputStream as long as we convert data to binary first.
If we start with a file test.csv, then the contained string can be read into an uint8 array by
filename = 'test.csv'; % change filename as needed.
fid = fopen(filename, 'r');
data = fread(fid , '*uint8');
fclose(fid );
If we start with data in a Matlab Workspace, we need to convert the data into the format we desire in the eventual output file and then convert it to binary. For example, if the desired compressed file is a .csv file, in other words, formatted text, we can prepare the string output with sprintf and convert it to the corresponding uint8 array such as
data = uint8(sprintf('%d, %d\r\n', [1,2;3,4]));
Following the above, one can use Java's ZipOutputStream to output to an existing zip file. Example below.
filename='test.csv'; % change filename of zip entry as needed
zipfilename='test.zip'; % change filename as needed
fos = java.io.FileOutputStream(zipfilename);
zos = java.util.zip.ZipOutputStream(fos);
ze = java.util.zip.ZipEntry(filename);
% zos.setLevel(9); % optional
zos.putNextEntry(ze);
zos.write(data, 0, numel(data));
zos.finish;
zos.close;
The benefit of this approach is that, if the data starts off in the current Matlab Worksapce, no additional file needs to be created, which would have required additional i/o use 3 times (in the above example, write test.csv, read csv, delete csv).
Another benefit is that the this method does not require powershell which is OS dependent -- not available in earlier Windows versions for example.
If the data starts off in an external file with Windows 10, as specified in the OP, then the 1st method is more expedient.
Note: Additional information on reading from the zip file or reading file list from zip file can be found here and here.

Edit an Abaqus input file and Run it from Matlab

I need perform 50 Abaqus simulations, each simulation analyses a certain material property and each differs by changing one parameter. So the idea is to write a Matlab script that:
opens the .inp file
edits the material parameter of interest
prints it into a new file which will be the new .inp file
runs it to perform the simulation
This is what I accomplished so far in a very simplified version:
f= fopen('PRD8_30s.inp');
c = textscan(f,'%s %s %s %s %s ','delimiter',',');
fclose(f) ;
S = [c{1}];
A = {'5e-08'} ;
S(12496) = A ;
fid = fopen('file.inp','w') ;
fprintf(fid,'%s \n',S{:} );
fclose(fid) ;
PRD_8_30s.inp
I manually found out the position of the parameter of interest (A at 12496 hence below the line *Viscoelastic). The code actually changes the parameter I need but there are major problems: it prints a new file with additional lines with respect to the original .inp (12552 vs 8737) and it doesn't print the entire .inp but only the first column.
How can I edit the .inp changing the parameter and obtaining a new .inp with the edited parameter that can be used to run the new simulation?
Thank you in advance for your help!
If your input file is not multiple Gb in size, The following might help.
create a template input and mark the parameter you want to change as, for example para_xxxx
Use the following script:
text=fileread('template.inp');
newtext=replace(text,'para_xxxx',newParameter);
fid=fopen('newcase.inp','w');
fprintf(fid,newtext);
fclose(fid);
The file name 'newcase.inp' should be updated each time in the loop.

Matlab saving a .mat file with a variable name

I am creating a matlab application that is analyzing data on a daily basis.
The data is read in from an csv file using xlsread()
[num, weather, raw]=xlsread('weather.xlsx');
% weather.xlsx is a spreadsheet that holds a list of other files (csv) i
% want to process
for i = 1:length(weather)
fn = [char(weather(i)) '.csv'];
% now read in the weather file, get data from the local weather files
fnOpen = xlsread(fn);
% now process the file to save out the .mat file with the location name
% for example, one file is dallasTX, so I would like that file to be
% saved as dallasTx.mat
% the next is denverCO, and so denverCO.mat, and so on.
% but if I try...
fnSave=[char(weather(i)) '.mat'] ;
save(fnSave, fnOpen) % this doesn't work
% I will be doing quite a bit of processing of the data in another
% application that will open each individual .mat file
end
++++++++++++++
Sorry about not providing the full information.
The error I get when I do the above is:
Error using save
Argument must contain a string.
And Xiangru and Wolfie, the save(fnSave, 'fnOpen') works as you suggested it would. Now I have a dallasTX.mat file, and the variable name inside is fnOpen. I can work with this now.
Thanks for the quick response.
It would be helpful if you provide the error message when it doesn't work.
For this case, I think the problem is the syntax for save. You will need to do:
save(fnSave, 'fnOpen'); % note the quotes
Also, you may use weather{i} instead of char(weather(i)).
From the documentation, when using the command
save(filename, variables)
variables should be as described:
Names of variables to save, specified as one or more character vectors or strings. When using the command form of save, you do not need to enclose the input in single or double quotes. variables can be in one of the following forms.
This means you should use
save(fnSave, 'fnOpen');
Since you want to also use a file name stored in a variable, command syntax isn't ideal as you'd have to use eval. In this case the alternative option would be
eval(['save ', fnSave, ' fnOpen']);
If you had a fixed file name (for future reference), this would be simpler
save C:/User/Docs/MyFile.mat fnOpen

Wait while variable does not exist MATLAB

I need to suspend the program until the variable is created. I point to the data file, then open uiimport to specify the range of data. And at this moment I have to suspend the program until the variable is created.
%find file
[FileName,PathName] = uigetfile({'*.xls;*.xlsx', 'Excel files(*.xls, *.xlsx)'},'Укажите Excel-файл с данными');
%open import wizard
uiimport(strcat(PathName, FileName));
% here i need to suspend the program until the variable is created
You must specify an output variable when calling uiimport. If you do this, no lines after your call to uiimport will be executed until uiimport has completed (the user has chosen data to import or not).
data = uiimport(fullfile(PathName, FileName));
% Do stuff with data
disp(data.value)
If for some reason, you did need to wait until a variable existed, you could use a while loop combined with exist, but in general this is a marker of poor program design.
while ~exist('variablename', 'var')
% Do something that may define the variable
end
Update
If you're simply reading an excel file, it is likely easier to use xlsread to do so:
data = xlsread(filename, -1);

MATLAB: Use a variable with a file extenstion to load files

I am using MATLAB
I Have 51 files in their own directory all of .out extention created by a seperate program, all numbered 0 to 50.
ie
0.out
1.out
2.out
and so on til 50.out.
I need to load each file 1 by one to do calculations upon them within a for loop. How would I do this using the count variable to load the file, if the directory is set beforehand?
i.e.
%set directiory
cd(......)
%for loop
For count = 0:50,
data = count.out *<-----this line*
.....
Many thanks!
First generate the file name with
fileName = [int2str(count) '.out'];
then open the file with
fid = fopen(fileName, 'r');
The loading phase depends on the kind of file you want to read. Assuming it is a text file you can, for example, read it line after line with
while ~feof(fid)
line = fgetl(fid);
end
or use more specialized functions (see http://www.mathworks.it/it/help/matlab/text-files.html). Before the end of the for loop you'll have to close the file by calling
fclose(fid);
Another quite nice way to do it is to use the dir function
http://www.mathworks.co.uk/help/matlab/ref/dir.html
a = dir('c:\docs*.out')
Will give you a structure containing all the info about the *.out files in the directory you point it to, (or the path). You can then loop through it bit by bit. using fopen or csvread or whatever file reading function you want to use.