Reputation: 3
I am very new to tcl, and am working through basic example to get some good understanding before I start my project.
I would appreciate if someone would help or advice the best way of deleting specific contents of a file.
In my case I have some data in LogData.dat file, I would like to open this file delete Line number 3 and at same time delete the first column (#Name, #Index#, #mspace) and then save the file after the changes have been made.
The number of columns may be more than 5 but it is always the first column with #Name, #Index#, #mspace that needs deleting and line 3 that needs deleting.
I wondering is it better to first delete line 3 (which gets rid of #mspace) and then match words #Name, #Index with regexp and then somehow delete #Name & #Index
I also need to keep in mind that these files might be very large (100mb) and there will be multiple files so I’d need to loop these till all files are modified. Therefore need to avoid any memory problems, if I have to read and write such big files quickly.
Would appreciate if some can give some help or provide an easy clean example.
Example (cut down version) shown below.
#Name Length Width height Time
#Index m - - s
#mSpace 0 0 0 0
13.4112 0 0 0
13.411177 0 1.8827043e-007 0.001
13.411122 0 1.8827043e-007 0.002
Upvotes: 0
Views: 3255
Reputation: 13282
I'll swipe Jerry's suggestion to read from one file and write to another:
set input [open LogData.dat r]
set output [open newLogData.dat w]
The fields don't seem to be character-delimited, so split
won't work as intended. If every line is a proper list with no whitespace within the fields, this will not cause any problems.
If the third line always has the string #mSpace
in the first field and no other line has it in the first field, we don't need to count lines. (Update: fixed stupid typo in the if
condition, sorry.)
# Loop through each line of the file
while {[chan gets $input line] != -1} {
set data [lassign $line first]
if {$first ne "#mSpace"} {
chan puts $output $data
}
}
On output, this code will compact consecutive whitespace characters between the fields into single space characters.
chan close $input
chan close $output
This code removes the first field from every line, since that seemed to be what you were asking for. Re-reading your question, it now seems that you only wanted to take it out in the first three lines. Updated code:
# Loop through each line of the file
while {[chan gets $input line] != -1} {
set data [lassign $line first]
if {[string match #* $first]} {
if {$first ne "#mSpace"} {
chan puts $output $data
}
} else {
chan puts $output $line
}
}
Documentation: chan, if, lassign, open, set, while
(Note: the 'Hoodiecrow' mentioned in the comments is me, I used that nick earlier.)
Upvotes: 0
Reputation: 71598
I would suggest you to read the file and write to another to make it easier to follow your own code. You could do it a bit like that:
# Open file for reading
set input [open "LogData.dat" r]
# Open file for writing
set output [open "newLogData.dat" w]
# This variable will help us know the line number
set ln 0
# Loop through each line of the file
while {[gets $input line] != -1} {
incr ln
if {$ln < 4} {
if {$ln < 3} {
# On lines 1 to 2, split the line on tab, remove the first
# element of the result list and join it back with tabs
set line [join [lreplace [split $line \t] 0 0] \t]
} else {
# Skip line 3 completely
continue
}
}
puts $output $line
}
close $input
close $output
You don't really need regex in there, the above is an example with the file contents already in a variable.
You can put something like file delete LogData.dat
and file rename newLogData.dat LogData.dat
to remove the initial file and rename the new one with the old one's name.
Upvotes: 2