Why does readlines display an empty list even with the file having data?

Asked

Viewed 96 times

2

f = open("grades.txt", "r")
for record in f.readlines():

    print(f"grade : {record} ")

print(f"readlines: {f.readlines()}")
f.close()

The.txt grid file exists and has the following content:

10
9.8
.6
5.3
0

Why on attaining education:

print(f"readlines: {f.readlines()}

The program displays an empty list? It would have to show :

[10,9.8,.6,5.3,0]

What is wrong?

2 answers

5


This is because readlines reads the entire contents of the file, and when you call it again, there is nothing left to read.

If you want to save lines to use later, just use readlines only once and save the result in a list, and use this list in the following times:

with open("grades.txt", "r") as f:
    linhas = f.readlines()

for record in linhas:
    print(f"grade : {record} ")

print(f"readlines: {linhas}")

Note the use of with, which already ensures that the file will be closed at the end even if any error occurs while reading (so you need not call close).


Note also that this does not have nothingness to do with "the file be occupied by the program", as he claimed another answer (which has been deleted). What happens is that there is an "inner pointer" that indicates the position you are in the file, and every time you read something from it, that pointer moves forward positions. And how readlines reads all the content, after calling it this "pointer" will be at the end of the file (so any call made after does not find anything else).

But you can go back to the beginning of the file (using seek) and read again (although it is not very useful in this case):

with open("grades.txt", "r") as f:
    for record in f.readlines() # ler o arquivo uma vez
        # ... faz o que quiser com record

    f.seek(0) # voltar ao início
    print(f.readlines()) # ler de novo

As I said, in this case it doesn’t make any sense to read the file again. Use the first solution, which only reads once and that’s it.


Just one detail: readlines keeps the file line breaks, so when printing with print(f"grade : {record} "), you will end up skipping 2 lines: one referring to the existing line break in the file, and another that the print automatically adds. That is, the first code will print:

grade: linha 1

grade: linha 2

etc...

If you want to remove these "extra" line breaks, you can change the parameter in the print, or remove it from the line itself:

for record in linhas:
    print(f"grade : {record} ", end="")

# ou
for record in linhas:
    record = record.rstrip('\n')
    print(f"grade : {record} ")

Remember that in the first case, the last line will not have the line break after (if the last non-empty line of the file does not have a line break). In the second case, all lines will have an added line break.

Another alternative is to already create the list without these line breaks:

with open("grades.txt", "r") as f:
    # remove a quebra de linha de todas as linhas
    linhas = [ linha.rstrip('\n') for linha in f.readlines() ]

for record in linhas:
    print(f"grade : {record} ")

It is also worth remembering that readlines always loads the entire contents of the file into memory at once, which can be a problem for very large files. If you really need to have a list of all the lines, there’s not much to do. But if you just want to read the lines (and do something with them) and don’t need to keep them, then you better read line by line:

with open("grades.txt", "r") as f:
    for linha in f: # assim você lê uma linha de cada vez
        # faz o que precisar com a linha

2

The methods of reading read(), readline() and readlines() perform the reading of the text only once, or better, perform the reading of where they have stopped.

file.read(3) # Lê até o 3º caractere do arquivo            (Texto: "Hel")
file.read() # Continua a partir do 4º caractere do arquivo (Texto: "lo World")

Soon if you perform the complete reading of the file, when calling one of these three methods next time, it will return a string or empty list, as there will be nothing else to read.

What you should do is use the method seek() that goes back to a file point. That way, you can perform the reading once again. Example:

file.read() # Lê todo arquivo                                      (Texto: "Hello World")
file.read() # Devolve string vazia pois ele já leu todo o arquivo  (Texto: "")

file.seek(3) # Volta para o 4º caractere
file.read() # Lê todo o texto a partir do 4º caractere             (Texto: "lo World")

Knowing now all this, just add the method in your code, passing the value zero as parameter for it to read from the beginning. See how it would look:

f = open("grades.txt", "r")

for record in f.readlines():
    print(f"grade : {record} ")

f.seek(0)

print(f"readlines: {f.readlines()}")
f.close()

Still, I don’t think this is a good way to work with files, because when using the methods seek and read, you would be performing the reading again of your file unnecessarily.

Imagine you have a file containing megabytes of text. You would even like to perform the reading again of your file, having read it once ?

The ideal solution for your specific case (sometimes the file can be too large, and maybe you prefer to exchange memory for processing or vice versa) would create a variable to save the text you read. Example:

f = open("grades.txt", "r")

lines = f.readlines()

for record in lines:
    print(f"grade : {record} ")

print(f"readlines: {lines}")
f.close()

Browser other questions tagged

You are not signed in. Login or sign up in order to post.