write() at beginning of file?

2019-01-17 21:40发布

问题:

I'm doing it like this now, but I want it to write at the beginning of the file instead.

f = open('out.txt', 'a') # or 'w'?
f.write("string 1")
f.write("string 2")
f.write("string 3")
f.close()

so that the contents of out.txt will be:

string 3
string 2
string 1

and not (like this code does):

string 1
string 2
string 3

回答1:

Take a look at this question. There are some solutions there.

Though I would probably go that same way Daniel and MAK suggest -- maybe make a lil' class to make things a little more flexible and explicit:

class Prepender:

    def __init__(self, fname, mode='w'):
        self.__write_queue = []
        self.__f = open(fname, mode)

    def write(self, s):
        self.__write_queue.insert(0, s)

    def close(self):
        self.__exit__(None, None, None)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        if self.__write_queue: 
            self.__f.writelines(self.__write_queue)
        self.__f.close()

with Prepender('test_d.out') as f:
    f.write('string 1\n')
    f.write('string 2\n')
    f.write('string 3\n')


回答2:

You could throw a f.seek(0) between each write (or write a wrapper function that does it for you), but there's no simple built in way of doing this.

EDIT: this doesn't work, even if you put a f.flush() in there it will continually overwrite. You may just have to queue up the writes and reverse the order yourself.

So instead of

f.write("string 1")
f.write("string 2")
f.write("string 3")

Maybe do something like:

writeList = []
writeList.append("string 1\n")
writeList.append("string 2\n")
writeList.append("string 3\n")
writeList.reverse()
f.writelines(writeList)


回答3:

Elaborating on Daniel DiPaolo's answer:

Simply append all the lines that you want to write to a list. Reverse the list and then write its contents into the file.

f=open('output.txt','w')

l=[]
l.append("string 1")
l.append("string 2")
l.append("string 3")

for line in l:
    f.write(line)

f.close()

You could also use a deque and add lines at its beginning instead of using a list and reversing it.



回答4:

A variation on kdtrv's answer. This version keeps the existing file contents, and offers a write_lines method that preserves line order.

class Prepender(object):
    def __init__(self,
                 file_path,
                ):
        # Read in the existing file, so we can write it back later
        with open(file_path, mode='r') as f:
            self.__write_queue = f.readlines()

        self.__open_file = open(file_path, mode='w')

    def write_line(self, line):
        self.__write_queue.insert(0,
                                  "%s\n" % line,
                                 )

    def write_lines(self, lines):
        lines.reverse()
        for line in lines:
            self.write_line(line)

    def close(self):
        self.__exit__(None, None, None)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        if self.__write_queue:
            self.__open_file.writelines(self.__write_queue)
        self.__open_file.close()


with Prepender('test_d.out') as f:
    # Must write individual lines in reverse order
    f.write_line('This will be line 3')
    f.write_line('This will be line 2')
    f.write_line('This will be line 1')

with Prepender('test_d.out') as f:
    # Or, use write_lines instead - that maintains order.
    f.write_lines(
        ['This will be line 1',
         'This will be line 2',
         'This will be line 3',
        ]
    )