5

I have two text files test1.txt and test2.txt. I want to be able to read test1.txt contents and write it to text2.txt at a specific line.

I have been able to read the contents of test1.txt and write them to a blank test2.txt.

Now I want to change my code to read context of test1.txt and write them to a non empty text2.txt.

with open("/test1.txt") as f:
    lines = f.readlines()

with open("/test2.txt", "w") as f1:
    f1.writelines(lines)

How can I insert the contents of test1.txt to test2.txt at line 20.

Remi Guan
  • 21,506
  • 17
  • 64
  • 87
kartoza-geek
  • 341
  • 1
  • 6
  • 20
  • Possible duplicate of [Python concatenate text files](http://stackoverflow.com/questions/13613336/python-concatenate-text-files) – Torxed Feb 24 '16 at 07:32
  • It's been asked so many times that this is one of the most common questions on the Internet and I hate to sound like a douche, but have you Google "merge two files python"? – Torxed Feb 24 '16 at 07:33
  • @Torxed: ​​​​​​​​​​​​​​​Well, OP said that: *How can I insert the contents of `test1.txt` to `test2.txt` at line 20.* – Remi Guan Feb 24 '16 at 07:47
  • @KevinGuan Yea and Google (on my phone so effort is minimal to find the perfect code): http://stackoverflow.com/q/1325905/929999 – Torxed Feb 24 '16 at 07:50
  • @Torxed: ​​​​​​​​​​​​​​​Nah, it's also a different question. The question you linked is trying to *Now I want to insert `'foo bar'` between `'foo1 bar3'` and `'foo2 bar4'`.* – Remi Guan Feb 24 '16 at 07:55

5 Answers5

3

Simple but somewhat memory-intensive:

# insert contents of "/test1.txt" into "/test2.txt" at line 20
with open("/test1.txt", "r") as f1:
    t1 = f1.readlines()
with open("/test2.txt", "r") as f2:
    t2 = f2.readlines()
t2.insert(20, t1)
with open("/test2.txt", "w") as f2:
    f2.writelines(t2)

Minimizes memory usage and disk writes, but is a little more complex :

# insert contents of "/test1.txt" into "/test2.txt" at line 20
with open("/test2.txt", "rw+") as f2:
    for x in range(20):
        f2.readline()   # skip past early lines
    pos = f2.tell() # remember insertion position
    f2_remainder = f2.read()    # cache the rest of f2
    f2.seek(pos)
    with open("/test1.txt", "r") as f1:
        f2.write(f1.read())
    f2.write(f2_remainder)

I haven't tested either of these, but they should get you most of the way there.

Matthias Fripp
  • 17,670
  • 5
  • 28
  • 45
  • the second one solution works but f2.read() should be f2.readline() – kartoza-geek Feb 24 '16 at 13:34
  • @MatthiasFripp, this is giving an error. f2.write(f1.read()) IOError: [Errno 9] Bad file descriptor – Hamad Hassan Apr 21 '18 at 19:45
  • @HamadHassan It sounds like you may be running that statement after the `with open(...) as f2:` block is finished. Are you sure `f2` is an open file descriptor at your point in the code? – Matthias Fripp Apr 21 '18 at 20:21
  • Solution 1 does not work if the insert structure is also a list. Therefore, instead of `insert()`, use slicing as explained in https://stackoverflow.com/a/3748092/11082684 - for inserting after line `20` use: `t2[20:20] = t1`; use solution from https://stackoverflow.com/q/7138686/11082684 to also insert with newlines with `with open("/test2.txt", "w") as f2:f2.write("\n".join(t2))` – pavol.kutaj Aug 26 '21 at 09:32
  • Actually the second solution is wrong too, you want `r+` mode, but apart from that, it's writing things in the wrong order. – tripleee Aug 26 '21 at 11:15
2

Actually both the solutions in the accepted answer are broken (!)

Here is a fixed version of the seek and tell version:

with open("test2.txt", "r+") as f2:
    for x in range(20):
        f2.readline()
    pos = f2.tell()
    f2_remainder = f2.read()
    f2.seek(pos)
    with open("test1.txt", "r") as f1:
        for line in f1:
            f2.write(line)
    f2.write(f2_remainder)

It will still be rather memory-intensive if the input file is large and you need to keep it in memory, though on modern computers, this should be doable even with gigabyte-size files.

Demo: https://ideone.com/UrOVmx (includes demonstrations of how the accepted answers are wrong, and a deployment of pavol.kutaj's answer.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
0

There may be several solutions for this problem. One possible solution is.

  1. Open file1 and read content to a list
  2. Open file2 and read content to another list
  3. Add content of file1 in file2 at desired place.
  4. Write back content in second list in file2.
niyasc
  • 4,440
  • 1
  • 23
  • 50
0

try this, if you want to write one file's data at a specific line then try this

fp = open("data.txt","r")
# fp is file1
data = fp.read()
f = open('workfile.txt', 'rw+')
#f is file2 on which you want to write data
ss = f.readlines()
f.seek(0)
f.truncate()
ss.insert(5,data)
#give your own line number instead of 5
f.write(''.join(ss))
sameera sy
  • 1,708
  • 13
  • 19
0

If you need to insert after a line containing the first occurrence of a particular substring and you don't know (don't want to rely on) the exact line number:

  • Put your data in source.txt (to be enriched) and insert.txt (to be enriched with).
import json


def main():
    with open("source.txt", mode="rt", encoding="utf-8") as f1:
        source_list = [line for line in f1.readlines()]

    with open("insert.txt", mode="rt", encoding="utf-8") as f2:
        insert_list = [line for line in f2.readlines()]

    pos = [i for i, line in enumerate(source_list) if '<substring>' in line][0]
    source_list[pos: pos] = insert_list

    with open("source.txt", mode="wt", encoding="utf-8") as f1:
        f1.write("".join(source_list))


if __name__ == "__main__":
    main()
pavol.kutaj
  • 401
  • 1
  • 7
  • 14
  • Thanks for clarifying. The `tell` + `seek` solution is probably preferable anyway, but working code is always good. – tripleee Aug 26 '21 at 10:24
  • The `.index()` can only work if the contents of the lines are reasonably unique up until the line you want to find. It should not be hard to divide the reading into two phases so you can keep track of the index of the substring before the insertion point without scanning the string again. – tripleee Aug 26 '21 at 11:37