如何在Python中覆盖文件?
我正在尝试覆盖一个文件。我是根据这个 在Python中读取和覆盖文件 的内容来写的。
为了完成我的代码:
<select class="select compact expandable-list check-list"
ONCHANGE="location = this.options[this.selectedIndex].value;">
<option value="{% url envelopes:auto_sort %}?sort_by=custom">
Custom order
</option>
<optgroup label="Category">
<option value="{% url envelopes:auto_sort %}?sort_by=cat_asc">
Ascending order
</option>
<option value="{% url envelopes:auto_sort %}?sort_by=cat_desc">
Descending order
</option>
</optgroup>
</select>
def auto_sort(request):
sort_by = request.GET.get('sort_by', None)
if sort_by:
temp_path = "{0}/file.txt".format(settings.SITE_ROOT)
f=open(temp_path,'r+')
text = f.read()
text = re.sub('cat_asc', 'cat_desc', text)
f.seek(0)
f.write(text)
f.truncate()
f.close();
handle=open(temp_path,'w+')
handle.write(sort_by)
handle.close();
return HttpResponseRedirect(reverse('envelopes:editor'))
我目前代码的输出结果:
文件里原本有 cat_desc
,当我再次尝试写入 custom
时,结果变成了 customc
。注意最后的 c
,它应该只显示 custom
。
这是我想要实现的目标:
- 我在文件中写入,比如
cat_desc
- 如果我想再写一次,比如
custom
,那么cat_desc
必须被删除,并替换成custom
。
5 个回答
新的回答...
你把 text
当作 re.sub
的第四个参数传入了。这个地方应该是一个 int
类型的数字。
Help on function sub in module re:
sub(pattern, repl, string, count=0, flags=0)
Return the string obtained by replacing the leftmost
non-overlapping occurrences of the pattern in string by the
replacement repl. repl can be either a string or a callable;
if a string, backslash escapes in it are processed. If it is
a callable, it's passed the match object and must return
a replacement string to be used.
旧的回答...
也许你在做的事情是
from os import open
那是一个不同(更底层)的打开方式,你只需要使用内置的 open 函数(使用它不需要导入任何东西)
这里有一个错误的例子,能让你看到错误信息
>>> from os import open
>>> open("some_path", "r+")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: an integer is required
另外,如果你想覆盖文件,需要用 "w+" 来打开。 "r" 是用来读取的。
关于你的新问题:
想要直接在文件里覆盖内容几乎是不可能的,除非你用新的字节串替换掉长度完全相同的旧字节串。比如说,如果你把 'cat_desc'
替换成 'cat_asc'
,最后的结果可能会变成 'cat_ascc'
。
你现在做的事情是:用 'r+'
模式打开文件,读取整个内容,处理后再用 seek
回到开头,最后写回去,这个方法是可行的。但这并不是最好的做法。
而且,无论如何,你的问题在于,刚做完这些后,你又用 'w+'
模式打开了同一个文件路径(这会清空文件),然后写入了不同的内容。所以,你刚写的内容就没了。
解决这个问题的方法就是……别这么做。我不太清楚你想要实现什么,但这可能不是你想要的结果。
同时,重写文件的最佳方法是“原子性写入临时文件并重命名”的方式。这种方法可以确保你不会损坏文件,你要么得到新文件,要么保留旧文件。这样也意味着你不需要把整个文件都放在内存中,可以逐步处理。而且这个方法非常简单……如果你不在乎Windows的话。它的工作方式是这样的:
with tempfile.NamedTemporaryFile(delete=False) as outfile:
with open(inpath) as infile:
# copy from infile to outfile, changing things as you go
os.rename(outfile.name, inpath)
不幸的是,在Windows上实现这个方法非常麻烦。你不能在 outfile
还打开的时候移动它,也不能在 with
语句外访问它,此外,你还不能直接用 outfile
替换 infile
;你必须进行复杂的操作。而且,除非你愿意使用Vista/2008并直接调用Win32 API,否则这个过程永远不会完全原子性。
根据你修改后的问题,或许下面这样的写法会更简单一些。
def auto_sort(request):
sort_by = request.GET.get('sort_by', None)
if sort_by:
temp_path = "{0}/file.txt".format(settings.SITE_ROOT)
#Set new_text to whatever you want based on your logic
new_text = 'custom'
f=open(temp_path,'w')
f.write(new_text)
f.close();
handle=open(temp_path,'w+')
handle.write(sort_by)
handle.close();
return HttpResponseRedirect(reverse('envelopes:editor'))