循环解压
import os
import zipfile
class Unzip(object):
@staticmethod
def scan(source_dir):
for sub_file in sorted(os.listdir(source_dir)):
sub_file_path = os.path.join(source_dir, sub_file)
if os.path.isdir(sub_file_path):
Unzip.scan(sub_file_path)
else:
if sub_file_path.lower().endswith('.zip'):
print(sub_file_path)
output_sub_dir = sub_file_path[:-4]
try:
Unzip.unzip(sub_file_path, output_sub_dir)
Unzip.scan(output_sub_dir)
except zipfile.BadZipFile:
pass
# os.remove(sub_file_path)
@staticmethod
def unzip(file, folder):
fz = zipfile.ZipFile(file, 'r')
for sub_file_name in fz.namelist():
fz.extract(sub_file_name, folder)
if __name__ == '__main__':
# root = r'D:\Projects\EP\OCR\2018'
root = '/data/ep'
Unzip.scan(root)
编码后压缩、解压后解码
import gzip
import base64
class Compress:
@staticmethod
def str2gz(text):
'''
str to Dynamodb binary
:param text: text to compress
:return:
'''
data = text.encode('utf-8')
gziped = gzip.compress(data)
return gziped
@staticmethod
def gz2str(data):
'''
Dynamodb binary to str
:param data: byte[]
:return: string
'''
flat = gzip.decompress(data)
return flat.decode('utf-8')
if __name__ == '__main__':
# 数据库中存储的是经过编码和压缩的value,是二进制的,而扫表时经过json转化写入文件后,将二进制字符直接变成了string类型
value_in_file = 'H4sIAAAAAAAAAHN2dnVzdPYLiIhwdA5xB5IANLDxZBEAAAA='
# 得到value最开始的值
value = Compress.gz2str(base64.decodebytes(value_in_file.encode('utf-8')))
# 对value进行压缩
gzip_value = Compress.str2gz(value)
print(gzip_value)
IO
同步IO:CPU等该条命令执行完再执行下一条命令
异步IO:CPU不等待该条命令执行完就执行下一条命令。分为回调模式、轮询模式
文件读写
with open() as file:
for line in file:
...
无论能否正确打开文件,都能关闭,不需要手动去close() 文件句柄,而且可以让系统自动进行IO缓存和内存管理,不需要管系统怎么去分配这些内存,真是读取大文件的利器。
写文件时加上编码说明,用write写内容时不会自动加上换行符,需手动添加。
with open('a.txt', 'a', encoding='utf-8') as a:
a.write('hello' + '\n')
编码
历史发展
编码、解码关系
Python里面的编码和解码也就是 unicode 和 str 这两种形式的相互转化
encode的作用,使我们看到的直观的字符转换成计算机内的字节形式
decode把字节形式的字符转换成我们看的懂的、直观的、“人模人样”的形式
Python 2.x的默认编码格式是ASCII,就是说,在没有指定Python源码编码格式的情况下,源码中的所有字符都会被默认为ASCII码。
python3中默认的编码格式是utf-8,计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。
特殊情况
解决错误编码的字符串
在Python3中,若字符串以字节形式表示,则必须加上前缀b,也就是写成b'xxxx'形式。
import chardet
b = b'\xe4\xbd\xa0\xe5\xa5\xbd'
print(type(b)) # <class 'bytes'>
print(chardet.detect(b)) # {'encoding': 'utf-8', 'confidence': 0.7525, 'language': ''}
b_ = b.decode()
print(b_) # 你好
print(type(b_)) # <class 'str'>
有时会遇到下面这样类似unicode的字符串,没有前缀b,无法encode成想要的形式
\x表示后面是十六进制
a = '\xe4\xbd\xa0\xe5\xa5\xbd'
print(a) # 返回乱码
print(type(a)) # <class 'str'>
print(a.encode('utf-8')) # b'\xc3\xa4\xc2\xbd\xc2\xa0\xc3\xa5\xc2\xa5\xc2\xbd'
print(a.encode('utf-8', 'ignore')) # b'\xc3\xa4\xc2\xbd\xc2\xa0\xc3\xa5\xc2\xa5\xc2\xbd'
python 提供了一个特殊的编码( raw_unicode_escape )用来处理这种情况,先编码,再解码即可
a_ = a.encode('raw_unicode_escape').decode('utf-8')
print(a_) # 你好
print(type(a_)) # <class 'str'>
异常处理
异常:
UnicodeDecodeError: 'utf8' codec can't decode byte 0xb2 in position 24137: invalid start byte
处理:
使用decode('utf-8', 'ignore')
网络传输
- HTTP中以base64编码发送数据:
att.add_header('Content-Disposition','attachment',filename = '=?utf-8?b?' + base64.b64encode(os.path.basename(id[7]).encode('UTF-8')) + '?=')
- 当取回来的数据与你当前脚本中声明的编码不一致时就要做编码转换
- 在编码转换时首先要将该数据以自身编码的格式解码成unicode码,再对这个unicode进行编码,如编码城utf-8
- “ZELBORAF®”特殊字符的编码:.decode("ISO-8859-1")
文件编码
如果知道文件的编码方式,可用codecs模块在读文件时转换编码:
import codecs
with codecs.open("test.txt",'r','utf-8') as data:
for seq in data:
print seq
获取文件编码方式
无论文件大小都可快速获取编码方式:
方法一
import chardet
bytes = min(32, os.path.getsize(filename))
raw = open(filename, 'rb').read(bytes)
result = chardet.detect(raw)
encoding = result['encoding']
with open(filename, encoding=encoding) as f:
for line in f:
do()
方法二
import chardet
with open(path, 'rb') as file:
data = file.read(200000)
dicts = chardet.detect(data)
encoding = dicts["encoding"]
中文编码建议如下处理
if encode.startswith('GB') or encode.startswith('Windows'):
encode = 'GB18030'
read()
每次读取整个文件,将文件内容放到一个字符串变量中,如果文件大于可用内存,不能使用这种处理。
readlines()
一次读取整个文件,自动将文件内容分析成一个行的列表。
for seq in data.readlines():
print seq.split('\t')[1]
readline()
每次只读取一行,返回的是一个字符串对象,保存当前行的内容,通常比 .readlines() 慢得多,仅当没有足够内存可以一次读取整个文件时,才选择使用。
while True:
line = f.readline()
if line: break
do()
读写标记
r只读,r+读写并覆写,不创建
w新建只写,不能读出,w+新建读写,二者都会将文件内容清零
r+:可读可写,若文件不存在,报错
w+: 可读可写,若文件不存在,创建
a:附加写方式打开,不可读
a+: 附加读写方式打开
不可读的打开方式:w和a
若不存在会创建新文件的打开方式:a,a+,w,w+
当我们写文件时,操作系统往往不会立刻把数据写入磁盘,而是放到内存缓存起来,空闲的时候再慢慢写入。只有调用close()方法时,操作系统才保证把没有写入的数据全部写入磁盘。忘记调用close()的后果是数据可能只写了一部分到磁盘,剩下的丢失了。
操作文件和目录
import os, shutil
os.listdir() #返回指定路径下的文件和文件夹列表。
os.path.isdir() #判断路径是否为目录
os.path.isfile() #判断路径是否为文件
os.path.abspath(path) #返回path规范化的绝对路径
os.path.join('/gpfs/data','testfastq') #返回/gpfs/daa/testfastq
os.path.seq #返回当前系统的路径的分隔符,如windows的是“\”,Linux的是“/”
os.path.split(path) #将path分割成目录和文件名二元组返回
os.path.dirname(path) #返回文件路径,就是os.path.split(path)的第一个元素
os.path.basename(path) #返回文件名,就是os.path.split(path)的第二个元素
os.path.exists(path) #路径存在则返回True,否则返回False
os.path.splitext(path) #返回列表,包含文件名和后缀
os.mkidr() #新建目录
os.rmdir() #删除目录
os.rename('a.txt','a.py') #重命名文件
os.remove() #删除文件
os.walk() #返回路径、子文件夹名字、文件名,再逐个显示子文件夹路径、子子文件夹名、文件名……文件夹名和文件名放在列表中。
shutil.rmtree(path) #删除文件夹,不管是否为空
os.path.splitext() #得到文件扩展名
序列化
把变量从内存中变成可存储或传输的过程称之为序列化,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等等,都是一个意思。
序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上。
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化,即unpickling。
在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为JSON,因为JSON表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。JSON不仅是标准格式,并且比XML更快,而且可以直接在Web页面中读取,非常方便。
dumps()方法返回一个str,内容就是标准的JSON。
dump()方法可以直接把JSON写入一个file-like Object。
用loads()或者对应的load()方法,前者把JSON的字符串反序列化,后者从file-like Object中读取字符串并反序列化: