egghelp.org community Forum Index
[ egghelp.org home | forum home ]
egghelp.org community
Discussion of eggdrop bots, shell accounts and tcl scripts.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Basic File Operations

 
Post new topic   Reply to topic    egghelp.org community Forum Index -> Tcl FAQ
View previous topic :: View next topic  
Author Message
stdragon
Owner


Joined: 23 Sep 2001
Posts: 959

PostPosted: Wed Feb 18, 2004 6:57 pm    Post subject: Basic File Operations Reply with quote

There are lots of questions about reading lines from files, replacing lines, etc. So I'll address a few things here.

1. Reading all the lines from a file into a list.
This is one of the most basic things you can do. It's the basis for several other operations we'll be discussing, so get familiar with it!

Code:

# File name to read.
set fname "yourfile.txt"

# Open file for read access (note we're not catching errors, you might
# want to use catch {} if the file might not exist.
set fp [open $fname "r"]

# Here we read in all of the data.
set data [read -nonewline $fp]

# Close the file, since we're done reading.
close $fp

# Now we split the data into lines.
set lines [split $data "\n"]


There you go, a list of all the lines in the file, with just a few simple lines of code! On to more advanced topics.

2. Reading a random line from a (small) file.
There are lots of reasons you might want to do this: quote scripts, random topic scripts, trivia games, etc. In this example we'll only be reading a single line, but you could easily change it to read more than 1 line in a row, or multiple lines from different places.

Code:

# Use the code from above (1.) to read in all the lines from the file.
# We continue right after: set lines [split $data "\n"]

# Get the number of lines.
set numlines [llength $lines]

# Choose a random line with eggdrop's rand function.
set num [rand $numlines]

# Get the line from the list!
set randline [lindex $lines $num]


Now you have the random line in the $randline variable. If you wanted to read multiple lines, you could put the last part in a loop.

3. Deleting a line from a text file.
We'll assume you want to delete a specific line. Remember that most languages, including tcl, index things starting from 0. So if you want to delete the first line, it is line 0. The second line is line 1. Etc.

Code:

# Use the code from above (1.) to read in all the lines from the file.
# We continue right after: set lines [split $data "\n"]

# We'll delete the first line.
set line_to_delete 0

# If you wanted to delete the last line instead, you would do this:
# set line_to_delete [expr [llength $lines] - 1]

# Now, we remove the line from the list in memory first.
set lines [lreplace $lines $line_to_delete $line_to_delete]

# And finally, we re-write the file with the new data.
set fp [open $fp "w"]
puts $fp [join $lines "\n"]
close $fp


As you can see, to delete a line from a file, we have to read the file into memory, remove the line from memory, then overwrite the file on disk. If you are doing a lot of adding/removing of records, you should consider using a database instead! Also, if your file is very large (several megabytes), these operations will take some time -- you should not be using a flat text file.

4. Inserting a line into a file.
Usually people want to insert lines at the beginning of a file, or append them onto the end. The latter will be handled in the next question.

Code:

# Use the code from above (1.) to read in all the lines from the file.
# We continue right after: set lines [split $data "\n"]

# For the beginning, use line 0, since tcl starts counting at 0. If you want
# to append the line to the end, see the next question for a better way.
set line_to_insert "this is the new line"
set where_to_insert 0

# Now we insert the line into our list in memory.
set lines [linsert $lines $where_to_insert $line_to_insert]

# And now we re-write the file, just like in 3.
set fp [open $fp "w"]
puts $fp [join $lines "\n"]
close $fp


5. Add a line to the end of a file.
For the special case of adding a line to the end of the file, we don't need
to mess with reading/re-writing at all. We simply open the file in a special
mode called "append mode."

Code:

# The new line.
set line_to_add "the dragon will eat your sheep!"

# Name of file to append to.
set fname "yourfile.txt"

# Open the file in append mode.
set fp [open $fname "a"]

# Add the line.
puts $fp $line_to_add

# We're done!
close $fp




If you'd like to see some other file i/o topics answered here, make a post below!
Of course, don't bother with things like "how do I read a random line and display it in a private message" because the whole reading-random-lines topic is covered already.
Back to top
View user's profile Send private message Visit poster's website
strikelight
Owner


Joined: 07 Oct 2002
Posts: 708

PostPosted: Wed Feb 18, 2004 11:25 pm    Post subject: Re: Basic File Operations Reply with quote

stdragon wrote:

3. Deleting a line from a text file.
We'll assume you want to delete a specific line. Remember that most languages, including tcl, index things starting from 0. So if you want to delete the first line, it is line 0. The second line is line 1. Etc.

Code:

# Use the code from above (1.) to read in all the lines from the file.
# We continue right after: set lines [split $data "\n"]

# We'll delete the first line.
set line_to_delete 0

# If you wanted to delete the last line instead, you would do this:
# set line_to_delete [expr [llength $lines] - 1]

# Now, we remove the line from the list in memory first.
set lines [lreplace $lines $line_to_delete $line_to_delete]

# And finally, we re-write the file with the new data.
set fp [open $fp "w"]
puts $fp [join $lines "\n"]
close $fp


As you can see, to delete a line from a file, we have to read the file into memory, remove the line from memory, then overwrite the file on disk. If you are doing a lot of adding/removing of records, you should consider using a database instead! Also, if your file is very large (several megabytes), these operations will take some time -- you should not be using a flat text file.


Just a couple of optimization tips, especially with reference to this section:
Take advantage of TCL's expression optimization by using {}'s:
Code:

# If you wanted to delete the last line instead, you would do this:
# set line_to_delete [expr [llength $lines] - 1]

to:

# set line_to_delete [expr {[llength $lines] - 1}]


When performing an in-place lreplace (that is to say, setting a variable to the result of an lreplace operation on the same variable itself), performance can be noticably enhanced by using the following:

Code:

# Now, we remove the line from the list in memory first.
set lines [lreplace $lines $line_to_delete $line_to_delete]

Becomes:

proc K {x y} { set x }
set lines [lreplace [K $lines [set lines {}]] $line_to_delete $line_to_delete]


(Tips obtained from The Tcl'ers Wiki).
Back to top
View user's profile Send private message Visit poster's website
Gust
Voice


Joined: 28 Jun 2006
Posts: 15

PostPosted: Wed Jan 17, 2007 10:09 am    Post subject: Re: Basic File Operations Reply with quote

stdragon wrote:
3. Deleting a line from a text file.
We'll assume you want to delete a specific line. Remember that most languages, including tcl, index things starting from 0. So if you want to delete the first line, it is line 0. The second line is line 1. Etc.


First of all, thanks for this explanation.

In the piece of code you've provided, you should allready know the line-number of the line you want to remove...
But what if you don't know the line-number in the textfile?

For example: I have a file that contains the following:
Code:
hostname 1 user1
hostname5 user5
hostname8 user8
hostname3 user3
hostname12 user12
hostname6 user6


And i want to delete the following line:
Code:
hostname8 user8


by searching on "user8"; how can i do that?

Thanks in advance!

Greetings,
Gust
Back to top
View user's profile Send private message
user
 


Joined: 18 Mar 2003
Posts: 1452
Location: Norway

PostPosted: Wed Jan 17, 2007 10:37 am    Post subject: Re: Basic File Operations Reply with quote

lsearch

Code:
# delete ALL lines ending with " user8"
set match "* user8"
while {[set i [lsearch -glob $lines $match]]>-1} {
   set lines [lreplace $lines $i $i]
}

_________________
Have you ever read "The Manual"?
Back to top
View user's profile Send private message
SL0RD
Voice


Joined: 05 Oct 2008
Posts: 19

PostPosted: Tue Oct 28, 2008 5:54 pm    Post subject: Reply with quote

Thanks for the great basic tutorial.

I have two "requests"

First off, say you had this:
Code:

thing1 disc
thing2 disc
thing3 disc
thing4 disc


I would like to add a new line but if the line that i want to add starts with thing1 for example instead of adding it again at the end i want to update the existing thing1
also how could you delete a line by using lsearch but by searching the first word in each line so i would like to delete things3 for example by searching for thing3

secondly, say you had that same table, I want to be able to do a command and have it pull the first word from every line and list it in the channel ex: <bot> thing1, thing2, thing3, thing4

That is all for now but i will probably have more questions later. thanks Wink
Back to top
View user's profile Send private message
A Hylian Human
Voice


Joined: 06 Sep 2010
Posts: 5

PostPosted: Mon Sep 06, 2010 12:03 pm    Post subject: Basic File Operations - Evaluating variables read from file Reply with quote

If I have variables, such as $nick or $arg, in the file, it doesn't evaluate the variables. Instead, it just leaves it at $nick or $arg.
Is there any way to evaluate the variables?
using [eval] makes Tcl want to use the first word of the line as a command, which is not appropriate when I have, say:
putmsg $chan "[eval [readFile filename.txt]]"
(readFile is a seperate process that reads the file and returns a random line)
Back to top
View user's profile Send private message
username
Op


Joined: 06 Oct 2005
Posts: 196
Location: Russian Federation, Podolsk

PostPosted: Mon Sep 06, 2010 4:39 pm    Post subject: Re: Basic File Operations - Evaluating variables read from f Reply with quote

A Hylian Human wrote:
If I have variables, such as $nick or $arg, in the file, it doesn't evaluate the variables. Instead, it just leaves it at $nick or $arg.
Is there any way to evaluate the variables?
using [eval] makes Tcl want to use the first word of the line as a command, which is not appropriate when I have, say:
putmsg $chan "[eval [readFile filename.txt]]"
(readFile is a seperate process that reads the file and returns a random line)

You need to use subst command. Look at this example:
Code:
        set realmsgs {
         "Hi, how are you?"
         "Hi $nick!"
         "Hello $nick, welcome to $chan"
         "]]] WELCOME to $chan!!!11111 ^^ ^^ [[["
         "Hi [$nick], you have to pay 20$ to enter here"
     }
     
     bind join - * greet
     proc greet {nick host hand chan} {
         set greetmsg [lindex $::realmsgs [rand [llength $::realmsgs]]]
         set greetmsg [subst -nocommands $greetmsg]
         putserv "PRIVMSG $nick :$greetmsg"
     }

_________________
Архив TCL скриптов для ботов Eggdrop/Windrop:
http://egghelp.ru/
Back to top
View user's profile Send private message Send e-mail Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    egghelp.org community Forum Index -> Tcl FAQ All times are GMT - 4 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Forum hosting provided by Reverse.net

Powered by phpBB © 2001, 2005 phpBB Group
subGreen style by ktauber