鱼C论坛

 找回密码
 立即注册
查看: 1326|回复: 4

[已解决]win10下python中文写入的bug

[复制链接]
发表于 2021-11-19 22:43:33 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
操作系统: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
最佳答案
2021-11-20 02:04:16
本帖最后由 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个字节,你会发现无论怎么样运行都会报错。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2021-11-19 23:26:07 | 显示全部楼层
你的最终目标是什么?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-20 02:04:16 | 显示全部楼层    本楼为最佳答案   
本帖最后由 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个字节,你会发现无论怎么样运行都会报错。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2021-11-20 02:17:14 | 显示全部楼层
txxcat 发表于 2021-11-20 02:04
你碰到的问题挺有意思,其实涉及到了几个方面的问题,一个是r+到底是什么工作方式,一个是Python文件写 ...

学到了,第一次看到关于这个问题的详细解释,由于常用的是r,w,rb,wb,a,带+的模式,一直都觉得会出各种莫名其妙的问题。看完感觉应该大概知道什么情况了。
另外建议初学的朋友,还是不要读写用同一个file对象来操作吧,真的容易出问题,调试起来也很烦~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2021-11-20 08:41:15 | 显示全部楼层
txxcat 发表于 2021-11-20 02:04
你碰到的问题挺有意思,其实涉及到了几个方面的问题,一个是r+到底是什么工作方式,一个是Python文件写 ...

说的真清楚,感谢大牛的解答!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-12 18:48

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表