1

myfile.txt contains "to be or not to be that is the question"

I am trying to write my program to output x characters at a time on a newline such that an input of x=8 would be:

to be or
 not to
be that
is the q
uestion

I am not sure how to get my code to continue to print the next 8 characters on a newline each time

def read_file():
    x = int(input("How many letters do you want to read each time : ")) # number of characters to read on each newline
    f = open('myfile.txt')
    contents = f.read(x)
    print(contents) # only prints first 8 characters

read_file()
elmo
  • 19
  • 3
  • You're only calling `read` once, so of course you're only getting the first eight characters. You're going to need to call `read` multiple times until you're done. Have you considered a loop of some sort? – larsks Apr 23 '20 at 17:31

6 Answers6

1

Note that this line of code can leave the file open for reading. Try using a with statement.

f = open('myfile.txt')

Reference: What is the python “with” statement designed for?

The other answers are not wrong. I wanted to add a solution with the recently introduced assignment expression "walrus operator" in Python 3.8.

Reference: Assignment Expressions: The Walrus Operator

def read_file():
    chunk_size = int(input("How many letters do you want to read each time?: "))
    with open('myfile.txt') as fh:
        while (contents := fh.read(chunk_size)):
            print(contents)
read_file()

Output:

to be or
 not to 
be that 
is the q
uestion
dmmfll
  • 2,666
  • 2
  • 35
  • 41
0

You need a loop around the reading/printing part:

def read_file():
    x = int(input("How many letters do you want to read each time : ")) # number of characters to read on each newline
    f = open('myfile.txt')
    while True:
        contents = f.read(x)
        if not contents: 
            break
        print(contents) 
Błotosmętek
  • 12,717
  • 19
  • 29
0

you need to read it via loop:

contents = []
while True:
  chunk = f.read(x)
  if not chunk:
    break
  contents.append(chunk)

print(contents)
Alexander
  • 171
  • 7
0

You can use "slicing" for get the part of string. Check here for comprehensive introduction. And the solution i find:

    def read_file():
        x = int(input("How many letters do you want to read each time : "))
        f = open('myfile.txt')
        contents = f.read()

        temp = x
        temp_string = contents

        while(len(contents) >= temp):
            print(temp_string[:x])
            temp_string = contents[x:]
            contents = temp_string
        print(temp_string[:x])# this need for last part

read_file()
Serkan
  • 45
  • 7
0
# -*- coding: utf-8 -*-
def read_n_datas(x_characters,
                 file_path, 
                 my_mode='r', 
                 my_encoding=None):
    with open(file_path, mode=my_mode, encoding=my_encoding) as f:
        assert isinstance(x_characters, int) and x_characters
        r = f.read(x_characters)
        while r:
            y = yield r
            r = f.read(y or x_characters)

Example #1

x = int(input("How many letters do you want to read each time : ")) # number of characters to read on each newline
e = read_n_datas(x, 'myfile.txt')#read 'x' on first call or as default
next(e)#init the generator
print(e.send(3))#read 3 more characters 
print(e.send(10))#read 10 more characters 
print(e.send(5))#read 5 more characters

Example #2

x = int(input("How many letters do you want to read each time : ")) # number of characters to read on each newline
e = read_n_datas(x, 'myfile.txt')#read 'x' on first call or as default
for t in e:
    print(t)
0

Just for funsies, the pre-walrus solution:

from functools import partial

def iter_chunks(fileobj, chunk_size):
    sentinel = b'' if 'b' in fileobj.mode else ''  # Use empty bytes as sentinel for binary mode,
                                                   # empty str otherwise

    # Two-arg iter calls the function over and over until it returns the sentinel,
    # No arguments are passed, so we use functools.partial to make a no argument function
    # that always calls read with the same number
    return iter(partial(fileobj.read, chunk_size), sentinel)

Of course, as noted above, once the walrus is available, it's somewhat easier to read and requires no imports or checking for text vs. binary mode:

def iter_chunks(fileobj, chunk_size):
    while chunk := fileobj.read(chunk_size):
        yield chunk
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271