我的python写入文件正常,打开后却是乱码格式为什么?,python写入,windows7 +2.


windows7 +2.7.5
我的源代码:

#!/usr/bin/env python# -*- coding: utf-8 -*-file = open(r"D:\Android\python\test.txt","w+")file.write('hello')file.read()

python test1.py后,用记事本打开文件显示乱码,请问这是怎么回事啊?

Windows下的编码是个大坑,别用记事本了,换nodepad++吧。

请特别阅读 @依云 的答案。分析上游代码和文档,这才是真正坚不可摧的力量。


同仁们,误入歧途了啊!!!别在ASCII的文件上这么深入的追究编码问题啊!!!

我试了一下,果然爽翻:

#!/usr/bin/env python# -*- coding: utf-8 -*-f = open(r"C:\Users\776\test.txt","w+") # 注:w+ truncates the file - 因此文件无论存在与否,结果一致f.write('hello')print(f.read())f.close()# 结果不贴了,同样不忍直视,传送门:http://paste.openstack.org/show/61806/

我没有深入的究其原因,不过大概能猜到理由是什么:文件的指针位置

open()以w+模式开启了一个读写模式的文件,由于是w,所以文件被废弃清空(truncate),此时的文件内容为[EOF],开启时的指针为0。此时如果做read(),则Python发现指针位置就是EOF,读取到空字符串。

在写入hello之后,指针的位置是5,文件在内存中是hello[EOF]。

但看起来read()的时候,Python仍然去试图在磁盘的文件上,将指针从文件头向后跳5,再去读取到EOF为止。

也就是说,你实际上是跳过了该文件真正的EOF,为硬盘底层的数据做了一个dump,一直dump到了一个从前文件的[EOF]为止。所以最后得到了一些根本不期待的随机乱字符(这里根本不是编码问题造成的乱码!)。

(看起来似乎还暴露了一些以前文件的内容呢,C:\Anaconda\神马的 :D)

解决这个问题,你需要在读文件之前,用file对象的flush()方法,将已修改的文件内容可靠写盘:

#!/usr/bin/env python# -*- coding: utf-8 -*-f = open(r"C:\Users\776\test.txt","w+") # 注:w+ truncates the file - 因此文件无论存在与否,结果一致f.write('hello') # 此时指针=5,内存内容=`hello[EOF]`f.flush() # 此时硬盘内容=`hello[EOF]`print(f.read()) # 此时指针=5,正好在[EOF]上,正确输出''f.seek(0) # 指针归0print(f.read()) # 正确从头读出全部内容'hello'f.close()

这并不是完美的解决方法,因为我总觉得flush()应该是真正决定写盘之前才做的,而不是read()一次就flush()一次。read()似乎还是优先读取内存缓冲区更有道理。

但总之至少猜测到了一个原因,并一定程度解决问题,更好的方法有待补充吧?

乱码应该是报错信息,读文件之前先打开,最后还最好要 close

试试下面这个

#!/usr/bin/env python# -*- coding: utf-8 -*-file = open(r"D:\Android\python\test.txt","w+")file.write('hello')file = open("D:\Android\python\test.txt")file.read()

file文件的读写,一定要注意,在写完之后,必须要seek(0),把文件指针重新指向文件开头,然后再读,否则就会从缓冲区读取一大堆乱码——顺便,这是不是一个潜在的缓冲区溢出漏洞啊。

更新:

我在路上就在想,这么底层的一个特性,为什么 Python 没有为程序员处理掉呢?都用 Python 了,谁会为了那么大的便利牺牲一丁点性能呢?一回来我就做了测试。

经测试,Python 2.7.5 on Windows XP 重现此情况,Python 3.3.2 on Windows XP 没有重现。这说明 Python 2 确实该换了!

再次更新:

找到原因之后我就觉得这问题在哪里见过,今天终于找出来了, python-cn 邮件列表里讨论过的。


真正的答案来啦~~我在 MSDN 里找得好苦哦 QAQ

真正的原因不在于 Python 怎么样了,而在于 Windows 怎么样了。经查源码(Python 2.7.6)Objects/fileobject.c:2837,Python 是使用 fopen/fread/fwrite 这系列函数来读写文件的。MSDN 说:

所以会有 @沙渺 发现添加 flush() 调用后正确的结果。

Linux 下没有重现。man 3 fopen 说:

所以 Windows 的这种行为是符合 ANSI C 标准的,但是 Linux 并不(总是)需要这样做。(并且,跨平台的方案是使用文件定位函数而不是 fflush()。)

编橙之家文章,

评论关闭