win10下python中文写入的bug
操作系统:win10专业版python环境:anaconda python3.8
现有代码如下:
str1 = "数据科学与大数据技术"
with open('j:\\b.txt', mode='r+', encoding='utf-8') as f:
print(f.closed)
print(f.tell())
size = f.write(str1)
# print(f.tell())
print(f.readlines())
print(f.closed)
在j盘根目录下首先新建一个b.txt文件,通过记事本下方的状态栏显示为utf-8编码,接下来在b.txt文件里输入两行数据:
123456789
python编程论坛
按照刚才的代码在pycharm下运行没有出错,但是pycharm显示出来的结果是:
False
0
['123456789\n', 'python编程论坛']
True
这时如果打开b.txt文件查看内容变成:
123456789
python编程论坛数据科学与大数据技术
如果再次运行上述程序,则pycharm显示出来的结果是:
False
0
['123456789\n', 'python编程论坛数据科学与大数据技术']
True
这时如果再次打开b.txt文件查看内容变成:
123456789
python编程论坛数据科学与大数据技术数据科学与大数据技术
问题1:
按照python中open的解释,'r+'模式下执行write应该会清除原本内容,写入‘数据科学与大数据技术’,为什么实际打开变成了附加模式?
问题2:
如果我把注释掉的那行取消注释,pycharm执行此时会出错:
False
0
30
Traceback (most recent call last):
File "J:/PycharmProjects/pythonProject/test.py", line 7, in <module>
print(f.readlines())
File "D:\anaconda3\lib\codecs.py", line 322, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x95 in position 0: invalid start byte 你的最终目标是什么? 本帖最后由 txxcat 于 2021-11-20 02:10 编辑
你碰到的问题挺有意思,其实涉及到了几个方面的问题,一个是r+到底是什么工作方式,一个是Python文件写入方式,再一个就是utf-8编码的问题,这三个问题都弄清楚了才能解答你的问题。
问题1:
Python的标准说法:默认模式为 'r' (打开文件用于读取文本,与 'rt' 同义)。'w+' 和 'w+b' 模式将打开文件并清空内容。而 'r+' 和 'r+b' 模式将打开文件但不清空内容。
说得不太明确,其实r+模式下,是从当前指针位置来写入内容的,如果一打开就写入,指针默认在文件头,这时写入的内容会覆盖掉同等字节的内容,之后的内容保持不变,如果指针是在最后,那么就是写入新内容了,比如,如果你在打开文件之后执行seek(0,2)把指针移到文件尾再写入内容,就成了附加模式。
当然你没有seek(0,2),为什么会变成附加模式了?这就涉及到Python文件的写入方式了,使用write后Python不会直接将内容写入到磁盘,而是会等到文件关闭的时候或者执行了其他的文件操作后,在注释掉tell()语句后下一句你执行了readlines(),这个是从当前指针遍历到文件尾,执行完之后指针放在文件尾,所以这个时候在执行write就在文件尾加入新内容了。
问题2:
为什么报错,你可以看到报的是编码错,这个时候你打开一下b.txt,会发现是乱码,看看文件编码,变成ansi了,为什么会这样?是因为b.txt的文件内容不能被识别为uft-8编码了。
出了什么问题,这还要从问题1的r+模式说起来,如果是在文件尾加入新内容,一点问题都没有,就像你第一次运行时看到的一样,但是,你恢复那句tellI()之后情况发生了变化,新的内容会覆盖掉老的内容,注意,只覆盖相应的字节,其他的并不会改变,而utf-8下,汉字占3个字节,数字和字母占一个字节,你的原始文件是9个数字,6个字母,4个汉字,加上换行2个字节,一共是9+6+4*3+2=29个字节,新内容是10个汉字就是30个字节。你如果保持b.txt为29个字节的时候运行其实是不会报错的,因为30个字节的新文件彻底覆盖掉了老文件,新文件的内容就是“数据科学与大数据技术”。但是你在执行第一次之后,b.txt附加这句话变成了59个字节,这个时候,你取消注释之后在运行程序。从文件头开始写入30个字节,覆盖掉老文件的29个字节后还改写了后面的“数”字3个字节中的第一个字节(错误信息里面提到的 0x95其实是'数'字的utf-8编码b'\xe6\x95\xb0'的第二个字节),这样就破坏了uft-8编码,文件就成了一堆乱码了。
PS:你可以在“坛”字后面加个空格或者数字、字母,把文件变成60个字节,再运行就会发现不会报错了,或者反过来,把str1删掉一个字,变成9汉字27字节,小于原始文件的29个字节,你会发现无论怎么样运行都会报错。 txxcat 发表于 2021-11-20 02:04
你碰到的问题挺有意思,其实涉及到了几个方面的问题,一个是r+到底是什么工作方式,一个是Python文件写 ...
学到了,第一次看到关于这个问题的详细解释,由于常用的是r,w,rb,wb,a,带+的模式,一直都觉得会出各种莫名其妙的问题。看完感觉应该大概知道什么情况了。
另外建议初学的朋友,还是不要读写用同一个file对象来操作吧,真的容易出问题,调试起来也很烦~~ txxcat 发表于 2021-11-20 02:04
你碰到的问题挺有意思,其实涉及到了几个方面的问题,一个是r+到底是什么工作方式,一个是Python文件写 ...
说的真清楚,感谢大牛的解答!{:5_95:}
页:
[1]