I need to open an existing excel workbook from within Matlab using ActiveX. xlsread is unfeasible because too slow. After getting help from this forum (thanks!) I know that to create a new excel workbook from within matlab and fill it with output you do this:
%# Create and NAME the output file name
wbk=1;fName = fullfile(pwd, 'ALLSDtemp2');
%# create Excel COM Server
Excel = actxserver('Excel.Application');
Excel.Visible = true;
%# delete existing file
if exist(fName, 'file'), delete(fName); end
%# create new XLS file
wb = Excel.Workbooks.Add();
wsheet=1;
(...calculations...)
% Write output to excel file
Mat=[calculation_output];
% Select work book
wb.Sheets.Item(wsheet).Activate();
% Get Worksheets object
ws = wb.Sheets;
%# insert matrix in sheet
Excel.Range(cellRange).Select();
Excel.Selection.Value = num2cell(Mat);
But I can't figure out how to do this with an excel workbook that already exists. And my efforts to do so caused a "serious error" in my computer the other day. So I could really use some guidance.
Thanks
XLSREAD is actually accessing the file through ActiveX, the same way you want to go. I don't see any reason to write you own (and hopefully clear of bugs) procedure.
If XLSREAD is too slow, you can use PROFILER to find performance bottlenecks in the function.
You can actually see what XLSREAD is doing if you type edit xlsread. The m-file with the function will be opened in the MATLAB editor. You can learn the code and actually run it line by line with great MATLAB debugging tools.
I'm not sure from your question whether you wish to just modify an existing Excel file, or to modify an Excel file that is currently open in Excel.
If it's the first, then you can open it like this:
xl = actxserver('Excel.Application');
xl.Visible = true;
wb = xl.Workbooks.Open('path_to_my_excel_file');
and then continue with whatever modifications you want, as you're already doing.
If you want to access an Excel file that is currently open in Excel, use actxGetRunningServer instead of actxserver. You will connect to the running copy of Excel and be able to find whatever workbooks are open.
By the way, you don't need to select a range to change its value. You can just use ws.Range(cellRange).Value = myValue. Might save you a few lines of code here and there.
Related
I have a directory containing with 50 DAT files one base xlsx file in each. I need to make one workbook with those 50 DAT files as an independent worksheet in each folder within directory. The worksheet shall use the columns 3,4,5 from DAT files which is tab separated. The worksheet shall have 6 columns. The first three will be taken from the base xlsx file in the directory. Column 4-6 shall have values from Column 3-5 from .DAT files. I wrote a code in MATLAB to do the needful. Everytime I run it, program crashes. The error I received is
Error using xlswrite (line 219)
Invoke Error, Dispatch Exception:
Source: Microsoft Excel
Description: Document not saved.
Help File: xlmain11.chm
Help Context ID: 0.
The code is as follows: In the code, files_larswg is base xlsx file. Is there a procesto rectify the error and make the process a batch process in case I have 10 similar directories.
date=xlsread('files_larswg.xlsx',1,'A2:C18251');
header_tree={ 'da' , 'mo', 'year', 'tminC', 'tmaxC','prcpmm'};
for k=1:50
k
fileID =fopen(sprintf('FortWayneWG%d.dat',k+516));
data = textscan(fileID,'%*d %*d %f %f %f');
fclose(fileID);
data=cell2mat(data);
sheet_no=sprintf('sheet%d',k);
xlswrite('FWYLARSWG_50set.xlsx', data, sheet_no,'D2:F18251');
xlswrite('FWYLARSWG_50set.xlsx', header_tree, sheet_no,'A1:F1');
xlswrite('FWYLARSWG_50set.xlsx', date, sheet_no,'A2:C18251');
end
Each time you use xlswrite, what you are doing is opening an excel instance, trying to write everything to a file, closing the file, and then reopening the file to do this again. Your OS is erroring (presuming you are using windows) out because the file is locked in windows.
What you should do is use the underlying ActiveXServer in excel, write all of your tabs into a spreadsheet once, and then save this.
Your code should broadly read something like this.
Create an excel object and setup a fresh new workbook.
e = actxserver('Excel.Application');
e.Visible = 1;
w=Add(e.Workbooks)
You should subsequently loop over your data range and write your data in.
This code will add a sheet for each item in a loop, change the sheetname, and then create a the following text in each cell.
datasheet=Add(e.Sheets)
datasheet.Name=sheetname(n)
datasheet.Range('A1:B1').Value='test data or your range'
Once you've completed the loop, save the file, and cleanup your excel object.
w.SaveAs('myfile.xls')
w.Saved = 1;
w.Close;
w.delete
You should follow the pattern of this example on the Matlab help page as well.
I have written a simple textfile using notepad, and I placed the text file in the same folder as a matlab script I want to run. I pretty much want to make a script so that when the user clicks run a pop-up of my text file will come up purely within matlab.(I will later include separate figures, graphs to pop up at the same time.)
I tried researching, and I found fopen. But when I do fopen('FileName.txt','r'); nothing happens?
I am not sure of what you are looking for, but I guessed that you need to open a file and read its content using Matlab.
fid = fopen('FileName.txt','r'); % generate a file identifier
if fid < 0
error 'Unable to open file ... check file location'
else
while ~feof(fid) % while there is a line to read
disp(fgets(fid))
end
end
fclose(fid);
This question already exists:
Closed 10 years ago.
Possible Duplicate:
Excel Addin Error #NAME?
I think it is a follow-up query to my earlier reported issue concerning User defined function in Excel.
I am able to use the function in Excel when used Manually, but when I write to an excel file using Matlab using xlswrite, it gives an error #NAME?
I am attaching the screenshots of the both when entered manually and when using the function through Matlab.
Thanks
EDIT :
Thanks a lot. I have stored the VBA function as an Excel addin here :
C:\Users\Administrator\AppData\Roaming\Microsoft\Addins
Here is what I saw about Excel Add-ins not loaded when used in Automation :
http://www.excelforum.com/excel-programming/472145-calling-excel-macro-from-vb-6-app-problem.html
I am attaching the small snippet of the code from chi_squared() here :
Function Chi_Squared(act, exp, Optional df)
This is how I write to an excel file in Matlab :
Formula_chisqr={[ '=chi_squared(' 'O2:O22' ',' 'M2:22' ')']};
[status, message] = xlswrite1(ExcelFilename,Formula_chisqr,sheetname, Location_Agg);
I also tried giving the complete path as suggested. But it did not work.
Thanks
You have to specify the workbook where the UDF defined. Even if your function is it your PERSONAL.XLSB file. You don't have to do it only if UDF is defined in the same file where you use it.
For example,
='myFunctions.xlsb'!chi_squired(O2:O21,P2:P21)
If myFunctions.xlsb is not opened you may need to specify full path to the file.
If you want to be able to call UDF in any file without specifying the file name, you need to save the file as Add-in, and then enable it in Options - Add-ins - Manage Add-ins.
Another idea: When you use XLSWRITE provide file name with extension XLSX, like test.xlsx, not just test. By default MATLAB saves files with XLS extention in older format. It looks like when you open such file in newer version of Excel (2007/2010) the compatibility mode does not allow macros or UDFs to run.
When you open the Excel as a COM server, the UDF's and Add-ins are not loaded by default. So, you need to first load the add-ins if you would like to use the add-in your Excel file.
Here is the small code snippet in Matlab which loads the add-ins before opening the Excel file.
Excel = actxserver ('Excel.Application');
Excel.Workbooks.Open('C:\YourAddInFolder\AddInNameWithExtension');
Excel.Workbooks.Item('AddInNameWithExtension').RunAutoMacros(1);
File='C:\YourFileFolder\FileName';
if ~exist(File,'file')
ExcelWorkbook = Excel.Workbooks.Add;
ExcelWorkbook.SaveAs(File,1);
ExcelWorkbook.Close(false);
end
Excel.Workbooks.Open(File);
Source : Mathworks
I've written the following function for importing excel files into matlab. The function works fine, where by inserting the path name of the files, the scripts imports them into the workspace. The function is shown below:
function Data = xls_function(pathName);
%Script imports the relevant .xls files into matlab - ensure that the .xls
%files are stored in a folder specified by 'pathName'.
%--------------------------------------------------------------------------
TopFolder = pathName;
dirListing = dir(TopFolder);%Lists the folders in the directory specified
%by pathName.
dirListing = dirListing(3:end);%Remove the first two structures as they
%are only pointers.
for i = 1:length(dirListing);
SubFolder{i} = dirListing(i,1).name;%obtain the name of each folder in
%the specified path.
SubFolderPath{i} = fullfile(pathName, dirListing(i,1).name);%obtain
%the path name for each of the folders.
ExcelFile{i} = dir(fullfile(SubFolderPath{i},'*.xls'));%find the
%number of .xls files in each of the SubFolders.
for j = 1:length(ExcelFile{1,i});
ExcelFileName{1,i}{j,1} = ExcelFile{1,i}(j,1).name;%find the name
%of each .xls file in each of the SubFolders.
for k = 1:length(ExcelFileName);
for m = 1:length(ExcelFileName{1,k});
[status{1,k}{m,1},sheets{1,k}{m,1},format{1,k}{m,1}]...
= xlsfinfo((fullfile(pathName,SubFolder{1,k},...
ExcelFileName{1,k}{m,1})));%gather information on the
%.xls files i.e. worksheet names.
Name_worksheet{1,k}{m,1} = sheets{1,k}{m,1}{1,end};%obtain
%the name of each of the .xls worksheets within
%each spreadsheet.
end
end
end
end
for n = 1:length(ExcelFileName);
for o = 1:length(ExcelFileName{1,n});
%require two loops as the number of excel spreadsheets varies
%from the number of worksheets in each spreadsheet.
TXT{1,n}{o,1} = xlsread(fullfile(pathName,SubFolder{1,n},...
ExcelFileName{1,n}{o,1}),Name_worksheet{1,n}{o,1});%import the
%relevant data from excel by using the spreadsheet and
%worksheet names previously obtained.
Data.(SubFolder{n}){o,1} = TXT{1,n}{o,1};
end
end
The only problem with the script is that it takes too long to run if the number of .xls files is large. I've read that vectorization would improve the running time, therefore I am asking for any advice on how I could alter this code to run faster, through vectorization.
I realise that reading a code like this isn't easy (especially as my form of coding is by no means as efficient as I would like) but any advice provided would be much appreciated.
I don't think vectorization applies to your problem - but one after the other.
As an example for your data you could use cellfun to turn a loop vectorized:
tmp = ExcelFileName{1,n}
result_cell = cellfun(#(x) xlsread(fullfile(pathName,x)),tmp, 'UniformOutput', false))
But the key problem is the poor implementation of xlsread and the other excel related functions in matlab. What they do is with every(!) function call they create a new excel process (which is hidden) in which they perform your command and then end it.
I remember a tool at matlab central that reused the same excel instance and thus was very quick - but unfortunately I can no longer find it. But maybe you can find an example there on which you can base your own reader which reuses it.
On a related note - Excel has the stupid limitation that it doesn't allow you two files with the same name to be opened at the same time - and then fails with some error. So if you run your reading vectorized/parallel you are in for a whole new fun of strange errors :D
For myself I found the only propper way to deal with these documents through java with Apache POI libraries. These have the nice advantage you don't need Excel installed - but unfortunatly require some programming.
I'm trying overwrite a csv file that already exists in Matlab on Windows. The problem is sometimes I have the file open in Excel. When this is the case, the write operation fails.
Is there anyway to overwrite the file in Matlab? I do NOT want to use ActiveX to connect to the Excel session and edit the file that way.
Seeing this post about FileShare settings made me think it might be possible, but none of the fopen parameters seem to be able to do the trick. Excel may be locking the file with exclusive write access, in which case there is no getting around it. Does anyone know how to check this?
Example of problem:
% make csv file
x = magic(4);
csvwrite('foo.csv', x);
% open foo.csv in EXCEL
% try writing again
csvwrite('foo.csv', x); % cannot write a new file
[fid, msg] = fopen('foo.csv' ,'w'); % cannot open handle for writing
As a side note, I used to be able to overwrite a file open in Excel when the file existed on a Linux box, and I had the file open over the network on a Windows box.
Those FileShare settings are for files opened from the Win32 API's CreateFile family of functions, not the C style fopen family, which Matlab exposes. The fopen options won't get you there. See http://support.microsoft.com/kb/99173 for a quick rundown of the differences. (If you really wanted to use CreateFile or other Win32 I/O, e.g. to check to see if Excel has the file locked or lock it yourself, you could call it from Matlab through .NET using System.IO.File.)
Regardless, by default, Excel opens the file in write mode, and gets an exclusive (write) lock. So you couldn't open it for writing anyway, those file sharing settings would only let you open the file for reading. If you want to be able to overwrite an Excel file while it's open in Excel, you need to have Excel open it in read-only mode like katrasnikj suggests. This causes Excel to read it in to memory once and then release the filehandle.
Try turning on the Read-Only file attribute on these files after you write them by shelling out to the attrib command. This will cause Excel to open them read-only by default. Then clear the read-only attribute right before opening it from Matlab for rewriting.
if exist(file, 'file')
[status,result] = system(sprintf('attrib -R "%s"', file));
end
[fid,msg] = fopen(file, 'w');
% ... write the file and close it ...
[status,result] = system(sprintf('attrib +R "%s"', file));
There's still a race condition between reader and writer, but if you write the file fast, it'll be a short window. Better would be to write out the csv to a temp file in the same directory, and then just turn off the read-only attribute long enough to swap the new file in to place with a movefile or java.io.File.renameTo. Still a race, but probably good enough to use in practice.
You could also change the permissions on the directory the files are in so your writer process has Modify permissions but the users running Excel only have Read access. Then the Excels will always open read-only and you don't have to fiddle with file attribs.