当前位置: 首页 > article >正文

python28-IO编程、文件读写、os模块

IO在计算机中指Input/Output,也就是输入和输出。

涉及到数据交换的地方,通常是磁盘、网络等,就需要IO接口。

IO编程中,Stream(流)是一个很重要的概念,可以把流想象成一个水管,数据就是水管里的水,但是只能单向流动。Input Stream就是数据从外面(磁盘、网络)流进内存,Output Stream就是数据从内存流到外面去。对于浏览网页来说,浏览器和新浪服务器之间至少需要建立两根水管,才可以既能发数据,又能收数据。

一、同步IO、异步IO

由于CPU和内存的速度远远高于外设的速度,所以,在IO编程中,就存在速度严重不匹配的问题。

比如要把100M的数据写入磁盘,CPU输出100M的数据只需要0.01秒,可是磁盘要接收这100M数据可能需要10秒,怎么办呢?有两种办法:

第一种是CPU等着,也就是程序暂停执行后续代码,等100M的数据在10秒后写入磁盘,再接着往下执行,这种模式称为同步IO;

另一种方法是CPU不等待,只是告诉磁盘,“您老慢慢写,不着急,我接着干别的事去了”,于是,后续代码可以立刻接着执行,这种模式称为异步IO。

同步和异步的区别就在于是否等待IO执行的结果。

很明显,使用异步IO来编写程序性能会远远高于同步IO,但是异步IO的缺点是编程模型复杂。

想想看,你得知道什么时候通知你“汉堡做好了”,而通知你的方法也各不相同。如果是服务员跑过来找到你,这是回调模式,如果服务员发短信通知你,你就得不停地检查手机,这是轮询模式。总之,异步IO的复杂度远远高于同步IO。

操作IO的能力都是由操作系统提供的,每一种编程语言都会把操作系统提供的低级C接口封装起来方便使用,Python也不例外。

本章的IO编程都是同步模式。

二、文件读写

读写文件是最常见的IO操作。

在磁盘上读写文件的功能都是由操作系统提供的,现代操作系统不允许普通的程序直接操作磁盘,所以,读写文件就是请求操作系统打开一个文件对象(通常称为文件描述符),然后,通过操作系统提供的接口从这个文件对象中读取数据(读文件),或者把数据写入这个文件对象(写文件)。

2-1、读文件

要以读文件的模式打开一个文件对象,使用Python内置的open()函数,传入文件名和标示符:

f = open('/Users/michael/test.txt', 'r')

标示符'r'表示读,这样,我们就成功地打开了一个文件。

如果文件不存在,open()函数就会抛出一个IOError的错误:

如果文件打开成功,接下来,调用read()方法可以一次读取文件的全部内容,Python把内容读到内存,用一个str对象表示:

最后一步是调用close()方法关闭文件。

文件使用完毕后必须关闭,因为文件对象会占用操作系统的资源,此时要是想要对文件做其他操作,比如删除、重命名,就会失败!并且操作系统同一时间能打开的文件数量也是有限的:

f.close()

由于文件读写时都有可能产生IOError一旦出错,后面的f.close()就不会调用。所以,为了保证无论是否出错都能正确地关闭文件,我们可以使用try ... finally来实现:

也可以用for循环,每次读取一行:

2-2、with语句

但是每次都这么写实在太繁琐,所以,Python引入了with语句来自动帮我们调用close()方法:

这和前面的try ... finally是一样的,但是代码更佳简洁,并且不必调用f.close()方法

2-3、read()、read(size)、readline()、readlines()

        调用read()会一次性读取文件的全部内容,如果文件有10G,内存就爆了,所以,要保险起见,可以反复调用read(size)方法,每次最多读取size个字节的内容。

read(size)示例:

或者:

【注意】:

若是在程序中多次调用read(),下一个read会在上一个read的结尾处接着读取的!

        另外,调用readline()可以每次读取一行内容,调用readlines()一次读取所有内容并按行返回list。因此,要根据需要决定怎么调用。

readline()示例:

readlines()示例: 

【注意】:

        读取文件的时候,只要文件对象打开后,后面不管调用什么方法,都会续借上一次读取文件的位置处开始读取!

2-4、file-like Object

open()函数返回的这种有个read()方法的对象,在Python中统称为file-like Object。

除了file外,还可以是内存的字节流,网络流,自定义流等等。file-like Object不要求从特定类继承,只要写个read()方法就行

StringIO就是在内存中创建的file-like Object,常用作临时缓冲。

2-5、二进制文件

要读取二进制文件,比如图片、视频等等,用'rb'模式打开文件即可:

 

2-6、字符编码

要读取非UTF-8编码的文本文件,需要给open()函数传入encoding参数,例如,读取GBK编码的文件:

遇到有些编码不规范的文件,你可能会遇到UnicodeDecodeError,因为在文本文件中可能夹杂了一些非法编码的字符。遇到这种情况,open()函数还接收一个errors参数,表示如果遇到编码错误后如何处理。最简单的方式是直接忽略:

f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')

【注意】:

前两个参数是位置指定;

encoding和errors是关键字传参,因为不是第三、第四个参数! 

2-7、写文件

写文件和读文件是一样的,唯一区别是调用open()函数时,传入标识符'w'或者'wb'表示写文本文件或写二进制文件:

或者:

当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存区起来,空闲的时候再慢慢写入。只有调用close()方法,或者flush()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。

close()方法是内置了flush的功能的。

所以,还是用with语句来得保险:

要写入特定编码的文本文件,请给open()函数传入encoding参数,将字符串自动转换成指定编码。

'w'方式的两种特点:

1、文件不存在,会创建新文件;

2、文件已存在,会直接覆盖内容。

细心的童鞋会发现,以'w'模式写入文件时,如果文件已存在,会直接覆盖(相当于删掉后新写入一个文件)。如果我们希望追加到文件末尾怎么办?可以传入'a'追加(append)模式写入。

2-8、常见的三种基础访问模式

三、操作文件和目录

如果我们要操作文件、目录,可以在命令行下面输入操作系统提供的各种命令来完成。比如dircp等命令。

如果要在Python程序中执行这些目录和文件的操作怎么办?

其实操作系统提供的命令只是简单地调用了操作系统提供的接口函数,Python内置的os模块也可以直接调用操作系统提供的接口函数。 

3-1、os模块

Python 的os模块提供了许多与操作系统交互的功能,允许你进行文件和目录操作、进程管理、环境变量处理等。

如果是posix,说明系统是LinuxUnixMac OS X,如果是nt,就是Windows系统。

【注意】:

os模块的某些函数是跟操作系统相关的,有些函数LinuxUnixMac OS X有,但是Windows系统没有!

1、环境变量的处理

在操作系统中定义的环境变量,全部保存在os.environ这个变量中,可以直接查看:

  • 获取环境变量:要获取某个环境变量的值,可以调用os.environ.get('key')

 

  • 设置环境变量:使用os.environ[key] = value的方式可以设置环境变量:

2、操作目录

操作文件和目录的函数一部分放在os模块中,一部分放在os.path模块中。

  • 获取当前工作目录:使用os.getcwd()方法可以获取当前 Python 脚本所在的工作目录。

  • 更改当前工作目录:使用os.chdir(path)方法可以更改当前的工作目录。

  • 列出目录内容os.listdir(path)方法用于列出指定目录中的所有文件和子目录。

  • 检查文件目录是否存在:使用os.path.exists(path)方法可以检查指定的文件或目录是否存在。

  • 判断是否为文件目录os.path.isfile(path)os.path.isdir(path)方法分别用于判断指定路径是否为文件或目录。

  • 创建文件夹:

1、使用os.mkdir()函数

os.mkdir()函数用于创建一个新的文件夹,如果指定的文件夹已经存在,则会抛出FileExistsError异常

2、使用os.makedirs()函数

os.makedirs()函数可以递归地创建多层文件夹,如果中间的文件夹不存在,会自动创建。

  • 删除文件夹:

1、使用os.rmdir()函数

os.rmdir()函数用于删除一个空文件夹,如果文件夹不为空,则会抛出OSError异常。

2、使用shutil.rmtree()函数
shutil.rmtree()函数可以删除一个非空文件夹及其所有内容,包括子文件夹和文件。

  • 重命名文件、文件夹

  • 把两个路径合并成一个:

可以使用 os.path.join() 函数来将两个或多个路径合成一个路径,这个函数会根据操作系统的规则自动处理路径分隔符等问题:

os.path.join() 函数不仅可以拼接两个路径,还可以拼接多个路径,它会按照正确的顺序依次组合这些路径:

  • 拆分路径

同样的道理,要拆分路径时,也不要直接去拆字符串,而要通过os.path.split()函数,这样可以把一个路径拆分为两部分,后一部分总是最后级别的目录或文件名:

os.path.splitext()可以直接让你得到文件扩展名,很多时候非常方便:

【注意】:

这些合并、拆分路径的函数并不要求目录和文件要真实存在,它们只对字符串进行操作。

3、shutil模块 

但是复制文件的函数居然在os模块中不存在!原因是复制文件并非由操作系统提供的系统调用。理论上讲,我们通过读写文件可以完成文件复制,只不过要多写很多代码。

幸运的是shutil模块提供了copyfile()的函数,你还可以在shutil模块中找到很多实用函数,它们可以看做是os模块的补充


http://www.kler.cn/a/466620.html

相关文章:

  • TPS和QPS的区别
  • Linux下编译安装PETSc
  • 余华和他的书
  • 小程序学习06——uniapp组件常规引入和easycom引入语法
  • windows11安装minikube
  • RabbitMQ通过代码创建交换机和队列
  • [商业化] 【微软商店】如何申请ITIN、修改Manifest并处理Win32应用的FullTrust权限
  • 区块链安全常见的攻击分析——拒绝服务攻击 (Denial of Service-DOS)King合约【11】
  • ROS导航使用贝塞尔曲线对全局路径进行平滑处理
  • 一份完整的软件测试报告如何编写?
  • 拆解 Web3:探寻去中心化网络的核心密码
  • RK3588+麒麟国产系统+FPGA+AI在电力和轨道交通视觉与采集系统的应用
  • mysql连接时报错1130-Host ‘hostname‘ is not allowed to connect to this MySQL server
  • 积木(01)
  • @Transactional注解 细节!
  • 检索增强生成(RAG):大语言模型的创新应用
  • LeetCode 141:环形链表
  • C++面向对象编程:纯虚函数、抽象类、虚析构、纯虚析构
  • 【项目】多模态图文理解-GLM-Edge实战
  • Scala_【5】函数式编程
  • 以太网连接,本地连接,宽带连接,无线WLAN连接;交换机和路由器
  • 【MyBatis-Plus 条件构造器】全面解析 Wrapper
  • 【赵渝强老师】MongoDB文档级别的并发控制
  • vue 虚拟滚动 vue-virtual-scroller RecycleScroller
  • logback日志文件多环境配置路径
  • Linux下读取Windows下保存的文件,报错信息中出现“^M“时如何解决?【由于Windows和Linux的换行方式不同造成的-提供两种转换方式】