Python之文件读写操作CSV/Excel/JSON/XML/TXT

?前言

CSVComma-Separated Values,逗号分隔值,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔;每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。CSV文件通常以 .csv 作为文件扩展名。

XLS就是Microsoft Excel工作表,是一种非常常用的电子表格格式。xls文件可以使用Microsoft Excel打开,另外微软为那些没有安装Excel的用户开发了专门的查看器Excel Viewer。使用Microsoft Excel可以将XLS格式的表格转换为多种格式:XML表格、XML数据、网页、使用制表符分割的文本文件(.txt)、使用逗号分隔的文本文件(.csv)等。

XLSXMicrosoft Office EXCEL 2007/.../2019文档及以上的扩展名。其基于Office Open XML标准的压缩文件格式取代以前专有的默认文件格式,在传统文件名扩展名后面添加字母"x"(即.docx取代.doc.xlsx取代.xls.pptx取代.ppt)。任何能够打开.xlsx文件的文字处理软件都可以将该文档转换为.xls文件,.xlsx文件比.xls文件所占用空间更小。

xlsx格式文档文件无法被EXCEL2003及以下版本EXCEL软件直接打开编辑,安装OFFICE2007兼容包后可以打开查看。手动将XLSX文件后缀修改为XLS无法改变文档文件的本质属性,是不能被EXCEL2003等低版本EXCEL直接打开编辑的。用户可在EXCEL软件成功打开EXCEL2007专有XLSX格式文档的前提下,采用另存为方式将其转换为EXCEL97—2003格式文档的XLS文件这样可与旧的版本兼容,但一些EXCEL2007文档专有的特性格式可能丢失。Excel xlsxlsx的详细区别如下:

  • 文件格式不同xls是一个特有的二进制格式,其核心结构是复合文档类型的结构,而xlsx的核心结构是XML类型的结构,采用的是基于XML的压缩方式,使其占用的空间更小。xlsx中最后一个x的意义就在于此。
  • 版本不同xlsexcel2003及以前版本生成的文件格式,不管有没有宏程序的话都是xls文件,而xlsxexcel2007及以后版本生成的文件格式,从2007开始做了区分,XLSM文件和XLSX文件都是excel2007及其以后的文件,但前者是含有宏启用,Excel中默认情况下不自动启用宏,默认是XLSXVBA中,如果不想保存代码,可以保存为xlsx,即可自动删除其中VBA代码,反之则保存为XLSM文件。
  • 兼容性不同xlsx格式是向下兼容的,可兼容xls格式。07版的Office Excel,能打开编辑07版(后缀.xlsx)的Excel文件,也能打开编辑03版(后缀.xls)的Excel文件,都不会出现乱码或者卡死的情况。03版的Office Excel,就只能打开编辑03版(后缀.xls)的Excel文件;如果打开编辑07版(后缀.xlsx)的Excel文件,则可能出现乱码或者开始能操作到最后就卡死,以后一打开就卡死。
  • 默认保存方式上xls是03版Microsoft Office Excel 工作表的格式,用03版Office,新建Excel默认保存的Excel文件格式的后缀是.xlsxlsx是07版Microsoft Office Excel 工作表的格式,用07版Office,新建Excel默认保存的的Excel文件格式后缀是.xlsx
  • 容量不同xls只有65536行、256列;xlsx可以有1048576行、16384列

JSONJavaScript Object Notation, JS对象简谱)是一种轻量级的数据交换格式。它基于 ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得JSON成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。

XML (Extensible Markup Language, 可扩展标记语言) ,标准通用标记语言的子集,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML是标准通用标记语言可扩展性良好,内容与形式分离,遵循严格的语法要求,保值性良好等优点。

TXT文件是微软在操作系统上附带的一种文本格式,是最常见的一种文件格式,早在DOS时代应用就很多,主要存储文本信息,即为文字信息,现在的操作系统大多使用记事本等程序保存,大多数软件可以查看,如记事本,浏览器等等。

?Python之读写文件

??CSV

(1)CSV库读取

csv.reader:以列表的形式返回读取的数据;
csv.writer:以列表的形式写入数据;
csv.DictReader:以字典的形式返回读取的数据;
csv.DictWriter:以字典的形式写入数据。

import csv
with open(r"D:Desktopdata.csv") as file:
    reader = csv.reader(file)
    print(reader)
    print("*"*20)
    # 用next()函数读取文件时:如果只执行一次默认读取第一行。
    headers = next(reader)
    print(headers)
    print("*"*20)
    for row in reader:
        print(row)
        print(row[2])

# 输出结果
<_csv.reader object at 0x000001D6B95F1668>
********************
['name', 'gender', 'age', 'hobby']
********************
['小红', '女', '20', '跑步']
20
['小汤', '男', '22', '篮球']
22
['小李', '男', '24', '足球']
24

namedtuple(具名元组),因为元组的局限性:不能为元组内部的数据进行命名,所以往往我们并不知道一个元组所要表达的意义,在这里引入了collections.namedtuple 这个工厂函数,来构造一个带字段名的元组。具名元组的实例和普通元组消耗的内存一样多,因为字段名都被存在对应的类里面。

# 获取一行数据中的某一列数据
import csv
from collections import namedtuple
with open(r"D:Desktopdata.csv") as file:
    reader = csv.reader(file)
    print(reader)
    print("*"*20)
    headers = next(reader)
    # namedtuple(具名元组)返回一个具名元组子类 typename
    Row = namedtuple('Row', headers)
    print(headers)
    print("*"*20)
    for row in reader:
        # 列表或元组前面加星号作用是将列表解开成两个独立的参数;
        # 字典前面加两个星号,是将字典的值解开成独立的元素作为形参。
        row = Row(*row)
        # 获取一行数据中的某一列数据。
        print(row.name,row.age)

# 输出结果
<_csv.reader object at 0x000001D6B95F1128>
********************
['name', 'gender', 'age', 'hobby']
********************
小红 20
小汤 22
小李 24

简单使用csv.DictReader

可以深入了解该函数的参数:

  • csv.DictReader()fieldnames参数
  • csv.DictReader()restkey参数
  • csv.DictReader()restval参数
import csv
with open(r"D:Desktopdata.csv") as file:
    '''
    # 如果没有字段名,参数fieldnames
    reader = csv.DictReader(file,fieldnames = ['name','gender','age','hobby'])
    # next()方法用于移动指针
    head_row = next(reader)
    '''
    reader = csv.DictReader(file)
    print(reader)
    print("*"*20)
    for row in reader:
        # OrderedDict是一种长相类似于列表的数据类型,该列表中嵌套着元组;
        # 每个元组中的第一个元素为键,第二个元素为值(类似于字典)
        print(row)
        print(row["name"],row["hobby"])

# 输出结果
<csv.DictReader object at 0x000001D6B95F0388>
********************
OrderedDict([('name', '小红'), ('gender', '女'), ('age', '20'), ('hobby', '跑步')])
小红 跑步
OrderedDict([('name', '小汤'), ('gender', '男'), ('age', '22'), ('hobby', '篮球')])
小汤 篮球
OrderedDict([('name', '小李'), ('gender', '男'), ('age', '24'), ('hobby', '足球')])
小李 足球
(2)CSV库写入

csv.reader:以列表的形式返回读取的数据;
csv.writer:以列表的形式写入数据;
csv.DictReader:以字典的形式返回读取的数据;
csv.DictWriter:以字典的形式写入数据。

import csv
# 1. 创建文件对象(指定文件名,模式,编码方式),指定下次写入在这次的下一行
# 注意引入newline="",不然加入的数据会空一行
with open(r"D:Desktopdata.csv", "a+", encoding="gbk", newline="") as f:
    # 2. 基于文件对象构建 csv写入对象
    csv_writer = csv.writer(f)
    # 3. 构建列表头
    # name = ['name','gender','age','hobby']
    # csv_writer.writerow(name)
    # 4. 写入csv文件内容
    z = [["小ai", "男", 21, "篮球"],["小张", "男", 25, "篮球"]]
    csv_writer.writerows(z)
with open(r"D:Desktopdata.csv", "r+", encoding="gbk", newline="") as f:   
    reader = csv.reader(f)
    headers = next(reader)
    for row in reader:
        print(row)

# 输出结果
['小红', '女', '20', '跑步']
['小汤', '男', '22', '篮球']
['小李', '男', '24', '足球']
['小ai', '男', '21', '篮球']
['小张', '男', '25', '篮球']

如果csvfile是文件对象,则打开它时应使用newline=""。如果没有指定newline="",则嵌入引号中的换行符将无法正确解析,并且在写入时,使用
换行的平台会有多余的
写入。由于csv模块会执行自己的(通用)换行符处理,因此指定newline=""应该总是安全的。

open()完成后必须调用close()方法关闭文件,因为文件对象会占用操作系统资源,并且操作系统同一时间能打开的文件数量也是有限的。由于文件读写时有可能产生IOError,一旦出错,后面的f.close()就不会调用。with open()则可以避免这样的情况。

模式 描述
t 文本格式打开文件(默认)。一般用于文本文件,如:txt
b 二进制格式打开文件。一般用于非文本文件,如:图片。
r 只读方式打开文件(默认模式)。文件的指针将会放在文件的开头,如果文件不存在会报错
w 只写方式打开文件。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,则创建新文件。
a 追加方式打开文件,同样是只写,不允许进行读操作。如果文件已存在,文件指针将会放在文件的结尾,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
r+ 打开一个文件用于读写。如果文件存在,则打开文件,将文件指针定位在文件头,新写入的内容在原有内容的前面;如果文件不存在会报错。
w+ 打开一个文件用于读写。如果文件存在,则打开文件,清空原有内容,进入编辑模式;如果文件不存在,则创建一个新文件进行读写操作。
a+ 以追加模式打开一个文件用于读写。如果文件存在,则打开文件,将文件指针定位在文件尾,新写入的内容在原有内容的后面;如果文件不存在,则创建一个新文件用于读写。
rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。
wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。
rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。
wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。
ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。

csv库常见的问题

  • csv.DictWriter():该函数返回的结果遍历一次之后,再次遍历返回的结果是空列表。
  • csv.reader():返回的结果是结构体,需要for循环才能调用,不能像list那样直接选取特定单元格。
  • 通过列名来查找指定列的操作麻烦。
(3)pandas库读取

使用pandas读取csv文件的优势:

  • 方便,有专门支持读取csv文件的pd.read_csv()函数;
  • csv转换成二维列表形式;
  • 支持通过列名查找特定列;
  • 相比csv库,事半功倍。
pandas.read_csv(filepath_or_buffer, sep=, delimiter=None, header=‘infer’, names=None, index_col=None, usecols=None, squeeze=False, prefix=None, mangle_dupe_cols=True, dtype=None, engine=None, converters=None, true_values=None, false_values=None, skipinitialspace=False, skiprows=None, skipfooter=0, nrows=None, na_values=None, keep_default_na=True, na_filter=True, verbose=False, skip_blank_lines=True, parse_dates=False, infer_datetime_format=False, keep_date_col=False, date_parser=None, dayfirst=False, cache_dates=True, iterator=False, chunksize=None, compression=‘infer’, thousands=None, decimal=’.’, lineterminator=None, quotechar='"', quoting=0, doublequote=True, escapechar=None, comment=None, encoding=None, dialect=None, error_bad_lines=True, warn_bad_lines=True, delim_whitespace=False, low_memory=True, memory_map=False, float_precision=None, storage_options=None)

# 常用参数详解
(1)filepath_or_buffer:必须有的参数,其它都是按需求选用的。文件所在处的路径。
(2)sep:指定分隔符,默认为逗号','。
(3)delimiter:str/default/None,定界符,备选分隔符(如果指定该参数,则sep参数失效)
(4)header:int or list of ints, default ‘infer’,指定哪一行作为表头。默认设置为0(即第一行作为表头),如果没有表头的话,要修改参数,设置header=None。
(5)names:指定列的名称,用列表表示。一般我们没有表头,即header=None时,这个用来添加列名就很有用啦。
(6)index_col:指定哪一列数据作为行索引,可以是一列,也可以多列。多列的话,会看到一个分层索引。
(7)squeeze:布尔值,默认为False。如果解析的数据仅包含一列,则返回一个Series。
(8)prefix:给列名添加前缀。如prefix="x",会出来"x1"、"x2"、"x3"。
(9)nrows:int, default None。需要读取的行数(从文件头开始算起)。
(10)encoding:编码方式。
(11)skiprows:list-like or integer, default None。在文件开始处要跳过的行号(索引为0)或要跳过的行数(整数)。
......
import pandas as pd
df = pd.read_csv(r"D:Desktopdata.csv",encoding="gbk")
print(df) 
print("*"*20)
print(df.index.values)
print(df.columns.values)
print(df.values)
# 通过位置选取
print("="*20)
print(df.iloc[:,0:3].values)
print(type(df.iloc[:,0:3].values))
print(df.iloc[:,0:3].values.tolist())
print(type(df.iloc[:,0:3].values.tolist()))
# 通过标签选取
print("-"*20)
print(df.loc[[0,3],["name","hobby"]].values)

# 输出结果
  name gender  age hobby
0   小红      女   20    跑步
1   小汤      男   22    篮球
2   小李      男   24    足球
3  小ai      男   21    篮球
4   小张      男   25    篮球
********************
[0 1 2 3 4]
['name' 'gender' 'age' 'hobby']
[['小红' '女' 20 '跑步']
 ['小汤' '男' 22 '篮球']
 ['小李' '男' 24 '足球']
 ['小ai' '男' 21 '篮球']
 ['小张' '男' 25 '篮球']]
====================
[['小红' '女' 20]
 ['小汤' '男' 22]
 ['小李' '男' 24]
 ['小ai' '男' 21]
 ['小张' '男' 25]]
<class 'numpy.ndarray'>
[['小红', '女', 20], ['小汤', '男', 22], ['小李', '男', 24], ['小ai', '男', 21], ['小张', '男', 25]]
<class 'list'>
--------------------
[['小红' '跑步']
 ['小ai' '篮球']]
(4)pandas库写入
DataFrame.to_csv(path_or_buf=None, sep=',', na_rep='', float_format=None, columns=None, header=True, index=True, index_label=None, mode='w', encoding=None, compression='infer', quoting=None, quotechar='"', lineterminator=None, chunksize=None, date_format=None, doublequote=True, escapechar=None, decimal='.', errors='strict', storage_options=None)

# 常用参数详解
(1)path_or_buf:字符串,放文件名、相对路径、文件流等。
(2)sep:字符串,分隔符,跟read_csv()的一个意思。
(3)na_rep:字符串,将NaN转换为特定值。
(4)columns:列表,指定哪些列写进去。
(5)header:默认header=0,如果没有表头,设置header=None,表示我没有表头呀!
(6)index:关于索引的,默认True,写入索引
(7)mode:{‘w’, ‘x’, ‘a’}, default ‘w’,写入方式。
(8)encoding:编码方式。
......
import pandas as pd
name = ["小小","小耿"]
gender = ["男","男"]
age = [20,25]
hobby = ["跳绳","羽毛球"]

dict_data = {"name":name,"gender":gender,"age":age,"hobby":hobby}
df1 = pd.DataFrame(dict_data)
# mode = "a"为追加数据,index为每行的索引序号,header为标题
df1.to_csv("D:Desktopdata.csv",mode="a",index=False,header=False,encoding="gbk")
df2 = pd.read_csv(r"D:Desktopdata.csv",encoding="gbk")
print(df2) 

# 输出结果
  name gender  age hobby
0   小红      女   20    跑步
1   小汤      男   22    篮球
2   小李      男   24    足球
3  小ai      男   21    篮球
4   小张      男   25    篮球
5   小小      男   20    跳绳
6   小耿      男   25   羽毛球

??Excel

python用于读写excel文件的库有很多,除了前面提到的pandas,还有xlrdxlwtopenpyxlxlwings等等。这里以pandas库为例对Excel进行操作

  • xlrd库:从excel中读取数据,支持xlsxlsx
  • xlwt库:对excel进行修改操作,不支持对xlsx格式的修改;
  • xlutils库:在xlwxlrd中,对一个已存在的文件进行修改;
  • openpyxl库:主要针对xlsx格式的excel进行读取和编辑;
  • xlwings库:对xlsxxlsxlsm格式文件进行读写、格式修改等操作;
  • xlsxwriter库:用来生成excel表格,插入数据、插入图标等表格操作,不支持读取;
  • Microsoft Excel API:需安装pywin32,直接与Excel进程通信,可以做任何在Excel里可以做的事情,但比较慢。
(1)读取Excel文件

read_excel()读取xlsx文件:

pd.read_excel(io, sheet_name=0, header=0, names=None, index_col=None, usecols=None, squeeze=False,dtype=None, engine=None, converters=None, true_values=None, false_values=None, skiprows=None, nrows=None, na_values=None, parse_dates=False, date_parser=None, thousands=None, comment=None, skipfooter=0, convert_float=True, **kwds)

# 常见参数详解
(1)io:文件的路径。
(2)sheet_name:读取的工作表的名称;可以是整型数字、列表名,如果读取多个sheet,也可以是它们组成的列表;以0为起始点。
(3)header:指定哪几行做列名;默认header为0,如果设置为[0,1],则表示将前两行作为多重索引。
(4)names:自定义列名;长度必须和excel的列大小相同;如果缺少列名,使用names指定列名字,会替代原来的列表头。
(5)index_col:用作索引的列;可以是某列的名字,也可以是整型数字或列表。
(6)usecols:指定读取的列;列从0开始,可以是列表,也可以使用Excel的列名,如'A','B'等字母。
(7)squeeze:一列数据时,返回Series还是DataFrame。仅当Excel只有一列的时候起作用,squeeze为True时,返回Series,反之返回DataFrame。
(8)skiprows:跳过指定行;skiprows=n,跳过前n行;skiprows=[a,b,c],跳过第a+1,b+1,c+1行(索引从0开始);使用skiprows后,可能会跳过行首,也就是列名。
(9)nrows:需要读取的行数,表示只读取excel的前nrows行,包括表头。
(10)skipfooter:跳过末尾n行。
......
import pandas as pd

# 读取xlsx,设置sheet位置,详细参数解释可以检索该函数
data = pd.read_excel(r"D:Desktopdata.xlsx",sheet_name=0)
print(data)
print(type(data))
print("*"*20)
print(data.iloc[:,[0,1,3]].values)
print(data.iloc[:,[0,1,3]].values.tolist())

# 输出结果
  name gender  age hobby
0   小红      女   20    跑步
1   小汤      男   22    篮球
2   小李      男   24    足球
3  小ai      男   21    篮球
4   小张      男   25    篮球
5   小小      男   20    跳绳
6   小耿      男   25   羽毛球
<class 'pandas.core.frame.DataFrame'>
********************
[['小红' '女' '跑步']
 ['小汤' '男' '篮球']
 ['小李' '男' '足球']
 ['小ai' '男' '篮球']
 ['小张' '男' '篮球']
 ['小小' '男' '跳绳']
 ['小耿' '男' '羽毛球']]
[['小红', '女', '跑步'], ['小汤', '男', '篮球'], ['小李', '男', '足球'], ['小ai', '男', '篮球'], ['小张', '男', '篮球'], ['小小', '男', '跳绳'], ['小耿', '男', '羽毛球']]
(2)写入Excel文件

to.excel()保存xlsx文件:

DataFrame.to_excel(excel_writer, sheet_name='Sheet1', na_rep='', float_format=None, columns=None, header=True, index=True, index_label=None, startrow=0, startcol=0, engine=None, merge_cells=True, encoding=None, inf_rep='inf', verbose=True, freeze_panes=None)

# 参数详解
(1)excel_writer:字符串或ExcelWriter对象;文件路径或现有的ExcelWriter。
(2)sheet_name:字符串,默认"Sheet1"将包含DataFrame的表的名称。
(3)na_rep:字符串,默认''缺失数据表示方式。
(4)float_format:字符串,默认None格式化浮点数的字符串。
(5)columns:序列,可选要编写的列。
(6)header:布尔或字符串列表,默认为Ture。写出列名。如果给定字符串列表,则假定它是列名称的别名。
(7)index:布尔,默认的Ture写行名(索引)。
......

ExcelWriter()可以向同一个excel的不同sheet中写入对应的表格数据,首先需要实例化一个writer对象,传入的主要参数为已存在容器表格的路径及文件名称。

# 用于将DataFrame对象写入Excel工作表的类。默认值是对xls使用xlwt,对xlsx使用openpyxl。
class pandas.ExcelWriter(path, engine=None, date_format=None, datetime_format=None, mode='w', **engine_kwargs)

# 参数详解
(1)path:str,xls或xlsx文件的路径。
(2)engine:str (可选参数),用于编写的引擎,常见的引擎有"openpyxl"和"xlsxwriter"。如果为无,则默认为xlsxwriter,但是"xlsxwriter"模块不支持追加操作,需要追加新的sheet操作选择"openpyxl"参数,否则会报错。注意:只能作为关键字参数传递。
(3)date_format:str,默认为None,格式字符串,用于写入Excel文件的日期(例如"YYYY-MM-DD")。
(4)datetime_format:str,默认为None,写入Excel文件的日期时间对象的格式字符串。(例如"YYYY-MM-DD HH:MM:SS")。
(5)mode:{"w","a"},默认为"w",要使用的文件模式(写或追加)。
(6)if_sheet_exists:{'error','new','replace','overlay'},默认'error',写入的sheet name已存在时代码操作。默认'error'表示报错;'new'表示engine自动创建新的其他sheet name;'replace'表示覆盖原sheet数据,在写入之前删除工作表的内容;'overlay'表示将内容写入现有工作表而不删除旧内容。

为了与CSV编写器兼容,ExcelWriter在写入之前将列表和字典序列化为字符串。

在使用pd.ExcelWriter()的时候可能会出现问题:if_sheet_exists=‘overlay’ 不起作用

查阅资料:if_sheet_exists{'error', 'new', 'replace', 'overlay'},如果pandas的版本过低,是没有overlay参数的,需要升级pandas版本。我的版本:pandas-2.0.1

# 追加数据
import pandas as pd
name = ["小伟","小猪"]
gender = ["男","男"]
age = [20,18]
hobby = ["跳绳","台球"]
dict_data = {"name":name,"gender":gender,"age":age,"hobby":hobby}
df = pd.DataFrame(dict_data)
with pd.ExcelWriter(r"D:Desktopdata.xlsx", engine='openpyxl', mode='a',if_sheet_exists='overlay') as writer:
	df1 = pd.DataFrame(pd.read_excel(r"D:Desktopdata.xlsx", sheet_name='data')) 
	df_rows = df1.shape[0] #获取原数据的行数
	# 将数据df写入excel中的sheet1表,从第一个空行开始写
	# 为了避免覆盖现有内容,要告诉to_excel方法从新的一行开始写,参数startrow设为"原行数+1"
	df.to_excel(writer, sheet_name='data',startrow=df_rows+1, index=False, header=False)
df2 = pd.read_excel(r"D:Desktopdata.xlsx",sheet_name=0)
print(df2) 

# 输出结果
  name gender  age hobby
0   小红      女   20    跑步
1   小汤      男   22    篮球
2   小李      男   24    足球
3  小ai      男   21    篮球
4   小张      男   25    篮球
5   小小      男   20    跳绳
6   小耿      男   25   羽毛球
7   小伟      男   20    跳绳
8   小猪      男   18    台球

写入Excel的几种情形与方式(覆盖、新增、追加、对齐),具体细节见:参考博客①、参考博客②

import pandas as pd
import numpy as np
s1 = pd.DataFrame(np.array([['s1', 's1', 's1', 's1']]), columns=['a', 'b', 'c', 'd'])
s2 = pd.DataFrame(np.array([['s2', 's2', 's2', 's2']]), columns=['a', 'b', 'c', 'd'])

# (1)删除文件原有数据,只保留s2一份数据(最后一份)
# s1.to_excel(r"D:Desktop	est.xlsx", sheet_name="111", index=False)
# s2.to_excel(r"D:Desktop	est.xlsx", sheet_name="222", index=False)
with pd.ExcelWriter(r"D:Desktop	est2.xlsx") as writer:
    # (2) 删除文件原有数据,同时保留s1和s2两份数据
    s1.to_excel(writer, sheet_name="111", index=False)
    s2.to_excel(writer, sheet_name="222", index=False)

??JSON

常见的处理JSON文件的第三方库(速度不同)包括:jsonsimplejsonujsonorjsonsimdjsonrapidjson。一般情况下的json文件,存储的是python中的一个dict。这里以map.geojson文件和CPython 本身的json模块为例,源文件内容如下。参考博客①、参考博客②

{
    "type": "FeatureCollection",
    "features": [{
            "type": "Feature",
            "properties": {},
            "geometry": {
                "coordinates": [[[116.3591064789793, 40.0611769097348], [116.35882714532096, 40.06035824493355], [116.3588680234169, 40.06017052423036], [116.3592154872361, 40.05968557668524], [116.35964470724883, 40.05949263960517], [116.36125939205749, 40.05968557668524], [116.36073478982053, 40.06143241456951], [116.3591064789793, 40.0611769097348]]],
                "type": "Polygon"
            }
        }, {
            "type": "Feature",
            "properties": {},
            "geometry": {
                "coordinates": [116.35838429946176, 40.0595499993847],
                "type": "Point"
            }
        }, {
            "type": "Feature",
            "properties": {},
            "geometry": {
                "coordinates": [116.36078873507478, 40.06152377992771],
                "type": "Point"
            }
        }
    ]
}

使用JSON函数需要导入json库:import json

函数 描述
json.loads() 将已编码的JSON字符串解码为Python对象
json.dumps() Python对象编码成JSON字符串
json.loads(s, *, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)

# 参数详解
(1)s:要解码的JSON字符串。
(2)cls:指定用于解码JSON字符串的自定义类。
(3)object_hook:指定一个回调函数,将解码后的JSON对象转换成其他Python对象。
(4)parse_float:指定一个回调函数,将解码后的JSON浮点数转换成Python浮点数。
(5)parse_int:指定一个回调函数,将解码后的JSON整数转换成Python整数。
(6)parse_constant:指定一个回调函数,用于解析JSON中的常量(例如null,true,false)。
(7)object_pairs_hook:指定一个回调函数,将解码后的JSON对象返回为Python的键值对。
json.dumps(obj, *, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw)

# 参数详解
(1)obj:转化成json的对象。
(2)skipkeys:是否跳过无法被JSON序列化的key(包括str, int, float, bool, None)。
(3)ensure_ascii:输出保证将所有输入的非ASCII字符转义。
(4)check_circular:是否检查循环引用。
(5)allow_nan:是否允许JSON规范外的float数据(nan, inf, -inf)。
(6)indent:是一个正整数, 代表序列化后的缩进。
(7)separators:是一个格式为 (item_separator, key_separator) 的元组, 默认取值为 (',',':')。
(8)default:是一个函数, 当某个value无法被序列化时, 对其调用该函数。
(9)sort_keys:是否对数据按照key进行排序。
# 读取json
import json
with open(r"D:Desktopmap.geojson", 'r') as f:
    content = f.read()
    a = json.loads(content)
    print(type(a))
    print(a)
    print("*"*20)
    print(a["features"][2]["geometry"])

# 输出结果
<class 'dict'>
{'type': 'FeatureCollection', 'features': [{'type': 'Feature', 'properties': {}, 'geometry': {'coordinates': [[[116.3591064789793, 40.0611769097348], [116.35882714532096, 40.06035824493355], [116.3588680234169, 40.06017052423036], [116.3592154872361, 40.05968557668524], [116.35964470724883, 40.05949263960517], [116.36125939205749, 40.05968557668524], [116.36073478982053, 40.06143241456951], [116.3591064789793, 40.0611769097348]]], 'type': 'Polygon'}}, {'type': 'Feature', 'properties': {}, 'geometry': {'coordinates': [116.35838429946176, 40.0595499993847], 'type': 'Point'}}, {'type': 'Feature', 'properties': {}, 'geometry': {'coordinates': [116.36078873507478, 40.06152377992771], 'type': 'Point'}}]}
********************
{'coordinates': [116.36078873507478, 40.06152377992771], 'type': 'Point'}
# 将字典保存成json
import json
a = {
     "type": "Feature",
     "properties": {},
     "geometry": {
         "coordinates": [116.36078873507478, 40.06152377992771],
         "type": "Point"
         }
     }

b_str = json.dumps(a)
print(type(b_str))
with open(r"D:Desktop
ew_json.json", 'w') as f:
    f.write(b_str)
with open(r"D:Desktop
ew_json.json", 'r') as f:
    content = f.read()
    a = json.loads(content)
    print(a)

# 输出结果
<class 'str'>
{'type': 'Feature', 'properties': {}, 'geometry': {'coordinates': [116.36078873507478, 40.06152377992771], 'type': 'Point'}}

??XML

Python中,有多个库可以用来读取和处理XML文档。以下是其中一些常用的库:

  • xml.etree.ElementTree(内置库):这是Python标准库中的一个模块,提供了基本的XML文档解析和操作功能。它具有简单的API和高效的性能,适合处理小型到中型的XML文档。
  • lxmllxmlPython中一个功能强大的XML/HTML解析库,基于libxml2libxslt库。它提供了与ElementTree相似的API,但具有更好的性能和更多的功能。lxml支持XPathXSLTXML Schema等高级特性,适用于处理大型和复杂的XML文档。
  • xmltodictxmltodict库可以将XML文档解析为Python字典,使XML数据的处理更加简便。它提供了一个简单的API,将XML数据转换为Python数据结构,便于数据的操作和处理。
  • minidomxml.dom.minidomPython标准库中的一个模块,提供了基本的DOM(文档对象模型)接口来解析和操作XML文档。尽管它的API相对较复杂,但它具有更多的功能和灵活性,适用于需要更高级控制的场景。

这些库都有各自的优点和适用场景。在选择库时,可以考虑以下因素:

  • 对于简单的XML操作和小型文档,内置库xml.etree.ElementTree是一个轻量级且易于使用的选择。
  • 如果需要更好的性能、更多的功能和高级特性(如XPathXSLT),可以选择lxml库。
  • 如果希望将XML数据解析为Python字典以便于处理,可以使用xmltodict库。
  • 如果对DOM接口熟悉并且需要更多的灵活性和控制能力,可以考虑使用minidom库。
# 说明
# 加载和读取xml文件,获取xml文档对象
from xml.dom import minidom  
doc = minidom.parse(xmlfile)
# 获取xml文档根节点
root = doc.documentElement
# 节点属性
root.nodeName	# 每个节点都有它的nodeName,nodeValue,nodeType属性
root.nodeValue	# nodeValue是节点的值,只对本节点有效
root.nodeType	# 节点类型;
root.ELEMENT_NODE
# 属性值的获取、修改、删除
root.getAttribute(attributeName)		# 获取xml节点属性值
root.setAttribute(attributeName, value)	# 修改或添加xml节点属性值
root.getElementsByTagName(TagName)		# 根据标签获取xml节点对象集合
root.removeAttribute(attributeName)		# 删除xml节点属性值
# 子节点的访问
root.childNodes  					# 获取子节点列表
root.childNodes[index].nodeValue	# 获取xml节点值
root.firstChild						# 访问第一个节点(相当于root.childNodes[0])
root.childNodes[0].data				# 获得文本值
# 删除子节点
node.removeChild(childnode_in_node)	# 删除node节点下面的子节点childnode_in_node
# 生成节点
node.createElement('activity')		# 生成节点  # 文本节点.createTextNode('xxxxx')
(1)读取XML

XML示例文件:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy?? -->
<breakfast_menu>
	<food>
		<name>Belgian Waffles</name>
		<price>$5.95</price>
		<calories>650</calories>
		<cropRegion x="0" y="0" width="0000" height="1234"/>
	</food>
	<food>
		<name>Strawberry Belgian Waffles</name>
		<price>$7.95</price>
		<calories>900</calories>
		<cropRegion x="1" y="1" width="1111" height="2345"/>
	</food>
	<food>
		<name>Berry-Berry Belgian Waffles</name>
		<price>$8.95</price>
		<calories>900</calories>
		<cropRegion x="2" y="2" width="2222" height="3456"/>
	</food>
	<food>
		<name>French Toast</name>
		<price>$4.50</price>
		<calories>600</calories>
		<cropRegion x="3" y="3" width="3333" height="4567"/>
	</food>
	<food>
		<name>Homestyle Breakfast</name>
		<price>$6.95</price>
		<calories>950</calories>
		<cropRegion x="4" y="4" width="4444" height="5678"/>
	</food>
</breakfast_menu>

DOM解析XML文件

from xml.dom import minidom

# 解析xml文件(句柄或文件路径)
doc = minidom.parse(r"D:Desktopsimple.xml")
# doc = minidom.parseString()  # 解析xml字符串
print(doc)
print("*"*20)
# 获得根节点
root_node = doc.documentElement  
print(root_node)
# 节点名称
print(root_node.nodeName)
# 节点类型(元素节点,文本节点,属性节点)
print(root_node.nodeType)
# 所有子节点,为列表
print(root_node.childNodes)
print("*"*20)
# 通过节点名称寻找节点,返回列表
filename_node = root_node.getElementsByTagName('name')
print(filename_node)
print("*"*20)
# 子节点为文本节点,文本节点有data属性即为文本值
filename = filename_node[1].childNodes[0].data
print(filename)
print("*"*20)
# 读取指定属性值,root.setAttribute(attributeName, value)更新修改属性值
cropRegion_node = root_node.getElementsByTagName('cropRegion')
width = cropRegion_node[1].getAttribute("width")
print(width)

# 输出结果
<xml.dom.minidom.Document object at 0x0000016F45D0EDC0>
********************
<DOM Element: breakfast_menu at 0x16f45d011f0>
breakfast_menu
1
[<DOM Text node "'
	'">, <DOM Element: food at 0x16f45d01f70>, <DOM Text node "'
	'">, <DOM Element: food at 0x16f45d01b80>, <DOM Text node "'
	'">, <DOM Element: food at 0x16f45ccddc0>, <DOM Text node "'
	'">, <DOM Element: food at 0x16f458e0dc0>, <DOM Text node "'
	'">, <DOM Element: food at 0x16f45cf05e0>, <DOM Text node "'
'">]
********************
[<DOM Element: name at 0x16f45d01dc0>, <DOM Element: name at 0x16f45d018b0>, <DOM Element: name at 0x16f45ccdd30>, <DOM Element: name at 0x16f45cf0af0>, <DOM Element: name at 0x16f45cf0280>]
********************
Strawberry Belgian Waffles
********************
1111
(2)写入XML
# 写入文件
DOM树对象.writexml(fh,indent='',addindent='	',newl='
',encoding='UTF-8')
# writexml()第一个参数是目标文件对象,第二个参数是根节点的缩进格式,第三个参数是其他子节点的缩进格式,第四个参数制定了换行格式,第五个参数制定了xml内容的编码。

# zip()函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
# zip()方法在Python2和Python3中的不同:在Python3.x中为了减少内存,zip()返回的是一个对象。如需展示列表,需手动list()转换。
a = [1,2,3]
b = [4,5,6]
c = [4,5,6,7,8]
# 返回一个对象
zipped = zip(a,b)
print(zipped)
# list()转换为列表
print(list(zipped))
# 元素个数与最短的列表一致
print(list(zip(a,c)))
# 与zip相反,*zip()函数是zip()函数的逆过程,将zip对象变成原先组合前的数据
a1 = zip(*zip(a,b))
print(a1)
print(list(a1))

# 输出结果
<zip object at 0x0000016F45CD6200>
[(1, 4), (2, 5), (3, 6)]
[(1, 4), (2, 5), (3, 6)]
<zip object at 0x0000016F45CD0FC0>
[(1, 2, 3), (4, 5, 6)]

DOMXML文件

# 写入XML文件
from xml.dom import minidom
# (1)创建DOM树对象
dom = minidom.Document()
# (2)创建根节点,每次都要用DOM对象来创建任何节点
root_node = dom.createElement("people")
# (3)用DOM对象添加根节点
dom.appendChild(root_node)

# 用DOM对象创建元素字节点
name_node = dom.createElement("name")
# 用父节点对象添加元素子节点
root_node.appendChild(name_node)
# 设置该节点的属性
name_node.setAttribute("sex","男")
name_node.setAttribute("height","180")
# 用DOM创建文本节点,把文本节点(文字内容)看成子节点
name_text = dom.createTextNode("小汤")
# 用添加了文本的节点对象(看成文本节点的父节点)添加文本节点
name_node.appendChild(name_text)

# 用DOM对象创建元素字节点
hobby_node = dom.createElement("hobby")
# 用父节点对象添加元素子节点
root_node.appendChild(hobby_node)
# 用添加了文本的节点对象(看成文本节点的父节点)添加文本节点
hobby_node.appendChild(dom.createTextNode("篮球"))

score_node = dom.createElement("score")
for item, value in zip(["语文", "数学", "英语", "理综"], [150, 150, 150, 300]):
        elem = dom.createElement(item)
        elem.appendChild(dom.createTextNode(str(value)))
        score_node.appendChild(elem)
root_node.appendChild(score_node)
try:
    with open(r"D:Desktopwrite.xml",'w',encoding='UTF-8') as fh:
        # dom.writexml()第一个参数是目标文件对象,第二个参数是根节点的缩进格式,第三个参数是其他子节点的缩进格式,
        # 第四个参数制定了换行格式,第五个参数制定了xml内容的编码。
        dom.writexml(fh, indent='', addindent='	', newl='
', encoding='UTF-8')
        print('OK')
except Exception as err:
    print('错误:{err}'.format(err=err))

输出的XML文件内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<people>
	<name sex="男" height="180">小汤</name>
	<hobby>篮球</hobby>
	<score>
		<语文>150</语文>
		<数学>150</数学>
		<英语>150</英语>
		<理综>300</理综>
	</score>
</people>

??TXT

(1)读取TXT

源数据data.txt内容如下:

name	gender	age	hobby
小红	女	20	跑步
小汤	男	22	篮球
小李	男	24	足球
小ai	男	21	篮球
小张	男	25	篮球
小小	男	20	跳绳
小耿	男	25	羽毛球

操作txt文件,read()readline()readlines()、以及获取某一列内容,代码示例如下:

# (1)read()一次性读取所有文本
with open(r"D:Desktopdata.txt", "r") as f:  #打开文本
    data1 = f.read()   #读取文本
    print(data1)
print("*"*20)
# (2)readline()读取第一行的内容
with open(r"D:Desktopdata.txt", 'r') as f:
    data2 = f.readline()
    print(data2)
print("*"*20)
# (3)readlines()读取全部内容,以列表的格式返回结果
with open(r"D:Desktopdata.txt", 'r') as f:
    data3 = f.readlines()
    print(data3)
    for ann in data3:
        # 去除文本中的换行符
        ann = ann.strip('
')
        print(ann)
print("*"*20)
# (4)读取txt某一列数据,第一种方法
# 要读取第i列数据则可以读取每行的第i个数据再将其拼接起来
column_list = []
with open(r"D:Desktopdata.txt", 'r') as f:
    data = f.readlines()
    for line in data:
        # 去除文本中的换行符
        ann = line.strip('
')
        a = ann.split("	")
        column_list.append(a[3])
print(column_list)
print("*"*20)
# (5)读取txt某一列数据,第二种方法
column_list2 = []
with open(r"D:Desktopdata.txt", 'r') as f:
    # 以行的形式进行读取文件
    line2 = f.readline()
    while line2:
        ann2 = line2.strip('
')
        aa = ann2.split("	")
        column_list2.append(aa[2])
        line2 = f.readline()
print(column_list2)
print("*"*20)
# (6)读取txt某一列数据,第三种方法
import codecs
column_list3 = []
with codecs.open(r"D:Desktopdata.txt", mode = 'r') as f:
    # 以行的形式进行读取文件
    line3 = f.readline()
    while line3:
        ann3 = line3.strip('
')
        aaa = ann3.split("	")
        column_list3.append(aaa[1])
        line3 = f.readline()
print(column_list3)

# 输出结果
name	gender	age	hobby
小红	女	20	跑步
小汤	男	22	篮球
小李	男	24	足球
小ai	男	21	篮球
小张	男	25	篮球
小小	男	20	跳绳
小耿	男	25	羽毛球

********************
name	gender	age	hobby

********************
['name	gender	age	hobby
', '小红	女	20	跑步
', '小汤	男	22	篮球
', '小李	男	24	足球
', '小ai	男	21	篮球
', '小张	男	25	篮球
', '小小	男	20	跳绳
', '小耿	男	25	羽毛球
']
name	gender	age	hobby
小红	女	20	跑步
小汤	男	22	篮球
小李	男	24	足球
小ai	男	21	篮球
小张	男	25	篮球
小小	男	20	跳绳
小耿	男	25	羽毛球
********************
['hobby', '跑步', '篮球', '足球', '篮球', '篮球', '跳绳', '羽毛球']
********************
['age', '20', '22', '24', '21', '25', '20', '25']
********************
['gender', '女', '男', '男', '男', '男', '男', '男']
(2)写入TXT
# 写入txt
hobby =["hobby", "跑步", "篮球", "足球", "篮球", "篮球", "跳绳", "羽毛球"]
name = ["name", "小红", "小汤", "小李", "小ai", "小张", "小小", "小耿"]
age = ["age", "20", "22", "24", "21", "25", "30", "25"]

with open(r"D:DesktopwriteTXT.txt","a") as f:
    length = len(age)
    for i in range(length):
        line = [hobby[i], name[i], age[i]]
        lines = "	".join(line)
        # lines = hobby[i] + "	" + name[i] + "	" + age[i]
        print(lines)
        f.write(lines + '
')
column_list = []
with open(r"D:DesktopwriteTXT.txt","r") as f:
    data = f.readlines()
    # print(data)
    for line in data:
        # 去除文本中的换行符
        ann = line.strip('
')
        a = ann.split("	")
        column_list.append(a[2])
print(column_list)

# 输出结果
hobby	name	age
跑步	小红	20
篮球	小汤	22
足球	小李	24
篮球	小ai	21
篮球	小张	25
跳绳	小小	30
羽毛球	小耿	25
['age', '20', '22', '24', '21', '25', '30', '25']

多谢!多谢!
笔者不才,请多交流!!!

欢迎大家关注预览我的博客Blog:HeartLoveLife
能力有限,敬请谅解!!