读写文本数据

使用其他分隔符或行终止符打印

问题:

  你想使用print() 函数输出数据,但是想改变默认的分隔符或者行尾符。

解决方案:

  可以使用在print() 函数中使用sep 和end 关键字参数,以你想要的方式输出。比如:

 1 #正常输出
 2 print('dmeon', 89 , 8, 23)
 3 
 4 #指定分隔符,
 5 print('dmeon', 89 , 8, 23, sep=',')
 6 
 7 #指定结尾符号
 8 print('dmeon', 89 , 8, 23, sep=',',end='!!!
')
 9 
10 #使用end 参数也可以在输出中禁止换行。比如:
11 for i in range(5):
12     print(i, end=' ')
13 
14 #另外一种添加分隔符的方法
15 print()
16 print('分隔符的方法'.center(30, '-'))
17 s1 = ('dmeon', 89 , 8, 23)
18 result = ' '.join((str(s) for s in s1))
19 print(result)
20 
21 #高逼格的方法
22 print("s1的值", s1)
23 print('高逼格的输出方式', *s1,sep=',')

以上代执行输出的结果为:

dmeon 89 8 23
dmeon,89,8,23
dmeon,89,8,23!!!
0 1 2 3 4 
------------分隔符的方法------------
dmeon 89 8 23
s1的值 ('dmeon', 89, 8, 23)
高逼格的输出方式,dmeon,89,8,23

读写字节数据

问题:

  你想读写二进制文件,比如图片,声音文件等等

解决方案:

  使用模式为rb 或wb 的open() 函数来读取或写入二进制数据。比如:

 1 #使用with打开文件,不需要考虑文件close的问题,rb模式是使用读二进制的模式打开
 2 with open('/tmp/go.pdf', 'rb') as f:
 3     #获取文件中的内容
 4     data = f.read()
 5 
 6 #wb是写的二进制模式打开,当文件存在会覆盖文件已有的内容,文件不存在会创建
 7 with open('/tmp/test.bin','wb') as f:
 8     f.write(b'Hello World')
 9 
10 #天坑,读取二进制数据的时候,字节字符串和文本字符串的语义差异可能会导致一个潜在的陷阱
11 t = 'Hello World'
12 print("t中0索引第一个元素为:", t[0])
13 
14 #循环t并打印每个元素
15 for i in t:
16     print('循环t中的每个元素:', i)
17 
18 #坑的地方来了
19 print('*'*30)
20 b = b'Hello World'
21 print('b中0索引的元素:', b[0])
22 
23 #循环bytes类型b变量中的每个元素
24 for x in b:
25     print('循环b中的每个元素:', x)

以上代执行输出的结果为:

t中0索引第一个元素为: H
循环t中的每个元素: H
循环t中的每个元素: e
循环t中的每个元素: l
循环t中的每个元素: l
循环t中的每个元素: o
循环t中的每个元素:  
循环t中的每个元素: W
循环t中的每个元素: o
循环t中的每个元素: r
循环t中的每个元素: l
循环t中的每个元素: d
******************************
b中0索引的元素: 72
循环b中的每个元素: 72
循环b中的每个元素: 101
循环b中的每个元素: 108
循环b中的每个元素: 108
循环b中的每个元素: 111
循环b中的每个元素: 32
循环b中的每个元素: 87
循环b中的每个元素: 111
循环b中的每个元素: 114
循环b中的每个元素: 108
循环b中的每个元素: 100

如果你想从二进制模式的文件中读取或写入文本数据,必须确保要进行解码和编码操作。比如:

1 with open('/tmp/test.bin', 'rb') as f:
2     data = f.read(16)
3     print('data的数据类型:', type(data))
4     print('data的数据:', data)
5 
6     text = data.decode('utf-8')
7     print('data转码以后的数据类型:', type(text))
8     print('text的数据:', text)

以上代执行输出的结果为:

data的数据类型: <class 'bytes'>
data的数据: b'Hello World'
data转码以后的数据类型: <class 'str'>
text的数据: Hello World

文件不存在才能写入

问题:

  你想像一个文件中写入数据,但是前提必须是这个文件在文件系统上不存在。也就是不允许覆盖已存在的文件内容

解决方案:

  可以在open() 函数中使用x 模式来代替w 模式的方法来解决这个问题。比如:

 1 #如果文件存在,会覆盖内容,如果文件不存在会创建文件并写入内容
 2 with open('/tmp/test.bin', 'wt') as f:
 3     f.write('Hello
')
 4 
 5 #如果文件存在,会报异常,否则创建文件并写入内容,如果文件是二进制,使用wb代替
 6 try:
 7     f = open('/tmp/test.bin', 'xt')
 8 except Exception as e:
 9     print(e)
10 else:
11     f.write('Hello
')
12 finally:
13     f.close()

以上代执行输出的结果为:

[Errno 17] File exists: '/tmp/test.bin'

字符串的I/O 操作

问题:

  你想使用操作类文件对象的程序来操作文本或二进制字符串

解决方案:

  使用io.StringIO() 和io.BytesIO() 类来创建类文件对象操作字符串数据。比如:

 1 import io
 2 
 3 s = io.StringIO()
 4 print(s.write('Hello World
'))
 5 
 6 print('This is a test', file=s)
 7 
 8 #获取s中的内容
 9 content = s.getvalue()
10 print('s中的内容为:', content)
11 
12 #读取5个长度的内容
13 s = io.StringIO('Hello
World
')
14 print("五个字符的内容:")
15 print(s.read(5))
16 
17 #读取剩余的内容
18 print("剩余的内容:")
19 print(s.read())

以上代执行输出的结果为:

12
s中的内容为: Hello World
This is a test

五个字符的内容:
Hello
剩余的内容:

World

io.StringIO 只能用于文本。如果你要操作二进制数据,要使用io.BytesIO 类来代替。比如:

1 import io
2 s = io.BytesIO()
3 s.write(b'binary data')
4 data = s.getvalue()
5 print("数据类型:", type(data))
6 print("data的值:", data)

以上代执行输出的结果为:

数据类型: <class 'bytes'>
data的值: b'binary data

注意:

  需要注意的是, StringIO 和BytesIO 实例并没有正确的整数类型的文件描述符。因此,它们不能在那些需要使用真实的系统级文件如文件,管道或者是套接字的程序中使用

读写压缩文件

问题:

  你想读写一个gzip 或bz2 格式的压缩文件

解决方案:

  gzip 和bz2 模块可以很容易的处理这些文件。两个模块都为open() 函数提供了另外的实现来解决这个问题。比如,为了以文本形式读取压缩文件,可以这样做:

 1 import gzip
 2 import bz2
 3 import os
 4 
 5 #打开/tmp/bashrc的文件并获取内容
 6 with open('/etc/bashrc', 'rb') as f:
 7     content = f.read()
 8 
 9 #使用gzip打开文件,xb如果文件存在就报错,不存在创建,把读取的内容写入到文件
10 try:
11     f = gzip.open('/tmp/bashrc.gz', 'xb')
12 except Exception as e:
13     print('文件已存在~')
14 else:
15     f.write(content)
16 finally:
17     f.close()
18 
19 #获取文件类型
20 result = os.popen('file /tmp/bashrc.gz').read()
21 print(result)
22 
23 #打开gzip文件并读取内容
24 with gzip.open('/tmp/bashrc.gz') as f:
25     content = f.read()
26 print('bashrc.gz中的内容为:')
27 print(content.decode('utf-8'))
28 
29 #bz2的操作和上面一样..
30 # with bz2.open('samefile.bz2', 'rb') as f:
31 #     #f.write(content)
32 #     #f.read()
33 #     pass

以上代执行输出的结果为:

文件已存在~
/tmp/bashrc.gz: gzip compressed data, was "bashrc", last modified: Sat Aug  5 00:57:56 2017, max compression

bashrc.gz中的内容为:
# System-wide .bashrc file for interactive bash(1) shells.
if [ -z "$PS1" ]; then
   return
fi

PS1='h:W u$ '
# Make bash check its window size after a process completes
shopt -s checkwinsize

[ -r "/etc/bashrc_$TERM_PROGRAM" ] && . "/etc/bashrc_$TERM_PROGRAM"
alias cls='clear'
alias ll='ls -l'

读取二进制数据到可变缓冲区中

问题:

  你想直接读取二进制数据到一个可变缓冲区中,而不需要做任何的中间复制操作。或者你想原地修改数据并将它写回到一个文件中去

解决方案:

  为了读取数据到一个可变数组中,使用文件对象的readinto() 方法。比如:

 1 import os.path
 2 
 3 def read_into_buffer(filename):
 4     buf = bytearray(os.path.getsize(filename))
 5     with open(filename, 'rb') as f:
 6         f.readinto(buf)
 7     return buf
 8 
 9 #创建文件并写入内容
10 with open('sample.bin', 'wb') as f:
11     f.write(b'Hello World')
12 
13 #获取buf的内容
14 buf = read_into_buffer('sample.bin')
15 
16 #修改缓存文件中五个长度的值
17 print("未修改文件中的前五个值:", buf[:5])
18 buf[:5] = b'hello'
19 print('修改bu文件以后的值:',buf)
20 
21 #再次打开文件并把修改的数据放入到里面
22 with open('sample.bin', 'wb') as f:
23     f.write(buf)

以上代执行输出的结果为:

未修改文件中的前五个值: bytearray(b'Hello')
修改bu文件以后的值: bytearray(b'hello World')

内存映射的二进制文件

问题:

  你想内存映射一个二进制文件到一个可变字节数组中,目的可能是为了随机访问它的内容或者是原地做些修改

解决方案:

  使用mmap 模块来内存映射文件。下面是一个工具函数,向你演示了如何打开一个文件并以一种便捷方式内存映射这个文件

 1 import os
 2 import mmap
 3 
 4 #使用mmap模块内存映射文件
 5 def memory_map(filename, access=mmap.ACCESS_WRITE):
 6     size = os.path.getsize(filename)
 7     fd = os.open(filename, os.O_RDWR)
 8     return mmap.mmap(fd, size , access=access)
 9 
10 
11 #以创建并且内容不为空的文件
12 size = 1000000
13 with open('data', 'wb') as f:
14     f.seek(size-1)
15     f.write(b'x00')
16 
17 #memory_map()函数内存映射
18 print('内存映射'.center(30, '*'))
19 m = memory_map('data')
20 print(len(m))
21 print(m[:10])
22 #重新赋值
23 m[:11] = b'hello world'
24 m.close()
25 
26 #获取内存映射的内容
27 print('获取内存映射的内容:'.center(30, '-'))
28 with open('data', 'rb') as f:
29     print(f.read(11))

以上代执行输出的结果为:

*************内存映射*************
1000000
b'x00x00x00x00x00x00x00x00x00x00'
----------获取内存映射的内容:----------
b'hello world'

为了随机访问文件的内容,使用mmap 将文件映射到内存中是一个高效和优雅的方法。例如,你无需打开一个文件并执行大量的seek() , read() , write() 调用,只需要简单的映射文件并使用切片操作访问数据即可。

文件路径名的操作

问题:

  你需要使用路径名来获取文件名,目录名,绝对路径等等

解决方案:

  使用os.path 模块中的函数来操作路径名。下面是一个交互式例子来演示一些关键的特性:

 1 import os
 2 path = '/etc/passwd/passwd.bak'
 3 
 4 #获取文件名
 5 basename = os.path.basename(path)
 6 print('file name:', basename)
 7 
 8 #获取目录路径
 9 dirname = os.path.dirname(path)
10 print("dirname:", dirname)
11 
12 #做多个目录拼接在拼接上文件
13 path_join = os.path.join('/tmp/a/b/c', 'd',os.path.basename(path))
14 print('path join:', path_join)
15 
16 #获取当前用户的家目录信息
17 path = '~/Data/data.csv'
18 print("user:", os.path.expanduser(path))
19 
20 
21 #获取后缀名
22 split_path = os.path.splitext(path)
23 print("splitext:", split_path)

以上代执行输出的结果为:

file name: passwd.bak
dirname: /etc/passwd
path join: /tmp/a/b/c/d/passwd.bak
user: /Users/demon/Data/data.csv
split: ('~/Data/data', '.csv')

测试文件是否存在

问题:

  你想测试一个文件或目录是否存在

解决方案:

  使用os.path 模块来测试一个文件或目录是否存在。比如:

 1 import os
 2 
 3 #判断/etc/passwd是否存在
 4 print('/etc/passwd exists:', os.path.exists('/etc/passwd'))
 5 
 6 #判断/tmp/spam是否存在
 7 print('/tmp/spam exists:', os.path.exists('/tmp/spam'))
 8 
 9 #判断/etc/passwd是否为一个文件
10 print('/etc/passwd is file:', os.path.isfile('/etc/passwd'))
11 
12 #判断/tmp是否为一个目录
13 print('/tmp is directory:', os.path.isdir('/tmp'))
14 
15 #判断/usr/local/bin/python3是否为一个链接文件
16 print('/usr/local/bin/python3 is link:', os.path.islink('/usr/local/bin/python3'))
17 
18 #获取软连接的绝对路径
19 print('/usr/local/bin/python3 real directory:', os.path.realpath('/usr/local/bin/python3'))
20 
21 #获取文件的大小
22 print('file size:', os.path.getsize('/etc/passwd'))
23 
24 #文件的修改时间
25 print('file mtime:', os.path.getmtime('/etc/passwd'))
26 
27 #文件的改变时间
28 import time
29 print('file ctime:', time.ctime(os.path.getctime('/etc/passwd')))

以上代执行输出的结果为:

/etc/passwd exists: True
/tmp/spam exists: False
/etc/passwd is file: True
/tmp is directory: True
/usr/local/bin/python3 is link: True
/usr/local/bin/python3 real directory: /Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6
file size: 5925
file mtime: 1456440624.0
file ctime: Sat Aug  6 07:46:53 2016

获取文件夹中的文件列表

问题:

  你想获取文件系统中某个目录下的所有文件列表

解决方法:  

  使用os.listdir() 函数来获取某个目录中的文件列表:

 1 import os
 2 
 3 #获取当前目录下的文件
 4 # names = os.listdir('somedir')
 5 
 6 #获取所有的文件
 7 path = '/tmp'
 8 #列表推到式的写法
 9 names = [name for name in os.listdir(path) if os.path.isfile(os.path.join(path,name))]
10 print('所有文件名的列表:', names)
11 
12 #另外一种通过高阶函数filter
13 filter_names = list(filter(lambda name:os.path.isfile(os.path.join(path,name)),os.listdir(path)))
14 print('filter的所有文件名列表:', filter_names)
15 
16 
17 #获取所有的目录
18 dirnames = list(filter(lambda name:os.path.isdir(os.path.join(path,name)),os.listdir(path)))
19 print('所有目录的名称 :', dirnames)
20 
21 #过滤内容,查找当前目录下的所有以.log结尾或者.gz结尾的文件
22 files = [name for name in names if name.endswith(('log','gz'))]
23 print("查找目录下以log或者gz结尾的文件", files)
24 
25 #另外一种写法
26 from fnmatch import fnmatch
27 fnmatch_files = [name for name in names if fnmatch(name, '*.log')]
28 print('另外一种查找以log结尾的文件:', fnmatch_files)

以上代执行输出的结果为:

所有文件名的列表: ['.adobeLockFile', '.keystone_install_lock', 'adobegc.log', 'AlTest1.err', 'AlTest1.out', 'bashrc.gz', 'com.adobe.acrobat.rna.AcroCefBrowserLock', 'escalatelantern.ico', 'swtag.log']
filter的所有文件名列表: ['.adobeLockFile', '.keystone_install_lock', 'adobegc.log', 'AlTest1.err', 'AlTest1.out', 'bashrc.gz', 'com.adobe.acrobat.rna.AcroCefBrowserLock', 'escalatelantern.ico', 'swtag.log']
所有目录的名称 : ['com.apple.launchd.18kY10uuPh', 'com.apple.launchd.dVLT4hIllt']
查找目录下以log或者gz结尾的文件 ['adobegc.log', 'bashrc.gz', 'swtag.log']
另外一种查找以log结尾的文件: ['adobegc.log', 'swtag.log']

打印不合法的文件名

问题:

  你的程序获取了一个目录中的文件名列表,但是当它试着去打印文件名的时候程序崩溃,出现了UnicodeEncodeError 异常和一条奇怪的消息—— surrogates not allowed

解决方案:

  当打印未知的文件名时,使用下面的方法可以避免这样的错误:

 1 import sys
 2 
 3 names = ['spam.py', 'budce4d.txt', 'foo.txt']
 4 
 5 def bad_filename(filename):
 6     return repr(filename)[1:-1]
 7 
 8 print('第一个版本的错误处理:'.center(40, '*'))
 9 for filename in names:
10     try:
11         print(filename)
12     except UnicodeEncodeError:
13         print(bad_filename(filename))
14 
15 
16 #另外一个版本的解决办法
17 def bad_filename(filename):
18     #忽略编码的错误,sys.getfilesystemencoding是获取当前系统的编码
19     temp = filename.encode(sys.getfilesystemencoding(), errors='surrogateescape')
20     return temp.decode('latin-1')
21 
22 print('第二个版本的错误处理:'.center(40, '-'))
23 for filename in names:
24     try:
25         print(filename)
26     except UnicodeEncodeError:
27         print(bad_filename(filename))

以上代执行输出的结果为:

**************第一个版本的错误处理:***************
spam.py
budce4d.txt
foo.txt
--------------第二个版本的错误处理:---------------
spam.py
bäd.txt
foo.txt

序列化Python 对象

问题:

  你需要将一个Python 对象序列化为一个字节流,以便将它保存到一个文件、存储到数据库或者通过网络传输它

解决方案: 

  对于序列化最普遍的做法就是使用pickle 模块。为了将一个对象保存到一个文件中,可以这样做:

 1 import pickle
 2 
 3 '''
 4 data = 'same python object....'
 5 #序列化对象到文件存储中
 6 f = open('somefile', 'wb')
 7 pickle.dump(data, f)
 8 '''
 9 
10 #实例
11 #利用pickle分别把列表 字符串 字典类型的数据写入到/tmp/test文件中
12 f = open('/tmp/test', 'wb')
13 pickle.dump([1, 2, 3, 4], f)
14 pickle.dump('Hello World', f)
15 pickle.dump({'name':'demon'}, f)
16 print('写入完毕')
17 f.close()
18 
19 #读取文件中的内容
20 f = open('/tmp/test', 'rb')
21 print(pickle.load(f))
22 print(pickle.load(f))
23 print(pickle.load(f))

以上代执行输出的结果为:

写入完毕
[1, 2, 3, 4]
Hello World
{'name': 'demon'}
原文地址:https://www.cnblogs.com/demon89/p/7288349.html