My tcl script is designed to update a table in CSV file inserting a new row under its header. Let's say there are only 2 columns: "Date" and "Description". To do that, I first open the CSV file in a read mode, store its whole content as a variable and close that file. Then I open the file again in a write mode and overwrite its content by my variable (which I update according my requirements). The simplified code is:
proc updateCSV {myDescription myDate myPath} {
set newContent "Date,Description\n$myDate,$myDescription";
#Stage A: Process the target file in a read mode:
set targetFile [open $myPath "r"];
#Store the existing content and remove the first line (header-line)
set existingContent [read $targetFile];
set newlinePos [string first "\n" $existingContent];
set oldContent [string range $existingContent $newlinePos+1 end];
close $targetFile;
#Stage B: Process the target file in a write mode:
set targetFile [open $myPath "w"];
#Add the header-line and the new content-line, overwrite the whole existing content:
puts $targetFile $newContent;
#Append the previous content:
seek $targetFile 0 end;
puts -nonewline $targetFile $oldContent;
close $targetFile;
}
What bothers me is that the above solution seems too clumsy. Is there a way to do the same stuff by: a) processing the target file only once; b) avoid overwriting its content but rather updating it directly?
Rather than reading the entire file, modifying it, and then overwriting the content, you can use a different approach that involves reading the file line by line, making modifications as needed, and then writing those changes to a new file. Here's an example using Tcl to update the CSV file directly without overwriting its content:
proc updateCSV {myDescription myDate myPath} {
set tempFile [file tempfile updatedCSV];
set header "Date,Description";
# Open the input file for reading
set inputFile [open $myPath "r"];
set outputFile [open $tempFile "w"];
# Read and write the header to the output file
puts $outputFile $header;
# Flag to indicate whether the header was found
set headerFound 0;
# Process each line of the input file
while {[gets $inputFile line] != -1} {
if {!$headerFound && [string equal $line $header]} {
# Skip the existing header in the input file
set headerFound 1;
continue;
}
# Write the line to the output file
puts $outputFile $line;
}
# Append the new row to the end of the file
puts $outputFile "$myDate,$myDescription";
# Close both files
close $inputFile;
close $outputFile;
# Replace the original file with the updated file
file rename -force $tempFile $myPath;
}
This script reads the input CSV file line by line. It skips the existing header and writes all other lines to a temporary file (updatedCSV). After processing all lines, it appends the new row ($myDate,$myDescription) to the end of the file and then replaces the original file with the updated one.
This way, you're not required to store the entire content in a variable, and it operates more efficiently by directly modifying the file as needed without overwriting its content entirely.