I want to update a line in a txt file which contains property-values pairs, where a property is between square brackets and its value in the line below. This is an example file: On top of that i want to ignore the comment lines started with '#'. On the other hand what if i want to add comments to the comment line?
#===========================
#===========================
[system]
# comment
programming
#===========================
[information]
#
application
In this example, ´system´ is a property and ´programming´ its value. The same way, ´information´ is another property and ´application´ its value.
I want to call my function with a property-value pair and update the corresponding values in the txt file. Until now I have the following:
fh = fopen(filename,'r');
fh= fopen(filename,'w');
while ~feof
line = fgetl(fh);
if(line(1) == '[') && (line(end) == ']')
value = lower(line(2:end-1));
Then I will compare the 'value' with my input to check if it matches with property. If so I should update the next line with the new input. Finally I have to write to the original file.
For this sample txt how can I update the word 'programming' to 'system information'?
How about
function [] = updateFile( fileName, propName, newProbVal )
%
% update file fileName, replacing the value of propName with newPropVal
%
% all inputs are strings
%
rfh = fopen( fileName, 'r' ); % read handle
tname = tempname(); % temporary file name
wfh = fopen( tname, 'w' );
% read line by line
foundFlag = false;
line = fgetl( rfh );
while ischar(line)
if foundFlag
fprintf( wfh, '%s\r\n', newProbVal );
foundFlag = false;
else
fprintf( wfh, '%s\r\n', line );
end
tks = regexp( line, ['^\[',propName,'\]'] );
foundFlag = ~isempty(tks);
line = fgetl( rfh );
end
fclose( rfh );
fclose( wfh );
movefile( tname, fileName, 'f' ); % rename temp file name
Related
I have a text file with data structure like this
30,311.263671875,158.188034058,20.6887207031,17.4877929688,0.000297248129755,aeroplane
30,350.668334961,177.547393799,19.1939697266,18.3677368164,0.00026999923648,aeroplane
30,367.98135376,192.697219849,16.7747192383,23.0987548828,0.000186387239864,aeroplane
30,173.569274902,151.629364014,38.0069885254,37.5704650879,0.000172595537151,aeroplane
30,553.904602051,309.903320312,660.893981934,393.194030762,5.19620243722e-05,aeroplane
30,294.739196777,156.249740601,16.3522338867,19.8487548828,1.7795707663e-05,aeroplane
30,34.1946258545,63.4127349854,475.104492188,318.754821777,6.71026540999e-06,aeroplane
30,748.506652832,0.350944519043,59.9415283203,28.3256549835,3.52978979379e-06,aeroplane
30,498.747009277,14.3766479492,717.006652832,324.668731689,1.61551643174e-06,aeroplane
30,81.6389465332,498.784301758,430.23046875,210.294677734,4.16855394647e-07,aeroplane
30,251.932098389,216.641052246,19.8385009766,20.7131652832,3.52147743106,bicycle
30,237.536972046,226.656692505,24.0902862549,15.7586669922,1.8601918593,bicycle
30,529.673400879,322.511322021,25.1921386719,21.6920166016,0.751171214506,bicycle
30,255.900146484,196.583847046,17.1589355469,27.4430847168,0.268321367912,bicycle
30,177.663650513,114.458488464,18.7516174316,16.6759414673,0.233057001606,bicycle
30,436.679382324,273.383331299,17.4342041016,19.6081542969,0.128449092153,bicycle
I want to index those file with a label file.and the result will be something like this.
60,509.277435303,284.482452393,26.1684875488,31.7470092773,0.00807665128377,15
60,187.909835815,170.448471069,40.0388793945,58.8763122559,0.00763951029512,15
60,254.447280884,175.946624756,18.7212677002,21.9440612793,0.00442053096776,15
However there might be some class that is not in label class and I need to filter those line out so I can use load() to load in.(you can't have char inside that text file and execute load().
here is my implement:
function test(vName,meta)
f_dt = fopen([vName '.txt'],'r');
f_indexed = fopen([vName '_indexed.txt'], 'w');
lbls = loadlbl()
count = 1;
while(true),
if(f_dt == -1),
break;
end
dt = fgets(f_dt);
if(dt == -1),
break
else
dt_cls = strsplit(dt,','){7};
dt_cls = regexprep(dt_cls, '\s+', '');
cls_idx = find(strcmp(lbls,dt_cls));
if(~isempty(cls_idx))
dt = strrep(dt,dt_cls,int2str(cls_idx));
fprintf(f_indexed,dt);
end
end
end
fclose(f_indexed);
if(f_dt ~= -1),
fclose(f_dt);
end
end
However it work very very slow because the text file contains 100 thousand of lines. Is it anyway that I could do this task smarter and faster?
You may use textscan, and get the indices/ line numbers of the labels you want. After knowing the line numbers, you can extract what you want.
fid = fopen('data.txt') ;
S = textscan(fid,'%s','delimiter','\n') ;
S = S{1} ;
fclose(fid) ;
%% get bicycle lines
idx = strfind(S, 'bicycle');
idx = find(not(cellfun('isempty', idx)));
S_bicycle = S(idx)
%% write this to text file
fid2 = fopen('text.txt','wt') ;
fprintf(fid2,'%s\n',S_bicycle{:});
fclose(fid2) ;
From S_bicycle, you can extract your numbers.
I want to acces a .csv file, look for empty data blocks and store all of the lines that have no empty data blocks.
This is my code:
filename = 'C:\Users\try.csv';
file1 = fopen(filename); %Acces file with empty data blocks
filename2 = 'C:\Users\try_corrected.csv';
file2 = fopen(filename2); %Acces destination file
tline = fgets(file1); %Read the first line of file1
while ischar(tline)
detected = false;
[r,s] = size(tline); %Determine the lengt of the textline for the for-loop
for(i=1: 1: s)
if( (tline(i)==',' && tline(i+1) ==',') || tline(1)==',' || tline(s-2)==',' )
detected = true %Line should not be printed in destination file
break;
end
end
if detected == false
fprintf(file2,'%s\n',tline);
end
tline = fgets(file1);
end
type 'C:\Users\try_corrected.csv'
fclose(file2);
textdata = textscan(file1, '%s %f %f %f %s %f %f %f %s %f %s','HeaderLines', 1,'Delimiter',',');
fclose(file1);
If I do the "type" command, I should see all the printed strings which is not the case.
Am I using fprintf wrong? I know there is a command called csvwrite but I thought this could work too?
First, when you open your destination file you need to open it for writing. Without a second parameter fopen will open for read access. If your destination file did not exist it would return you a -1 file handle.
Use instead:
fopen(filename2,'w')
Here is a simplified version of your code including that amendment:
filename = 'c:\try.csv';
fid_in = fopen(filename,'r'); %Access file with empty data blocks
filename2 = 'C:\try_corrected.csv';
fid_out = fopen(filename2,'w'); %Access destination file
while (~feof(fid_in))
str=fgets(fid_in);
if (~doublecommas(str))
fprintf(fid_out,'%s',str);
end
end
fclose(fid_in);
fclose(fid_out);
type(filename2)
This uses a different method to detect double presence of commas in the CSV line:
function flag=doublecommas(str)
flag=false; % flag = result returned,
% true if empty CSV fields present in line
if (ischar(str) && length(str)>0)
for cindex=1:length(str)-1
if strcmp(str(cindex:(cindex+1)),',,')
flag=true; break;
end
end
end
return;
This question already has an answer here:
Property_value + matlab
(1 answer)
Closed 9 years ago.
How to read and write ini files: I want to add new property to an existing one. I want to write the ini file to temp file and finally add the new property to it. the new property will have head,name,desc, value and layout (like: line 1 & 3)
#---------------
# head
# --------------
[name]% type
# desc
value
fileData = [];
fh = fopen( fileName, 'r' ); % read handle
tname=tempname();
wfh =fopen(tname,'w'); % write handle
line = fgetl(fh);
val = '';
Prop ='';
type = '';
header = '';
desc= '';
while ischar(line)
if strcmpi(line(1),'#') && strcmpi(line(3),'=')
layout = line(2:end);
elseif strcmpi(line(1),'#')&& ~strcmpi(line(3),'=')
header = line(2:end);
else
Prop = regexp(line,{'\[*\w+\]\s*%\s*.*\s*'},'match');
[property data_type] = strtok(Prop,'%')
prop_p = property{1};% property_name
prop_per = regexprep(prop_p,{'\[','\]'},'');
prop = prop_per{1};
Dtype = data_type{1}; % datatype
dtype = strtrim(strrep(Dtype,'%',''));
DATA_type = dtype{1};
end
% How can i define filedname (prop) for the 'layout' and 'header' as they are found in lines before the actual'prop'.
% From command window
% Undefined variable prop.
% Error in ecco2511>add (line 212)
% fileData.(prop{1}).layout = layout;
desc = fgetl(fh); % description
desc = desc(1:end);
line = fgetl(fh);
val = line(1:end);
fileData.(prop).layout = layout;
fileData.(prop).header = header;
fileData.(prop).type = DATA_type;
fileData.(prop).desc = desc;
fileData.(prop).val = val;
line = fgetl(fh); % keep reading
end
if ~isfield( fileData, propName)
fileData.(propName).val = newVal;
fileData.(propName).type = datatype;
fileData.(propName).desc = description;
fileData.(propName).layout = layout;
fileData.(propName).header = header;
else
error ( 'property %s already exists, use set to change its value',propName );
end
fileData = orderfields( fileData );
propNames = fieldnames( fileData );
for ii = 1:numel( propNames )
fprintf(wfh,'%s\r',fileData.(propNames{ii}).layout);
fprintf(wfh,'\n');
fprintf(wfh,'%s\r',fileData.(propNames{ii}).header);
fprintf(wfh,'\n');
fprintf(wfh,'%s\r',fileData.(propNames{ii}).layout);
fprintf(wfh,'\n');
fprintf( wfh, '[%s]%s\r', (propNames{ii}),fileData.(propNames{ii}).type);
fprintf(wfh,'\n');
fprintf( wfh,'#%s\r',fileData.(propNames{ii}).desc);
fprintf(wfh,'\n');
fprintf( wfh,'%s\r',fileData.(propNames{ii}).val);
fprintf(wfh,'\n');
end
fclose(fh);
fclose(wfh);
[status,errmsg]= movefile(tname,fileName,'f');
Sounds like you need INI Config from MATLAB File Exchange. It will allow you to read, write, and modify INI style files. I have used it a number of times and it works quite well.
I have 100 ASCII files in my directory all named as follows:
int_001.ASC
int_002.ASC
int_003.ASC
.
.
.
int_099.ASC
int_100.ASC
I have to import them in MATLAB all with importdata, which should work as follows:
A = importdata('int_001.ASC', ' ', 9)
x = A.data(:,1)
y = A.data(:,2)
My question is: how can I avoid writing 100 times importdata? Is there a way to write the first string only and then have all data uploaded?
Thanks
fls = dir( 'int_*.ASC' );
for fi=1:numel(fls)
A{fi} = importdata( fls(fi).name, ' ', 9 );
% ...
end
UPDATE:
You may use string formatting to read the files according to their numbers:
for fi=1:100
A{fi} = importdata( sprintf('int_%03d.ASC', fi ), ' ', 9 );
% ...
end
You can use strcat function in a for loop :
for k=1:n
fileName = strcat('int_',num2str(k, '%03d'),'.ASC');
A(k) = importdata(fileName, ' ', 9);
x(k) = A(k).data(:,1);
y(k) = A(k).data(:,2);
end
If you want to take this a little overboard:
alldata = arrayfun(...
#(dirEntry)importdata(dirEntry.name, ' ', 9), ...
dir('int_*.ASC'),...
'uniformoutput',false);
This line does the following
Gets a listing of all files matching the partial filename, as an array of structures (h/t Shai)
For each element in that array, performs the importdata call from your original post.
Compiles all the outputs into a cell array.
I want to add a property-value pair to existing file. In the mean time all the properties should be ordered in alphabetical order. For example :
[Info] % property 1
value 1
[system] % property 2
value 2
How can i add additional property such that all properties will be sorted in alphabetical order. I was able to add property -value pair to the end of the file using
fh = fopen(filename,'a') but i am not able to sort them alphabetically.
so far i tried this as follows but with this one it keeps printing only the new property-value pair . I want to print remaining properties onces it prints the new one.
function [] = myfun(filename ,propName,propvalue)
rfh = fopen(filename,'r');
tname = tempname();
wfh = fopen(tname,'w');
line = fgetl(rfh);
while ischar(line)
if (line(1) == '[') && (line(end) == ']')
property = lower(line(2:end-1)) % from ini file
String2 = property;
String1 = propName;
[sat] = sor(String1,String2)% subfunction
if sat == -1
fprintf(wfh,'[%s]\r\n%s\r\n',propName,propvalue);
else
fprintf(wfh,'%s\r\n',line);
end
else
fprintf(wfh,'%s\r\n',line);
end
line = fgetl(rfh);
end
fclose(rfh);
fclose(wfh);
movefile(tname,filename,'f')
function [sat] = sor(String1,String2)
Index = 1;
while Index < length(String1) && Index < length(String2) && String1(Index) == String2(Index)
Index = Index + 1;
end
% Return the appropriate code
if String1(Index) < String2(Index)
sat= -1
elseif String1(Index) > String2(Index)
sat= +1
else % the characters at this position are equal -- the shorter of the two strings should be "less than"
if length(String1) == length(String2)
sat = 0
elseif length(String1) < length(String2)
sat = -1
else
sat = +1
end
end
Is this a .ini file? You might want to take a look at INIConfig from the MATLAB File Exchange, a set of routines for handling INI files arranged in a convenient class. I haven't used it, but perhaps it might do what you need.
If not, you can always:
Read in the file
Loop through it line by line
When you find a line starting with [ followed by a word alphabetically later than the property you'd like to insert, insert your property and value
Include the remainder of the file
Write the whole file back out again.
How about read the file into a struct?
function fileData = readFileIntoStruct( fileName )
%
% read [property] value pairs file into struct
%
fh = fopen( fileName, 'r' ); % read handle
line = fgetl( fh );
while ischar( line )
% property
tkn = regexp( line, '\[([^\]+)]\]', 'once', 'tokens' );
% read next line for value
val = fgetl( fh );
fileDate.(tkn{1}) = val;
line = fgetl( fh ); % keep reading
end
fclose( fh ); % don't forget to close the file at the end.
Now you have all the data as a struct with properties as fieldnames and values as the field value.
Now you can update a property simply by:
function fileData = updateProperty( fileData, propName, newVal )
if isfield( fileData, propName )
fileData.(propName) = newVal;
else
warning( 'property %s does not exist - please add it first', propName );
end
You can add a property:
function fileData = addProperty( fileData, propName, newVal )
if ~isfield( fileData, propName )
fileData.(propName) = newVal;
else
warning ( 'property %s already exists, use update to change its value', propName );
end
You can sort the properties alphabetically using orderfields:
fileData = orderfields( fileData );
You can write the struct back to file simply using:
function writeDataToFile( newFileName, fileData )
fopen( newFileName , 'w' ); %write handle
propNames = fieldnames( fileData );
for ii = 1:numel( propNames )
fprintf( fh, '[%s]\r\n%s\r\n', propNames{ii}, fileData.(propNames{ii}) );
end
fclose( fh );
Assumptions:
The properties' names are legitimate Matlab field names (see variable naming for details).
The value of each property is always a string.
I did not include any error-checking code in these examples (files not found, wrongly formatted strings, etc.)
I assume the input file is strictly "[prop] val" pairs without any additional comments etc.