I need to copy the content of a file to another one except the first two and the last two lines of that file.
For that purpose I wrote this function
def copy_file(self, input_file, output_file):
line_nr = 1
fout = open(output_file, "w ")
with open(input_file, 'r') as fp:
for line in fp:
if line_nr == 1 or line_nr == 2 or line_nr == 53 and line_nr == 54 :
continue
new_line = line.split(' ', 1)[-1]
fout.write(new_line)
fp.close()
I was able to achieve what I desired by hardcoding the line numbers that I wanted to ignore but I would like to make this function more generic.
How can I do it?
CodePudding user response:
What you are doing is going through the file manually, line by line, which as you can see can be impractical and tedious. A good alternative is to use list splicing and the function f.read.splitlines(True)
Try this:
def copy_file(input_file, output_file):
line_nr = 1
fout = open(output_file, "w ")
with open(input_file, 'r') as fp:
text = fp.read().splitlines(True)[2:-2]
fout.writelines(text)
fp.close()
The beginning of the code is the same as yours. However, instead of looping through the file, line by line, I use the code fp.read().splitlines(True)
. This returns the entire file in a list, where each element is a line. From their, I can use list splicing [2:-2]
to get rid of the first 2 and last 2 elements of the list. Finally, I can then write these to the new file with fout.writelines(text)
, which turns a list into text to write into a file.
CodePudding user response:
Here is how to do this efficiently, keeping at most "skip_last" elements in memory. This uses itertools.islice
to slice the file iterator, and a collections.deque
to efficiently keep a buffer of lines:
import itertools
import collections
def copy_file(
input_file: str,
output_file: str,
skip_first: int,
skip_last: int
) -> None:
with open(input_file) as fin, open(output_file, 'w') as fout:
skipped_beginning = itertools.islice(fin, skip_first, None)
buffer = collections.deque(maxlen=skip_last)
buffer.extend(itertools.islice(skipped_beginning, skip_last))
for line in skipped_beginning:
fout.write(buffer.popleft())
buffer.append(line)
CodePudding user response:
You can make the function more generic by skipping the desired number of lines at the beginning and end of the file. One approach is shown below:
def copy_file(input_file, output_file, skip_first, skip_last):
with open(output_file, "w ") as fout:
with open(input_file, 'r') as fp:
lines = list(fp)
for line in lines[skip_first:len(lines)-skip_last]:
fout.write(line)
This function takes in an additional parameter skip_first
and skip_last
that specify the number of lines to skip at the beginning and end of the file respectively.
You can call this function passing the input and output file paths, and the number of lines to skip at the beginning and end of the file.
copy_file("input_file.txt", "output_file.txt", 2, 2)
This approach will make sure your function will be flexible enough and allow to skip any number of lines you want to skip.