0

How do I use (if they exist) string placeholders for writing in a text file? I want to write a text file, which keeps track of how many lines are written in itself. As soon as the amount of lines changes, the count should change accordingly.

Here is an example:

number_of_lines = 0

with open('./test.txt', "w") as out_file:
    out_file.write('number of elements in list: '+str(2)+'\n')
    out_file.write('element 1\n')
    out_file.write('element 2\n')

with open('./test.txt', "r+") as out_file:
    next(out_file)
    out_file.write('element 3\n')
    out_file.write('element 4\n') 
    out_file.write('element 5\n')
    out_file.write('element 6\n') 
    out_file.write('element 7\n')
    out_file.write('element 8\n') 
    out_file.write('element 9\n')
    out_file.write('element 10\n')    # now 2 Digits '10'
    out_file.seek(0)
    for i in out_file:
        number_of_lines += 1
    
    out_file.seek(0)
    out_file.write('number of elements in list: '+str(number_of_lines-1)+'\n')

text file:

number of elements in list: 10
lement 1
element 2
element 3
element 4
element 5
element 6
element 7
element 8
element 9
element 10
thommy bee
  • 73
  • 2
  • 9

1 Answers1

2

As a .txt file can't read itself, the tricky part in what you are trying to do is updating only a specific line in a file while keeping the rest of the data. More on that here.

So, a simple solution would be to define a function to update the relevant line, then call it after each modification we make to the file. Let's do that:

def update_line_count(filename):
    with open(filename, 'r') as original:
        # Get the original file data so we can re-insert it later
        data = original.read()
    with open(filename, 'w') as modified:
        # Remove the first line if it's already a line count
        if data.startswith('number of elements in list'):
            data = '\n'.join(data.split('\n')[1:])
        # Get the updated line count
        number_of_lines = len(data.split('\n'))-1
        updated = f'number of elements in list: {number_of_lines}\n{data}'
        modified.write(updated)

Now we can just call it after we make modifications to the file, and it will update the first line to include the correct line count.

Let's see it in action:

my_file = './test.txt'

with open(my_file, "w") as file:
    file.write('element 1\n')
    file.write('element 2\n')

update_line_count(my_file)

Now, inside test.txt, we have:

number of elements in list: 2
element 1
element 2

Let's modify and update some more:

with open(my_file, "r+") as file:
    next(file)
    file.write('element 3\n')
    file.write('element 4\n') 
    file.write('element 5\n')
    file.write('element 6\n') 
    file.write('element 7\n')
    file.write('element 8\n') 
    file.write('element 9\n')
    file.write('element 10\n')
    file.write('element 100\n')
    file.write('element 1000?\n')

update_line_count(my_file)

Look inside test.txt:

number of elements in list: 12
element 1
element 2
element 3
element 4
element 5
element 6
element 7
element 8
element 9
element 10
element 100
element 1000?

Hooray! :)

pitamer
  • 905
  • 3
  • 15
  • 27
  • 1
    Thank you so much, this is a perfect solution! Unfortunately I am not allowed to upvote. – thommy bee Oct 01 '20 at 10:28
  • Happy to help! Up-voting is absolutely not necessary, however, **choosing** the answer can be done by anyone, and it would be great for users who have a similar question in the future :) @thommybee – pitamer Oct 01 '20 at 10:35
  • that's right! Can you explain me 2 things? why do we have to reduce len(data.split('\n')) by 1 to get the number of lines? is it because of an empty line at the end ('\n)? And what does the 'f' stand for in: updated = f'number of elements in list: … @pitamer – thommy bee Oct 01 '20 at 11:54
  • `len(data.split('\n'))` counts all the lines in the file *including the first line*, which is only supposed to do the counting. If you want to include it in the count, you can drop the `-1`. As for the mysterious `f`, this is a [Literal String Interpolation](https://www.python.org/dev/peps/pep-0498/), commonly known as an *f-string*. It's an elegant way of **formatting** strings. Say we have `age = 25`, then `f'I am {age}'` is more elegant than `'I am ' + str(age)`. As for accepting an answer on Stack Overflow, this can be done by clicking the 'V' icon on an answer, just below the voting :) – pitamer Oct 01 '20 at 12:38