IO编程
IO在计算机中就是input\output,就是输入\输出。凡是用到数据交换的地方,都会涉及IO编程,例如磁盘、网络的数据传输。
在计算机系统中I/O操作针对不同的操作对象,可以划分为磁盘I/O模型,网络I/O模型,内存映射I/O, Direct I/O、数据库I/O等,只要具有输入输出类型的交互系统都可以认为是I/O系统,也可以说I/O是整个操作系统数据交换与人机交互的通道,这个概念与选用的开发语言没有关系,是一个通用的概念。
在IO编程中,Stream(流)是一个很重要的概念:只不过流的概念一直让人比较混淆。输入\输出流是相对于内存而言的。程序运行在内存当中,文件保存在磁盘里面,如果读取一个文件,是从磁盘到内存当中,属于输入流。如果从程序中输出到文件中,便是内存写入到磁盘,是输出流。
我们可以把流理解为一个水管,数据相当于水管中的水,但是只能单向流动,所以数据传输过程中需要架设两个水管,一个负责输入,一个负责输出,这样读写就可以实现同步。
文件的读写操作
读写文件就是一个常见的IO操作,python编程中给我们内置了读写文件的一些函数:
1,打开文件:
在用程序对一个文件操作之前需要打开这个文件,并且要确定打开文件的读写模式
open函数是用来打开文件的一个语句,用法如下:
open(文件名,读写模式,缓冲区)
其中打开文件的文件名是必填参数,另外两个是可选参数。
参数说明:
2,文件读取
文件的读取分为按字节读取和按行读取
常用的方法有三个:
f = open(文件名)
1. f.read(参数)——按字节读取,返回str类型的对象,参数是要读取的前几个字符
2. f.readline(参数)——读取文件内容的第一行,返回str类型的对象,参数是读取的第一行的前几个字符
3. f.readlines()——一次性读取整个文件,自动将文件每一行的内容分别放在列表里。
f.close()
最后一步调用close(),可以关闭对文件的引用。文件使用完毕后必须关闭,因为文件对象会占用操作系统资源,影响系统的IO操作。
由于文件操作可能会出现IO异常,例如打开的文件不存在。一旦出现IO异常,后面的close()方法就不会调用,文件打开后就无法正常关闭。所以为了保证程序的合理性,我们需要使用try……finally异常捕获来实现。
try:
f = open(r'c:\test\test.txt','r')
f.read()
finally:
if f:
f.close()
上面的代码是为了保证不管文件有没有打开出错,最终都会关闭文件。
但是上面的代码有点长,python代码里面提供了一个with语句也可以实现同样的效果。
with open(r'c:\test\test.txt','r') as fileReader:
fileReader.read()
with语句的格式:
with 表达式 as 变量:
执行语句
with后面是一个需要执行的表达式,变量里面存放的是表达式返回的结果,下面是执行语句。
with 语句适用于对资源进行访问的场合,确保不管使用过程中是否发生异常都会执行必要的“清理”操作,释放资源,比如文件使用后自动关闭、线程中锁的自动获取和释放等。
关于with语句,更加详细的说明:↓
https://wenku.baidu.com/view/698508022c60ddccda38376baf1ffc4ffe47e2a7.html
3,文件的写入:
写文件和读文件是一样的,唯一的区别是在调用open方法时,读写默认传入标识符‘w’或者‘wb’或者‘a’表示写入文本文件或者写入二进制文件,示例如下:
f = open(r'c:\test\test.txt','w')
f.write('qiye')
f.close()
在close关闭文件之间可以一直用write写入内容
使用write()方法的时候,操作系统不是立即将数据写入文件中的,而是先写入内存中缓存起来,等到空闲时候再写入文件中,最后使用close()方法就将数据完整地写入文件中了。当然也可以使用f.flush()方法,不断将数据立即写入文件中,最后使用close()方法来关闭文件。和读文件同样道理,文件操作中可能会出现IO异常,所以还是推荐使用with语句:
with open(r'c:\text\qiye.txt','w') as fileWriter:
fileWriter.write('qiye')
操作文件和目录
我们可以通过编写一个python代码去对电脑里面的文件或者文件夹来操作。
下面介绍一下文件操作的一些语句:
import os
os.getcwd() # 获得当前Python脚本工作的目录路径
os.listdir() # 返回指定目录下的所有文件和目录名
os.remove() # 删除一个指定目录的文件,不能用来删除文件夹,否则拒绝访问
os.removedirs() # 删除多个空目录
os.path.isfile() # 检验给的路径是不是一个文件
os.path.isdir() # 检验给的路径是不是一个文件夹
os.path.isabs() # 判断是否是绝对路径
os.path.exists() # 检验路径是否真的存在
os.path.split() # 分离一个路径内容的目录名和文件名
例如:os.path.split(r“/home/test/test.txt”),返回结果是一个元组:(‘/home/test’,‘test.txt’)
os.path.splitxt() # 分离拓展名
例如:os.path.splitxt(r“/home/test/test.txt”),返回结果是一个元组(‘/home/test/test’,‘.txt’)
os.path.dirname() # 获取路径名
os.path.basename() # 获取文件名
os.getenv()与os.putenv() # 读取和设置环境变量
os.linesep # 给出当前平台使用的行终止符
os.name # 指示你正在使用的平台,对于Windows,它是‘nt’,而对于Linux/Unix用户,它是‘posix’
os.rename(old,new) # 重命名文件或者目录
os.makedirs(r“c:\python\test”) # 创建多级目录
os.makedir('test') # 创建单个目录
os.stat() # 获取文件属性
os.chmod() # 修改文件权限与时间戳
os.path.getsize # 获取文件大小
shutil.copytree(“olddir”,“newdir”) # 复制文件夹,olddir和newdir都只能是目录,且newdir必须不存在。
复制文件:shutil.copyfile(“oldfile”,“newfile”),oldfile和newfile都只能是文件;shutil.copy(“oldfile”,“newfile”),oldfile只能是文件,newfile可以是文件,也可以是目标目录
shutil.move(“oldpos”,“newpos”) # 移动文件或目录
os.rmdir(“dir”) # 删除目录,只能删除空目录
shutil.rmtree(“dir”)# 删除目录,空目录、有内容的目录都可以删
序列化操作
序列化是什么
从百度百科中可以得知,序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。所以说序列化是一种技术。
对象的序列化在很多高级编程语言中都有相应的实现,Python也不例外。程序运行时,所有的变量都是在内存中的,例如在程序中声明一个dict对象,里面存储着爬取的页面的链接、页面的标题、页面的摘要等信息:
d = dict(url='index.html',title='首页',content='首页')
在程序运行的过程中爬取的页面的链接会不断变化,比如把url改成了second.html,但是程序一结束或意外中断,程序中的内存变量都会被操作系统进行回收。如果没有把修改过的url存储起来,下次运行程序的时候,url被初始化为index.html,又是从首页开始,这是我们不愿意看到的。所以把内存中的变量变成可存储或可传输的过程,就是序列化。
将内存中的变量序列化之后,可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上,实现程序状态的保存和共享。反过来,把变量内容从序列化的对象重新读取到内存,称为反序列化。
python中提供了两个模块来进行序列化操作:cPickle和pickle。前者是由C语言编写的,效率比后者高很多,但是两个模块的功能是一样的。
一般编写程序的时候,采取的方案是先导入cPickle模块,如果此模块不存在,再导入pickle模块。示例如下:
try:
import cPickle as pickle
except ImportError:
import pickle
pickle实现序列化主要使用的是dumps方法或dump方法。dumps方法可以将任意对象序列化成一个str,然后可以将这个str写入文件进行保存。在Python Shell中示例如下:
>>> import cPickle as pickle
>>> d = dict(url='index.html',title='首页',content='首页')
>>> pickle.dumps(d)
"(dp1\nS'content'\np2\nS'\\xca\\xd7\\xd2\\xb3'\np3\nsS'url'\np4\nS'index.html'\n
p5\nsS'title'\np6\ng3\ns."
如果使用dump方法,可以将序列化后的对象直接写入文件中:
>>> f=open(r'D:\dump.txt','wb')
>>> pickle.dump(d,f)
>>> f.close()
pickle实现反序列化使用的是loads方法或load方法。把序列化后的文件从磁盘上读取为一个str,然后使用loads方法将这个str反序列化为对象,或者直接使用load方法将文件直接反序列化为对象,如下所示:
>>> f=open(r'D:\dump.txt','rb')
>>> d=pickle.load(f)
>>> f.close()
>>> d
{'content':'\xca\xd7\xd2\xb3', 'url':'index.html', 'title':'\xca\xd7\xd2\xb3'}
通过反序列化,存储为文件的dict对象,又重新恢复出来,但是这个变量和原变量没有什么关系,只是内容一样。以上就是序列化操作的整个过程。
假如我们想在不同的编程语言之间传递对象,把对象序列化为标准格式是关键,例如XML,但是现在更加流行的是序列化为JSON格式,既可以被所有的编程语言读取解析,也可以方便地存储到磁盘或者通过网络传输。
进程和线程
进程和线程是两个很重要的概念,可以提高爬虫的效率。打造分布式爬虫,都离不开进程和线程的身影。
下面是自己总结的线程,进程和协程的知识点。
Socket类型,TCP编程,UDP编程
学习爬虫当然要了解一些网络编程知识
计算机网络是把各个计算机连接到一起,让网络中的计算机可以互相通信。网络编程就是如何在程序中实现两台计算机的通信。例如当你使用浏览器访问谷歌网站时,你的计算机就和谷歌的某台服务器通过互联网建立起了连接,然后谷歌服务器会把把网页内容作为数据通过互联网传输到你的电脑上。
网络编程对所有开发语言都是一样的,Python也不例外。使用Python进行网络编程时,实际上是在Python程序本身这个进程内,连接到指定服务器进程的通信端口进行通信,所以网络通信也可以看做两个进程间的通信。
下面是自己总结的Socket以及TCP和UDP的知识点。
TCP和UDP