Last active
December 23, 2017 16:18
-
-
Save rqelibari/d2ab0edc56e25e5b1d86a782b26403d4 to your computer and use it in GitHub Desktop.
Python >2.7 function to replace a string in a file using mmap.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from __future__ import (unicode_literals, | |
with_statement) | |
import mmap | |
import os.path | |
def replace_placeholder_in_file(filepath, placeholder, text): | |
"""Replace `placeholder` in file `filename` with `text` if found. | |
Do nothing, if the file given by `filepath` does not exist. Replaces are | |
done in-place. If `text` is longer than `placeholder` the file is expanded. | |
If `text` is shorter the file is truncated by the amount of excessive bytes. | |
Otherwise there is just a replacement. | |
Examples: | |
>>> replace_placeholder_in_file("somefile.txt", "Hallo", "Hello") | |
Args: | |
string filepath - The path to the file, where the placeholder shall be | |
replaced. | |
string placeholder - The placeholder string, for which to look inside | |
the file given by `filepath`. This string will get | |
replaced by `text` if found inside the file. | |
string text - The replacement text. | |
""" | |
if not os.path.isfile(filepath): | |
return | |
placeholder_size = len(placeholder.encode("utf-8")) | |
text_size = len(text.encode("utf-8")) | |
new_bytes = text_size - placeholder_size | |
filesize_before_modification = os.path.getsize(filepath) | |
if new_bytes > 0: | |
# Pad file to right size | |
with open(filepath, 'a') as f: | |
f.write(new_bytes * b'\0') | |
with open(filepath, "r+b") as f: | |
mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_WRITE) | |
begin = mm.find(placeholder.encode("utf-8")) | |
if begin == -1: | |
# Nothing to replace here. | |
return | |
# mm.resize(filesize + NEW_BYTES) does not work on macOS | |
end_of_placeholder = begin + placeholder_size | |
following_bytes_length = filesize_before_modification -\ | |
end_of_placeholder | |
mm.move(end_of_placeholder + new_bytes, | |
end_of_placeholder, | |
following_bytes_length) | |
mm.seek(begin) | |
mm.write(text.encode("utf-8")) | |
mm.flush() | |
mm.close() | |
if new_bytes < 0: | |
f.seek(new_bytes, os.SEEK_END) | |
f.truncate() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment