python常⽤⽂件读写及with的⽤法
⼀ CSV⽂件
csv是逗号分隔值⽂件格式,⼀般⽤WORDPAD或记事本(NOTE),EXCEL打开。csv(逗号分隔值)是⼀种⽤来存储数据的纯⽂本⽂件,通常都是⽤于存放电⼦表格或数据的⼀种⽂件格式。这种格式的数据通常应⽤在数据处理⽅⾯,⽐如我们爬⾍的数据量较⼩,不⽤插⼊数据库,或者只是临时测试,那么可以把数据存放在.csv⽂件中,很是⽅便。下⾯我们结合pythonCSV模块的源码讲解具体怎么⽤
要⽤到操作csv⽂件的库,要导⼊csv模块,我们进⼊到csv源码之中来看看。
“""
csv.py - read/write/investigate CSV files
"""
import re
from _csv import Error, __version__, writer, reader, register_dialect, \
unregister_dialect, get_dialect, list_dialects, \
field_size_limit, \
QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE, \
__doc__
from _csv import Dialect as _Dialect
from collections import OrderedDict
from io import StringIO
⾸先来看,csv的引⼊。可以看出它导⼊了_csv模块,那么也就是说,此模块的实现是有两层,最底层的⽅法实现是在_CSV模块
中,CSV模块只是对于_csv模块的⼀个再次封装和功能强化。
来看具体⽤法,⾸先是读csv操作,csv模块有提供了两种⽅式来读,⼀种是ader,另⼀种是Dictreader,先看reader:
import csv
with open('z.csv', 'r+', newline='',encoding='utf-8') as csv_file:
reader = ader(csv_file)
for row in reader:
print(str(row))
运⾏结果:
['name', 'city', 'price']
['清华珠三⾓研究院', '⼴州-黄埔区', '1-1.5万/⽉']
['上海桥之队教育科技有限公司', '上海-杨浦区', '6-8千/⽉']
['⽂思海辉技术有限公司', '成都', '1-1.5万/⽉']
['上海皓维电⼦股份有限公司', '上海-嘉定区', '1-2万/⽉']
python怎么读入excel
with的⽤法稍后讨论,上⾯运⾏结果,那么我们深⼊到reader这个⽅法本⾝去看看究竟,python源代码如下:
def reader(iterable, dialect='excel', *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__
"""
csv_reader = reader(iterable [, dialect='excel']
[optional keyword args])
for row in csv_reader:
process(row)
The "iterable" argument can be any object that returns a line
of input for each iteration, such as a file object or a list. The
optional "dialect" parameter is discussed below. The function
also accepts optional keyword arguments which override settings
provided by the dialect.
The returned object is an iterator. Each iteration returns a row
of the CSV file (which can span multiple input lines).
"""
pass
这是python官⽅对于此⽅法的解释,⽤法全部都说了。简单明了,所以养成看官⽅⽂档的习惯很重要,reader函数,接收⼀个可迭代的对象,可以是⼀个列表,也可以是⼀个⽂件句柄,返回的便是每⼀⾏的数据。我试过了,如果你输⼊的是⼀个列表或者字符串,他会把其中的元素都进⾏迭代出来。iterable⽅法是衡量⼀个对象是否是可迭代对象,但是可迭代对象都是迭代器吗?No,要想⼀个对象是可迭代对象,⾸先要实现其next⽅法,这样的对象才会被称为可迭代对象。
再来看下⼀种⽅式,DictReader⽅法,⾸先看此⽅法的实际运⽤:
import csv
for d in csv.DictReader(open('z.csv', 'r+', newline='',encoding='utf-8')):
print (d)
运⾏结果:
OrderedDict([('name', '清华珠三⾓研究院'), ('city', '⼴州-黄埔区'), ('price', '1-1.5万/⽉')])
OrderedDict([('name', '上海桥之队教育科技有限公司'), ('city', '上海-杨浦区'), ('price', '6-8千/⽉')])
OrderedDict([('name', '⽂思海辉技术有限公司'), ('city', '成都'), ('price', '1-1.5万/⽉')])
OrderedDict([('name', '上海皓维电⼦股份有限公司'), ('city', '上海-嘉定区'), ('price', '1-2万/⽉')])
OrderedDict为python中的有序字典,他会记录字段的顺序,按顺序输出。
再来分析python关于此类的源码:
class DictReader:
def __init__(self, f, fieldnames=None, restkey=None, restval=None,
dialect="excel", *args, **kwds):
self._fieldnames = fieldnames # list of keys for the dict
self.dialect = dialect
self.line_num = 0
def __iter__(self):
return self
@property
def fieldnames(self):
if self._fieldnames is None:
try:
self._fieldnames = ader)
except StopIteration:
pass
self.line_num = ader.line_num
return self._fieldnames
@fieldnames.setter
def fieldnames(self, value):
self._fieldnames = value
def __next__(self):
if self.line_num == 0:
# Used only for its side effect.
self.fieldnames
row = ader)
self.line_num = ader.line_num
# unlike the basic reader, we prefer not to return blanks,
# because we will typically wind up with a dict full of None
# values
while row == []:
row = ader)
d = OrderedDict(zip(self.fieldnames, row))
lf = len(self.fieldnames)
lr = len(row)
if lf < lr:
stkey] = row[lf:]
elif lf > lr:
for key in self.fieldnames[lr:]:
d[key] = stval
return d
这个类⾥⾯⽤到了python的⾼级⽤法,装饰器的嵌套应⽤,此部分内容移步到我的装饰器讲解篇,这样会更加的清晰,那么在这⾥要分析的是,这个类⾥⾯的next⽅法,实际上调⽤了_csv模块⾥的reader,把其中的每⾏的元素与字段,再次封装成⼀个有序字典来进⾏返回,这⾥可以看到我刚才说的,这两种读取⽅法都返回了可迭代对象,那么可迭代对象必然要实现next⽅法。
说完读⽅法,再来讨论⼀下CSV⽂件的写操作。那么在平常的应⽤之中,我们经常把爬取到的内容写⼊CSV,我们知道,从爬⾍的⼤部分实现⽅法来说,都是⽣成了⼀个字典,那么我们写⼊CSV时,我们想简单⼀些,把爬取出来的字典直接写⼊,这样很⽅便,那么python 显然已经为我们实现了这个⽅法,这就是DictWriter。先看⽤法:
file = open('zane.csv', 'w', newline='', encoding='utf-8')
headers = ['price', 'district', 'name', 'layout', "space", 'floor', 'RentType','loc']
writers = csv.DictWriter(file, headers)
writers.writeheader()
for item in a.Prase_info(url):
writers.writerow(item)
这段代码直接是⽤不了的,因为是我爬⾍程序删减过后的,知道⽤法,⾃⼰写⼀个很简单,看看运⾏结果:
price,district,name,layout,space,floor,RentType,loc
5000,⾹洲区,华发新城⼆期,4室2厅,164平⽶,⾼层/11层,整租,"113.526232893,22.2376243653"
5800,⾹洲区,华发新城⼆期,4室2厅,165平⽶,中层/11层,整租,"113.526232893,22.2376243653"
3000,⾹洲区,嘉园,4室2厅,95.11平⽶,⾼层/6层,整租,"117.179603933,39.1072266636"
2800,⾹洲区,⼼海州 (⼼悦湾),2室2厅,60平⽶,⾼层/29层,整租,"113.530491251,22.2476647077"
5000,横琴新区,华融琴海湾,2室2厅,87平⽶,⾼层/19层,整租,"113.549125605,22.1416825418"
4300,⾹洲区,华发新城五期,2室2厅,90平⽶,中层/30层,整租,"113.516777146,22.2377163421"
上述结果是爬⾍结果的⼀部分,可以看出已经成功写⼊,下⾯结合python源代码进⾏分析:
class DictWriter:
def __init__(self, f, fieldnames, restval="", extrasaction="raise",
dialect="excel", *args, **kwds):
self.fieldnames = fieldnames # list of keys for the dict
if extrasaction.lower() not in ("raise", "ignore"):
raise ValueError("extrasaction (%s) must be 'raise' or 'ignore'"
% extrasaction)
self.writer = writer(f, dialect, *args, **kwds)
def writeheader(self):
header = dict(zip(self.fieldnames, self.fieldnames))
self.writerow(header)
def _dict_to_list(self, rowdict):
asaction == "raise":
wrong_fields = rowdict.keys() - self.fieldnames
if wrong_fields:
raise ValueError("dict contains fields not in fieldnames: "
+ ", ".join([repr(x) for x in wrong_fields]))
return ((key, stval) for key in self.fieldnames)
def writerow(self, rowdict):
return self.writer.writerow(self._dict_to_list(rowdict))
def writerows(self, rowdicts):
return self.writer.writerows(map(self._dict_to_list, rowdicts))
# Guard Sniffer's type checking against builds that exclude complex()
try:
complex
except NameError:
complex = float
从我们⾸先执⾏此句writers = csv.DictWriter(file, headers)时,可以看出在DictWriter类中,我们的headers也就是我们要写⼊的字段名,被传⼊到了fieldnames变量中,可以看此变量的注释,他说这是字典键的列表。结合⽤法,我们最后传⼊到这⾥的字典不就是以我们每个字段名为键的字典吗。再看,当我们执⾏writers.writeheader()时,代码⾥⾸先⽤zip函数,把列表转换成了元组,把元组在转换为字典,写⼊到了⾸⾏之中。接下来的⽅法,_dict_to_list就是把我们最后传⼊的字典转换为列表,根据键名去写值。这⾥还看到,如果我们传⼊的字典的键与之前写⼊的对不上,会抛出异常。最后我们只需要在我们需要迭代写⼊的地⽅,调⽤writerow⽅法,可以实现把字典写⼊我们的CSV⽂件之中。
⼆普通⽂本⽂件及with
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
程序⽰例:
f = open(yourfilepath, 'r')
ss = f.read() # 读进⽂件的全部内容返回⼀个字符串
ss = f.read(1024) # 读取指定字节的内容返回⼀个字符串
line = f.readline() # 读取⽂件的⼀⾏返回字符串(包含换⾏符)
line = line.strip("\n") # 处理的时候⼀般要去掉换⾏符(这⾥是\n)
lines = f.readlines() # 读取所有⾏返回⼀个列表list,每个元素(类型为字符串)为⽂件的⼀⾏
for line adlines():
pass
f.close() # ⽂件⽤完要记得关闭,可以⽤with关键字,不⽤⼿动关闭,程序会⾃动关闭
# 以下均⽤with来读写⽂件
with open('yourfilepath', 'w') as tmpf:
a = 100;
b = 97.5;
c = 'Good'
tmpf.write('number=%d score=%f result%s' % (a, b, c))
# 或者直接写⼊⽂件内容——字符串(或⼆进制数据)
ss = 'yourstring'
f.write(ss) # 直接写⼊
ss = 'yourstring'
f.writeline(ss) # 写⼊时会⾃动加⼊换⾏符
ss = ['a', 'b', 'c']
f.writelines(ss) # 参数为字符串序列
python中的open和操作系统的open返回值都是⽂件描述符,但是有的⼈会问,为什么⽤with。那么我们来分析⼀下,如果我们open⼀个⽂件之后,如果读写发⽣了异常,是不会调⽤close()的,那么这会造成⽂件描述符的资源浪费,久⽽久之,会造成系统的崩溃。那么我们怎么去解决呢,python⾥⾯为我们提供了⼀种解决⽅案,那就是with,也叫上下⽂管理器。那么with具体是怎么实现的呢。在迭代器的部分,我们知道所有可迭代对象都实现了iterable⽅法,迭代器⼜多实现了next⽅法,那么,在with中,我们必须实现两个⽅法才能进⾏上下⽂也就是with的作⽤,那就是__enter__⽅法和__exit__⽅法。看下⾯实例:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论