How can I read a simple txt file in Matlab in the fortran way (i.e. I want to keep reading after the newline) - matlab

I have to read the simple text file I write on the end of this post (it is just a sctructured grid). In fortran it is so easy to do this, you just have to do:
read(fileunit,*)
read(fileunit,*) mc,nc
do j = 1, nc
read (fileunit, *) dummy, dummy, (xcor(j,i), i=1,mc)
enddo
is there an equivalent function in matlab that reads element by element and keeps reading after the newline like in fortran? I could not find it, all the function as fscanf, textscan etc read line by line and then i have to parse each line. Here is the file. thanks for any help A.
Gridfile version 8.675.44
8 3
eta= 1 0.00000000000000000E+00 1.50000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
eta= 2 0.00000000000000000E+00 1.50000000000000000E+02
3.00000000000000000E+02 4.50000000000000000E+02
7.50000000000000000E+02 9.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02
eta= 3 0.00000000000000000E+00 1.50000000000000000E+02
3.00000000000000000E+02 4.50000000000000000E+02
7.50000000000000000E+02 9.00000000000000000E+02
4.50000000000000000E+02 6.00000000000000000E+02

There are many ways to do this, but perhaps you will like the way fscanf works, as in this example. After the file is opened by something like fin = fopen('gridfile.txt') and the header swallowed, you can use fscanf(f, 'x= %d'), and then fscanf(f, '%f'), which will read the entire block. fscanf does not stop at the end of a line if not instructed to do so. Taken together, a solution could look like
fin = fopen('gridfile.txt');
fgetl(fin);
% read data counts
cnt = fscanf(fin, '%d %d', 2);
mc = cnt(1);
nc = cnt(2);
xcor = zeros(nc, mc);
% read blocks of data
for j = 1 : nc
fscanf(fin, '%s %s', 2);
xcor(j, :) = fscanf(fin, '%f', mc)';
end
fclose(fin);
fscanf keeps matching the format specifier as long as possible, and returns only when no further consecutive matches can be found. The above examples uses this in two places. First, to extract the dimensionality cnt, in your example (8, 3), and second, to read eight consecutive floating point values per record.

Related

MATLAB : read data file in real time

I have an application, A, that writes to a File.
I want to use MATLAB to read N lines in realtime from this file.
My question is related to this stack post: How to plot real time data from text file in MATLAB
The author of one of the answers, mentions the following approach:
You can't plot using hard real time conditions, thus it can always happen that matlab misses a 10ms timeslot. You have to use option 2 to get all data.
To get started: Write a function which only reads the new data which was written since last call. To achieve this, do not close the file handle. It stores the position.
As such, here is my code:
myfile_fid=fopen(filePath, 'rt')
waitForFileToHaveData(filePath, 10);
for readingIdx = 1:10
fgetl(myfile_fid)
end
My waitForFileToHaveData function, is defined as follows:
function waitForFileToHaveData(filePath, desired_length)
if (getNumLinesOfFile(filePath) < desired_length)
disp('###### not enough data in the file');
pause(0.02);
waitForFileToHaveData(filePath, desired_length);
end
end
function num = getNumLinesOfFile(file_to_read)
[status, result] = system( ['wc -l ', file_to_read] );
if(status~=1)
scanCell = textscan(result,'%u %s');
num = scanCell{1} - 2;
else
num = 0;
end
end
Result:
When I get into the for loop, myfile_fid evaluates to 3, while fgetl(myfile_fid) evaluates to -1. If I print out the results of getNumLinesOfFile(filePath), I see 20. The odd part is that if I wait, say for the file to have 40 lines, and execute the code above, I do not get the error. I tried to look at the documentation to see why fgetl returns back -1, but I cannot seem to find it in 2018b MATLAB documentation. There is mention that the myfile_fid can return a -1, but that is only if the file cannot be opened. However, at runtime, myfile_id evaluates to 3.
Using MATLAB, is it possible to read N number of lines since last read in a file that is being written to by another application?
fgetl returns -1 when fileID reaches the end-of-file marker, See Matlab fgetl documentation. This means that if the first result from fgetl is -1 then the file is empty.
I'm not sure why you are getting -1 if getNumLinesOfFile returns 20, check the code carefully if you are reading the same file. Maybe the file has changed?
I wrote here MATLAB code that checks if 10 new lines were added and and then gets them with fgetl:
myfile_fid = fopen(filePath, 'rt');
newLines = 10;
linesRead = 0;
while(waitForFileToHaveData(filePath, linesRead + newLines))
linesRead = linesRead + newLines;
for readingIdx = 1:newLines
line = fgetl(myfile_fid)
end
end
fclose(myfile_fid);
I updated the waitForFileToHaveData function to return 1:
function ready = waitForFileToHaveData(filePath, desired_length)
while (getNumLinesOfFile(filePath) < desired_length)
disp('###### not enough data in the file');
pause(0.02);
end
ready = 1;
end
Note:
If the file had exactly 10 lines with no end-line marker at line 10, and you read them, then another 10 lines were added, fileID now points to the end-line of line 10 and the first line fgetl will return is the end-line at line 10, but since fgetl removes the end-line, it returns an empty array.
Side note:
the function waitForFileToHaveData uses recursion which is inefficient. You can easily use a while loop.

Loading text file as a 2D array of strings without specifying the number of columns

Suppose I have a plaintext file test.dat:
foo bar baz
qux ham spam
I know want to load this into Octave (or Matlab if necessary) as a two-dimensional cell array, preserving the structure encoded in whitespace and newlines. According to my understanding of the documentation, the following should be the way to go:
format = '%s';
file = fopen('test.dat');
data = textscan(file,format);
fclose(file);
disp(data);
However this only loads the data as a one-dimensional array:
{
[1,1] =
{
[1,1] = foo
[2,1] = bar
[3,1] = baz
[4,1] = qux
[5,1] = ham
[6,1] = spam
}
}
Explicitly specifying Delimiter, Whitespace, and EndOfLine does not help (what’s the point of the latter then?); neither does using other loading functions like textread or dlmread. What does work is using format = '%s%s%s' in the above but this requires that I somehow identify the number of columns, which the function should be able to do itself.
Thus I ask: Is there any built-in function that does what I want? I am not interested in ways to write such a function myself – I am confident that I can do this, but that’s exactly what I want to avoid (as I need to use this for demonstrating good practice, and thus not re-inventing the wheel).
Related Q&As (that all work with knowing the number of columns):
How to load 2D array from a text(csv) file into Octave?
How do I read a delimited file with strings/numbers with Octave?
You can use readtable
data = readtable('test.txt', 'ReadVariableNames', false, 'Delimiter', ' ')
Output:
Var1 Var2 Var3
_____ _____ ______
'foo' 'bar' 'baz'
'qux' 'ham' 'spam'
If you wanted a cell, not a table, you could use
data = table2cell( data );
>> data = {'foo' 'bar' 'baz'
'qux' 'ham' 'spam'}
I'm not sure that readtable is an Octave method, it seems to be on GitHub but I have no installation to check. It was introduced to Matlab in 2013b.
You could use lower level actions, reading the lines one by one
fid = fopen('test.txt','r');
data = {};
while ~feof(fid)
line = fgets(fid); % Read line
A = strsplit(line, ' '); % Split on spaces
data(end+1, :) = A; % Append to output
end
fclose(fid);
>> data = {'foo' 'bar' 'baz'
'qux' 'ham' 'spam'}
This method assumes each row of data will have the same number of elements (same number of delimiters in each line). If you can't assume that, then a safer way would be to do data{end+1,1} = A, then splitting the lines afterward.
The only function used in this method which isn't low level file I/O is strsplit. This is a built-in for Octave and Matlab.
In Octave you can use csv2cell from the package io:
pkg load io
result = csv2cell('test.dat',' ')
I would suggest that you have a look at fgetl() or fgets() functions.
Basically you read the lines of the file and then you can apply your code with textscan() and get the "columns".
I had the same problem. readtable.m was slow for me in Matlab, and fgetl examples are resizing in a loop.
But perhaps an acceptable solution is based on this forum post:
https://de.mathworks.com/matlabcentral/answers/476483-how-to-use-textscan-on-a-cell-array-without-a-loop
So, at least in newer Matlab:
fid=fopen(file,'r');
data=textscan(fid,'%s','Delimiter','\r\n');
fclose(fid);
data=split(data{1},';',1);
I haven't tested split.m for speed with large data though.

extracting numeric data from text in data files in Matlab

I have a .txt data file which has a few rows of text comments in the beginning, followed by the columns of actual data. It looks something like this:
lens (mm): 150
Power (uW): 24.4
Inner circle: 56x56
Outer Square: 256x320
remarks: this run looks good
2.450000E+1 6.802972E+7 1.086084E+6 1.055582E-5 1.012060E+0 1.036552E+0
2.400000E+1 6.866599E+7 1.088730E+6 1.055617E-5 1.021491E+0 1.039043E+0
2.350000E+1 6.858724E+7 1.086425E+6 1.055993E-5 1.019957E+0 1.036474E+0
2.300000E+1 6.848760E+7 1.084434E+6 1.056495E-5 1.017992E+0 1.034084E+0
By using importdata, Matlab automatically separates the text data and the actual data . But how do I extract those numeric data from the text (which is stored in cells format)? What I want to do to achieve:
extract those numbers (e.g. 150, 24.4)
If possible, extract the names ('lens', 'Power')
If possible, extract the units ('mm', 'uW')
1 is the most important and 2 or 3 is optional. I am also happy to change the format of the text comments if that simplifies the codes.
Let's say your sample data is saved as demo.txt, you can do the following:
function q47203382
%% Reading from file:
COMMENT_ROWS = 5;
% Read info rows:
fid = fopen('demo.txt','r'); % open for reading
txt = textscan(fid,'%s',COMMENT_ROWS,'delimiter', '\n'); txt = txt{1};
fclose(fid);
% Read data rows:
numData = dlmread('demo.txt',' ',COMMENT_ROWS,0);
%% Processing:
desc = cell(5,1);
unit = cell(2,1);
quant = cell(5,1);
for ind1 = 1:numel(txt)
if ind1 <= 2
[desc{ind1}, unit{ind1}, quant{ind1}] = readWithUnit(txt{ind1});
else
[desc{ind1}, quant{ind1}] = readWOUnit(txt{ind1});
end
end
%% Display:
disp(desc);
disp(unit);
disp(quant);
disp(mat2str(numData));
end
function [desc, unit, quant] = readWithUnit(str)
tmp = strsplit(str,{' ','(',')',':'});
[desc, unit, quant] = tmp{:};
end
function [desc, quant] = readWOUnit(str)
tmp = strtrim(strsplit(str,': '));
[desc, quant] = tmp{:};
end
We read the data in two stages: textscan for the comment rows in the beginning, and dlmread for the following numeric data. Then, it's a matter of splitting the text in order to obtain the various bits of information.
Here's the output of the above:
>> q47203382
'lens'
'Power'
'Inner circle'
'Outer Square'
'remarks'
'mm'
'uW'
'150'
'24.4'
'56x56'
'256x320'
'this run looks good'
[24.5 68029720 1086084 1.055582e-05 1.01206 1.036552;
24 68665990 1088730 1.055617e-05 1.021491 1.039043;
23.5 68587240 1086425 1.055993e-05 1.019957 1.036474;
23 68487600 1084434 1.056495e-05 1.017992 1.034084]
(I took the liberty to format the output a bit for easier viewing.)
See also: str2double.

How to print and save result of a Table in a text format in a loop?

result 'output1' 'output2'
result1 [1.0000] [0.0182]
counter [ 2] [ 0]
percentage [ 4] [ 7]
I have an output stored in a table (T), I want to print all my 200 loop results in just one text file. I already tried with writetable function and always have a problem, the output overwrite the previous output.
fid = fopen(filename,'w');
for i = 1:200
writetable(T,'finalresult.txt','Delimiter','\t','WriteRowNames',true);
end
fclose(fid);
the output should be like this:
result 'output1' 'output2'
result1 [1.0000] [0.0182]
counter [ 2] [ 0]
percentage [ 4] [ 7]
result 'output1' 'output2'
result1 [0.0182] [1.0000]
counter [ 3] [ 0]
percentage [ 4] [ 7]
and so on for all the outputs i = 200
Per MATLAB's documentation for writetable, this is the default behavior.
If filename is the name of an existing text file, then writetable overwrites the file.
This gives you two options: create your own export routine or overload MATLAB's with the desired behavior. Let's look at the latter.
Warning: Modifying default MATLAB behavior can lead to unexpected results and errors. Take care to modify only copies of MATLAB's default files so you can revert MATLAB's state when you are finished.
Fortunately for us, the source code for table and its related methods are currently open so you can use open to read them and understand their behavior. We see that writetable is a thin wrapper for the undocumented table.write, which parses the input arguments and makes the determination whether or not to write to a text file or to a spreadsheet. For the text case MATLAB calls the writeTextFile function (again, undocumented) which handles writing table data to a text file.
If you look at line 25, you will see that MATLAB opens the file for writing as follows:
% Open the file for writing
[fid,errmsg] = fopen(file,'Wt'); % text mode: CRLF -> LF
Per the documentation for fopen this opens the file for writing ('W'), which will discard any existing contents. Saving a copy of writeTextFile and changing the fopen call to append data rather than overwrite it should give the desired behavior.
% Open the file for writing
fprintf('!!! Using overloaded writeTextFile D:\n%s\n', mfilename('fullpath'));
[fid,errmsg] = fopen(file,'At'); % text mode: CRLF -> LF
Per MATLAB's Function Precedence Order, Private or Object functions take precedence over functions in MATLAB's path, so we need to place this modified file in the same location as the original. You can find this location this using which -all:
>> which writeTextFile -all
C:\excaza\writeTextFile.m
C:\Program Files\MATLAB\R2016b\toolbox\matlab\datatypes\#tabular\writeTextFile.m % tabular method
You should see your saved copy and MATLAB's built-in version. You should now rename the built-in function (e.g. writeTextFile_builtin.m) and copy your modified version of the file into the folder. Run a clear all once to clear any memory cached version of the function.
We can now test to see if we've achieved the desired result:
filename = 'test.txt';
var1 = 1;
var2 = 2;
T1 = table(var1, 'RowNames', {'hi'});
T2 = table(var2, 'RowNames', {'hi'});
writetable(T1, filename)
writetable(T2, filename)
Which returns the following test.txt:
Row var1
hi 1
Row var2
hi 2
When you are done, be sure to revert the changes you made to the built-in.
a1=0.1;
a2=0.2;
opt =fopen('test.txt','a');
for i=1: size(t,1)
j=1;
if(i==1)
s=strcat('\n','result','\t',t(i,j),'\t',t(i,j+1),'\n');
s=s{1};
end
if (i==2)
a1=t{i,j};
a2=t{i,j+1};
s=strcat('\n','result1','\t',num2str(a1),'\t',num2str(a2),'\n');
end
if (i==3)
a1=t{i,j};
a2=t{i,j+1};
s=strcat('\n','counter','\t',num2str(a1),'\t',num2str(a2),'\n');
end
if (i==4)
a1=t{i,j};
a2=t{i,j+1};
s=strcat('\n','counter1','\t',num2str(a1),'\t',num2str(a2),'\n');
end
if (i==5)
a1=t{i,j};
a2=t{i,j+1};
s=strcat('\n','percentage','\t',num2str(s1),'\t',num2str(s1),'\n');
end
fprintf(opt,s);
end
the output will be like this
result output1 output2
result1 1.0000 0.0182
counter 1 1
counter1 0 0
percentage 0 0
I solved it without doing any function modification. #Brian thank you for the answer, and clear explanation.

How to fix error: "A(I): index out of bounds; value 1 out of bound 0"

So I made this function, but I don't know why I'm getting this error. How can I fix it?
error: LOADC: A(I): index out of bounds; value 1 out of bound 0
error: called from
LOADC at line 15 column 13
function res=LOADC(url)
[nomeFicheiro,sucesso]= urlwrite(url,'Composicoes.txt');
ficheiro=fopen(nomeFicheiro,'r');
fgetl(ficheiro);
nLinhas=0;
while (fgets(ficheiro) ~= -1)
nLinhas = nLinhas+1;
end
for i=2:nLinhas
linha=fgetl(ficheiro);
pontovirgula=findstr(linha,';');
Material=linha(1:pontovirgula(1)-1);
for n=1:2:length(pontovirgula)
ElemX=linha(pontovirgula(n)+1:pontovirgula(n+1)-1);
PercentX=linha(pontovirgula(n+1)+1:pontovirgula(n+2)-1);
end
end
fclose(ficheiro);
res=Composicoes;
end
The immediate is you're trying to access a value within an empty array (which has no values in it).
The reason that this is happening is that you read your entire file inside of your first while loop which places the file pointer at the end of the file. Then (without resetting the file pointer), you try to read it line by line in the for loop. Since the file pointer is at the end of the file already, fgetl will always return an empty array ([]) so when you start trying to work with it, you get the indexing error that you've shown.
The solution is one of two options:
Call frewind(ficheiro) before the for loop to reset the file pointer to the beginning of the file so that you can successfully read each line.
Come up with a better way to parse your file rather than looping through the whole file for the sole purpose of counting the number of lines in the file.
If you post some of the file contents we can likely provide you with a better way to parse the file in one or two lines of code.
Update
Also if you look at this line, n goes all the way to the end of pontovirgula.
for n = 1:2:length(pontovirgula)
But then you try to access 1 and 2 past the end of the array
pontovirgula(n+1)
pontovirgula(n+2)
This is going to cause issues for sure. Try only looping until 2 from the end instead.
for n = 1:2:(numel(pontovirgula) - 2)
Update 2
Given that you have posted the file contents, here is an alternate way to parse the file.
fid = fopen('filename.txt', 'rt');
lines = textscan(fid, '%s', 'HeaderLines', 1);
fclose(fid);
% For each line we want to get the reference off of the front
parts = regexp(lines{1}, ';', 'split');
materials = cell(1, numel(parts));
elements = cell(1, numel(parts));
percentages = cell(1, numel(parts));
for k = 1:numel(parts)
% Remove the last empty blank
parts{k}(end) = [];
% Get the material (the first element)
materials{k} = parts{k}{1};
% Get the elements
elements{k} = parts{k}(2:2:end);
% Get the percents
percents{k} = parts{k}(3:2:end);
end
Check the length of linha, and the values of pontovirgula that you are using to index into linha.