Python中的数据读入、写出以及交换

b本章会涉及不同类型的数据存储,它们基于不同的目的进行优化:普通文件、结构化文件和数据库。普通文件输入/输出数据持久化最简单的类型是普通文件,有时也叫平面文件(flat file)。它仅仅是在一个文件名下的字节流,把数据从一个文件读入内存,然后从内存写入文件。打开文件# fileobj是open()返回的文件对象# filename是该文件的字符串名# mode是指明文件类型和操作的字符串fi
摘要由CSDN通过智能技术生成

本章会涉及不同类型的数据存储,它们基于不同的目的进行优化:普通文件结构化文件数据库

普通文件输入/输出

数据持久化最简单的类型是普通文件,有时也叫平面文件(flat file)。它仅仅是在一个文件名下的字节流,把数据从一个文件读入内存,然后从内存写入文件。

打开文件

# fileobj是open()返回的文件对象
# filename是该文件的字符串名
# mode是指明文件类型和操作的字符串
fileobj = open(filename, mode)

mode的第一个字母表明对其的操作

  • r表示读模式。
  • w表示写模式。如果文件不存在则新创建,如果存在则重写新内容。
  • x表示在文件不存在的情况下新创建并写文件。
  • a表示如果文件存在,在文件末尾追加写内容。

mode的第二个字母是文本类型

  • t(或者省略)代表文本类型。
  • b代表二进制文件。

写文本文件

使用write()

sa = 'Never\nGive\nUp'
sb = 'Try\nMy\nBest'

fout = open('record', 'wt')
fout.write(sa)
fout.write(sb)
fout.close()

结果

# record1
# 注意Up与Try首尾相接
Never
Give
UpTry
My
Best

使用print()

sa = 'Never\nGive\nUp'
sb = 'Try\nMy\nBest'

fout = open('record', 'wt')
print(sa, file = fout)
print(sb, file = fout)
fout.close()

结果

# record2
# 注意Up与Try首尾有换行
Never
Give
Up
Try
My
Best

print()默认会在每个参数后添加空格,在每行结束处添加换行。这两个特性可以由sepend两个参数设置。

  • sep分隔符:默认是一个空格’ ‘
  • end结束字符:默认是一个换行符’\n’

因此,下面的print等价于write

print(sa, file = fout, sep='', end='')
print(sb, file = fout, sep='', end='')

注意

  1. write函数的参数一定要是字符串,writelines函数的参数一定要是字符串或字符串列表,print函数的参数是任意可以被str函数转化的类型。
  2. writelines函数写出列表时,不会给列表中每个字符串元素自动添加换行符。如[‘ab’, ‘cd’],则只会输出abcd,不会输出
    ab
    cd

写出列表[1, 2, ‘ab’, ‘efg’]

# 需要结果
1
2
ab
efg

显然,直接用write、writelines以及print都是不可行的。

方法1:write
lines = [1, 2, 'ab', 'efg']
with open('filename.txt', 'w') as f:
    # [str(line) for line in lines]生成字符串列表
    # '\n'.join生成一个中间由'\n'连接的字符串
    f.write('\n'.join([str(line) for line in lines]))
方法2:writelines
lines = [1, 2, 'ab', 'efg']
with open('filename.txt', 'w') as f:
    # [str(line)+'\n' for line in lines]生成字符串列表,每个字符串后面有换行符'\n'
    f.writelines([str(line)+'\n' for line in lines])

将数据分块写入

fout = open('record2', 'wt')
sentence = sa + sb
size = len(sentence)
offset = 0
chunk = 100
while True:
    if offset > size:
        break
    fout.write(sentence[offset:offset+chunk])
    offset += chunk

使用模式x避免重写文件

try:
    fout = open('record2', 'xt')
    fout.writ(sentence)
except FileExistsError:
    print('record already exists!')

使用read()、readline()或者readlines()读文本文件

使用read()

利用read()读入文件时,1GB的文件会用到同样大小的内存

# record2
Never
Give
Up
Try
My
Best
# read()会把整个文件以字符串的形式读入
# '\n'也算一个字符
fin = open('record2', 'rt')
sentence = fin.read()
fin.close()
print(type(sentence))

结果:

<class 'str'>

同样也可以设置最大的读入字符数限制read()函数一次返回的大小。下面一次读入100个字符,然后把每一块拼接成原来的字符串sentence:

sentence = ''
fin = open('record2', 'rt')
chunk = 100
while True:
    fragment = fin.read(chunk)
    if not fragment:
        break
    sentence += fragment
fin.close()

使用readline()

readline()每次读入文件的一行。对于一个文本文件,即使空行也有1字符长度(换行字符’\n’),自然就会返回True。当文件读取结束后,readline()(类似read())同样会返回空字符串。

# record1
Never
Give
UpTry
My
Best
fin = open('record1', 'rt')
sentence = ''
while True:
    line = fin.readline()
    print(len(line))
    if not line :
        break
    sentence += line
fin.close()
print(sentence)

结果:

# 记住换行符也是一个普通的字符
6   # '\n'也在里面
5
6
3
4   # 没有'\n'
0
Never
Give
UpTry
My
Best
更好的用法
sentence = ''
fin = open('record', 'rt')
for line in fin:
    sentence += line
fin.close()

使用readlines()

函数readlines()调用时读入所有行,并返回单行字符串的列表

fin = open('record1', 'rt')
lines = fin.readlines()
fin.close()
print lines

结果:

['Never\n', 'Give\n', 'UpTry\n', 'My\n', 'Best']

使用write()写二进制文件

bdata = bytes(range(0, 256))
print(len(bdata))
fout = open('bfile', 'wb')
blen = fout.write(bdata)
# blen为write()写入的字节数
print(blen)
fout.close()

分块写入

fout = open('bfile', 'wb')
size = len(bdata)
offset = 0
chunk = 100
while True:
    if offset > size:
        break
    fout.write(bdata[offset:offset+chunk])
    offset += chunk
fout.close()

使用read()读二进制文件

fin = open('bfile', 'rb')
bdata = find.read()
print(len(bdata))
fin.close()

使用with自动关闭文件

如果你忘记关闭已经打开的一个文件,在该文件对象不再被引用之后Python会关掉此文件

这也就意味着在一个函数中打开文件,没有及时关闭它,但是在函数结束时会被关掉。

Python的上下文管理器(context manage)(什么鬼?)会清理一些资料,例如打开的文件。它的形式为with expression as variable:

# fout = open('record', 'wt')
with open('record', 'wt') as fout:
    fout.write(poem)

完成上下文管理器的代码后,文件会被自动关闭。

使用seek()改变位置(基于字节)

无论是读或者写文件,Python都会跟踪文件中的文件。

函数tell()返回距离文件开始处的字节偏移量。

函数seek()允许跳转到文件其他字节偏移量的位置。这意味着可以不用从头读取文件的每一个字节,直接跳到最后位置并只读一个字节也是可行的。

这些函数对于二进制文件都是极其重要的。当文件是ASCII编码(么个字符一个字节)时,也可以使用它们,但是计算偏移量回事一件麻烦事。其实,这都取决于文本的编码格式,UTF-8每个字符的字节数都不尽相同。

>>> b'abc'[0]
97
>>> fin = open('bfile', 'rb')
>>> fin.tell()
0
>>> # 初始字节偏移量为0,最后字节偏移量为255
>>> # 使用seek()跳转到文件结束前最后一个字节
>>> fin.seek(255)
255 #255是指当前的偏移量
>>> # 读取最后一个字节
>>> bdata = fin.read()
>>> len(bdata)
1
>>> bdata[0]
255

seek(offset, origin)

  • 如果origin等于0(默认为0),从开头偏移offset个字节;
  • 如果origin等于1,从当前位置处偏移offset个字节;
  • 如果origin等于2,距离最后结尾处(指的是所有数据后的一个字节的位置)偏移offset个字节;

上述值也在标准os模块中被定义:

>>> import os
>>> os.SEEK_SET
0
>>> os.SEEK_CUR
1
>>> os.SEEK_END
2
读取bfile最后一个字节的方法

方法一:

fin.seek(-1, 2)
bdata = fin.read()

方法二:

fin.seek(255, 0)
bdata = fin.read()

方法三:

fin.seek(254, 0)
fin.seek(1, 1)
bdata = fin.read()

结构化的文本文件输入/输出

结构化的文本文件

对于简单的文本文件,唯一的结构层次是间隔的行

结构化的文本有很多格式,区别它们的方法如下所示:

  • 分隔符,比如tab(‘\t’)、逗号(‘,’)或者竖线(‘|’)。逗号分隔值(CSV)就是这样的例子。
  • ‘<’和’>’标签,例如XML和HTML
  • 标点符号,例如JavaScript Object Notation ( JSON2 J S O N 2 )
  • 缩进,例如YAML
  • 混合的,例如各种配置文件

CSV

带分隔符的文件一般用作数据交换格式或者数据库

你可以人工读入CSV文件,每一次读取一行,在逗号分隔符处将每行分开,并添加结果到某些数据结构中。

但是,最好使用标准的csv模块,因为这样切分会得到更加复杂的信息。

  • 除了逗号,还有其他可代替的分隔符: ‘|’和’\t’很常见。
  • 有些数据会有转义字符序列,如果分隔符出现在一块区域内,则整块都要加上引号或者在它之前加上转义字符。
  • 文件可能有不同的换行符,Unix系统的文件使用’\n’,Microsoft使用’\r\n’,Apple之前使用’\r’而现在使用’\n’
  • 在第一行可以加上列名

写出CSV

import csv
data = [\
['Doctor', 1, 1.01, True, 'a,a,,', [1], [1,2], [1, 'a'], ['a']],\
['Teacher', 'a', 2.02, False, 'b,b,,']]
with open('data', 'wt') as fout: # 一个上下文管理器
     csvout = csv.writer(fout)
     csvout.writerows(data)
# data
Doctor,1,1.01,True,"a,a,,",[1],"[1, 2]","[1, 'a']",[
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值