问题的起因

菜鸟教程上有一段关于file.seek()方法的讲解,先简短描述一下seek()方法:

  • seek(offset, whence)方法用于移动文件读取指针到指定位置
  • 参数offset--开始的偏移量,也就是代表偏移的字节数
  • 参数whence--可选,默认为0。0表示从文件开头算起,1表示从当前位置算起,2表示从文件末尾算起
  • 返回值:该方法没有返回值

实例

文件runoob.txt的内容如下:

1:www.runoob.com
2:www.runoob.com
3:www.runoob.com
4:www.runoob.com
5:www.runoob.com

循环读取文件的内容:

#打开文件
fo = open("runoob.txt", "r+")
print("文件名为: ", fo.name)

line = fo.readline()
print("读取的数据为: %s" % line)

#重新设置文件读取指针到开头
fo.seek(2, 1)
line = fo.readline()
print("读取的数据为: %s" % line)

#关闭文件
fo.close()

运行一下发现报错了:

D:\Program\python34\python.exe D:/python_workshop/python6/study_file.py
Traceback (most recent call last):
文件名为:  runoob.txt
  File "D:/python_workshop/python6/study_file.py", line 158, in <module>
读取的数据为: 1:www.runoob.com
    fo.seek(2, 1)

io.UnsupportedOperation: can't do nonzero cur-relative seeks

Process finished with exit code 1

分析原因

文本文件和二进制文件

这要要从文本文件和二进制文件说起了。

从广义(物理意义)上说,二进制文件包括了文本文件,因为计算机最终存储的是二进制文件,所以物理意义上两者就是一回事,但从狭义(逻辑)上来说,两者存储的方式又有所不同。

文本文件又叫ASCII文件,这种文件在磁盘上存放时,每个字符(8个bit位)对应一个字节,用于存放对应的ASCII码,例如:

ASCII 码   00110101 00110110 00110111 00111000

|              |               |             |

     5     6     7     8

共占用了4个字节,ASCII文件可在屏幕上按字符显示。

二进制文件,是按二进制编码存放文件的,如5678的存储方式为:00010110 00101110,只占用2个字节,二进制文件虽然也可在屏幕上显示,但其内容无法读懂。C系统在处理这些文件时,并不区分类型,都看成是字符流,按字节进行处理。 输入输出字符流的开始和结束只由程序控制而不受物理符号(如回车符)的控制。 ,因此也把这种文件称作"流式文件"。

读写的区别

在读取文档时,python认为0x1A(26)是文档结束符(EOF),所以有时使用"r"读取二进制文件时,可能会出现读取不全的现象,如:

二进制文件中存在如下从低位向高位排列的数据:7F 32 1A 2F 3D 2C 12 2E 76
如果使用'r'进行读取,则读到第三个字节,即认为文件结束
如果使用'rb'按照二进制位进行读取的,不会将读取的字节转换成字符,从而避免了上面的错误

在写入文档时,写入'\n',windows操作系统会隐式的将'\n'转换为"\r\n",再写入到文件中;读的时候,会把“\r\n”隐式转化为'\n',再读到变量中,而二进制文件是非解释性的,一次处理一个字符,并且不转换字符。

r+和rb+

  • "r+"是打开一个文件用于读写。文件指针将会放在文件的开头
  • "rb+"是以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头

python3.4的官方解释

To change the file object’s position, use f.seek(offset, from_what). The position is computed from adding offset to a reference point; the reference point is selected by the from_what argument. A from_what value of 0 measures from the beginning of the file, 1 uses the current file position, and 2 uses the end of the file as the reference point. from_what can be omitted and defaults to 0, using the beginning of the file as the reference point.

意思是,为了改变文件对象的位置,可以使用f.seek(offset, from_what)方法。最终位置等于参考点位置加上偏移量,参考点是由from_what参数决定的。from_what有三个值,0代表文件的开始位置,1代表使用当前的位置,2代表文件的末尾位置。from_what参数省略时,默认是0。

python官方文档也给了一个实例:

>>> f = open('workfile', 'rb+')                      #我们可以看出,文件workfile是以二进制格式进行读写的
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5)     # Go to the 6th byte in the file
5
>>> f.read(1)
b'
>>> f.seek(-3, 2) # Go to the 3rd byte before the end
13
>>> f.read(1)
b'd'

In text files (those opened without a b in the mode string), only seeks relative to the beginning of the file are allowed (the exception being seeking to the very file end with seek(0, 2))

在文本文件中,只有在文件开头(即from_what默认是0时)进行偏移是被允许的。不允许在当前所在位置(from_what=1)和文件末尾(from_what=2)时进行偏移。

现在回头看看我们的第一个代码和报错信息,发现我们的读写模式用了"r+",我们的文件是文本文件,在使用fo.seek()时,将from_what的值设置为1,所以报错了。

#打开文件
fo = open("runoob.txt", "r+")
print("文件名为: ", fo.name)

line = fo.readline()
print("读取的数据为: %s" % line)

#重新设置文件读取指针带开头
fo.seek(2, 1)
line = fo.readline()
print("读取的数据为: %s" % line)

#关闭文件
fo.close()
D:\Program\python34\python.exe D:/python_workshop/python6/study_file.py
Traceback (most recent call last):
文件名为:  runoob.txt
  File "D:/python_workshop/python6/study_file.py", line 158, in <module>
读取的数据为: 1:www.runoob.com
    fo.seek(2, 1)

io.UnsupportedOperation: can't do nonzero cur-relative seeks

Process finished with exit code 1

延伸

如果我们把读写模式改为"rb+",以二进制的方式进行读写,那么是不是就可以了,确实可以,但不容忽视的一个小问题是,二进制文件不会对windows下的换行(\r\n, 0x0D 0x0A)进行转化的,我们看到的结果将是:

文件名为:  runoob.txt
读取的数据为: b'1:www.runoob.com\r\n'
读取的数据为: b'www.runoob.com\r\n'

参考

https://blog.csdn.net/timberwolf_2012/article/details/28499615

https://www.zhihu.com/question/19971994

https://docs.python.org/3.4/tutorial/inputoutput.html

http://bbs.fishc.com/thread-60449-1-1.html

https://www.cnblogs.com/kingleft/p/5142469.html

https://www.cnblogs.com/xisheng/p/7636736.html

https://bbs.csdn.net/wap/topics/350127738

https://www.cnblogs.com/pengwangguoyh/articles/3223072.html

https://blog.csdn.net/seu_xuxueqi/article/details/621904

http://www.xuebuyuan.com/367184.html

file.seek()方法引出的文本文件和二进制文件问题的更多相关文章

  1. 文件操作中file.seek()方法

    摘要: file.seek()可以将文件游标移动到文件的任意位置,本文具体的file.seek()文件游标移动操作方法. file.seek()方法标准格式是:seek(offset,whence=0 ...

  2. Python File seek() 方法

    概述 seek() 方法用于移动文件读取指针到指定位置.高佣联盟 www.cgewang.com 语法 seek() 方法语法如下: fileObject.seek(offset[, whence]) ...

  3. 【c的文件操作】文本文件和二进制文件(内存映像)的不同 文件结尾判断feof , EOF

    查看 stdio.h 可以看到如下定义: #define  EOF  (-1) #define  _IOEOF  0x0010  #define  feof(_stream)  ((_stream)- ...

  4. 020_Python3 File(文件) 方法

    1.open() 方法 Python open() 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError. 注意:使用 open ...

  5. 吴裕雄--天生自然python学习笔记:Python3 File(文件) 方法

    open() 方法 Python open() 方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要使用到这个函数,如果该文件无法被打开,会抛出 OSError. 注意:使用 open() ...

  6. Python学习(16)File(文件)方法

    Python File(文件) 方法 file 对象使用 open 函数来创建,下表列出了 file 对象常用的函数: 序号 方法及描述 1 file.close() 关闭文件.关闭后文件不能再进行读 ...

  7. 小小换行符乱谈(文本文件vs二进制文件)

    使用 C 语言的 fopen 打开文件时,可以指定的 mode 有 12 个,其中 6 个包含  "b" 使用 C++ 的 fstream 打开文件时,可用的模式组合有 24 个( ...

  8. Python File(文件) 方法

    file 对象使用 open 函数来创建,下表列出了 file 对象常用的函数: 序号 方法及描述 1 file.close() 关闭文件.关闭后文件不能再进行读写操作. 2 file.flush() ...

  9. Python3基础 file seek 将文件的指针恢复到初始位置

             Python : 3.7.0          OS : Ubuntu 18.04.1 LTS         IDE : PyCharm 2018.2.4       Conda ...

随机推荐

  1. Qt里的原子操作QAtomicInteger

    所谓原子操作,即一系列复杂的操作能一气呵成,中间不被其他的操作打断.这在多线程程序中尤其常见,但要实现这种功能,既要考虑程序的良好设计,又要关心特定平台的体系结构和相关编译器对原子特性的支持程度.所以 ...

  2. [IOI2018]狼人

    [IOI2018]狼人 luogu UOJ 对人形和狼形分别建克鲁斯卡尔重构树 每次询问就是对于两棵树dfs序的一个二维数点,主席树维护 #include<bits/stdc++.h> u ...

  3. LinuxCentos系统安装Nginx过程记录

    网站服务 想必我们大多数人都是通过访问网站而开始接触互联网的吧.我们平时访问的网站服务就是Web网络服务,一般是指允许用户通过浏览器访问到互联网中各种资源的服务. Web网络服务是一种被动访问的服务程 ...

  4. ABAP rfc 发布webservice 错误

    一.SICF 测试服务报错: 哎呀,找不到网页! 网站在检索此网址时出现错误.托管此网站的服务器可能关闭进行维护或配置不正确. HTTP ERROR 500

  5. MySQL中的DDL,DML

    MySQL中的DDL,DMLDDL:数据定义语言:    CREATE,ALTER,DROP        DB组件:数据库.表.索引.视图.用户.存储过程.存储函数.触发器.事件调度器等    CR ...

  6. JAVA使用DES加密解密

    在使用DES加密解密的时候,遇到了一些问题,廖记一下.如有哪位大神亲临留言指点,不胜感激. 先上代码: public DESUtil() { } //密码,长度要是8的倍数 注意此处为简单密码 简单应 ...

  7. 每天一个Linux命令(49)traceroute命令

        traceroute指令让你追踪网络数据包的路由途径,预设数据包大小是40Bytes.     (1)用法:     用法: traceroute [参数] [主机]   (2)功能:     ...

  8. HTML学习笔记(上)

    1. HTML介绍 1.1 什么是HTML HyperText Markup Language,超文本标记语言.简单来说,HTML文件本质上就是一个文本文件,但是这个文本文件是带有标签的. 不同的标签 ...

  9. apache2.4配置ssl

    1,yum 安装openssl和openssl-devel,httpd-devel2,生成证书(也可以从公司的证书颁发机构获取): #建立服务器密钥 openssl genrsa -des3 > ...

  10. Windos Server 2008 FTP 服务安装

    安装服务:FTP 系统环境:Windos 2008 R2 x64 安装FTP服务 管理-->角色-->添加角色-->Web 服务器 IIS 测试