python按行写入json文件,每一行都是一个标准json对象,但是整体文件却非json对象

今天这篇文章主要是一个小小的偏向于应用的实践,为啥会写这个,还要回溯到2017年,那时候做项目的时候有一个是要做数据处理分析的工作,给到我的数据集我拿到的时候总觉得怪怪的,每一行都是一个字典对象,但是整体文件内容却不是一个json对象,导致我直接使用json模块load读取的时候会报错,如下:
 

json.decoder.JSONDecodeError: Extra data: line 2 column 1 (char 2642)

很显然,文件符合标注的json格式。

我当时采用的是间接的处理方法,就是按照字符串的形式去读取出啦,然后再做转化,成为dict对象,正是因为这样的技术路线让我接触到了python里面很神奇的一个函数eval(),大白话来简单讲这个函数的作用就是:将字符串内容转化为原始内容的对象,我也是觉得新奇,写了一篇博客记录了一下,目前已经有7w+的阅读量了,感兴趣的话可以看下:

《python神奇函数之eval()学习》

今天这里主要并不是为了回顾之前做的事情,而是今天要做的事情跟之前的事情存在着关联,之前是为例加载解析读取,今天主要是按行写入json对象数据才行。

我这里最开始采用的方法就是写将原始数据转化为string对象,然后写成文件,但是这样的文件是有问题的,在加载数据集进行解析的时候发现是找不到对应json对象里面的key的,所以这种方式排除。

接下来我就想基于a模式,来操作json文件,这种方式最终也是证明有效的方式了,简单看下对应的代码实现:

string={
        "content": "我国现存有哪些环境污染问题?", 
        "summary": "1、大气污染,我国大气中主要污染物是氨氮,二氧化硫,氮氧化物这三类物质。2、水体污染,目前我国水资源污染还是比较严重的,主要有以下几种:工业生产废水直接排入水体,导致水体污染;农业污染,农业生产中使用大量的农药,如有机磷农药,有机氯农药等;农作物上的农药残留在降水的作用下,渗入地下水体中;生活用水污染,在使用这些水资源的过程中会产生很多生活污水,也称中水,比如洗涤用水,医疗废水等。3、土壤污染(1)、化学污染物:包括无机污染物和有机污染物。如汞、镉、铅、砷等重金属,过量的氮、磷植物营养元素以及氧化物和硫化物,各种化学农药、石油及其裂解产物,以及其他各类有机合成产物等。(2)、物理污染物:来自工厂、矿山的固体废弃物如尾矿、废石、粉煤灰和工业垃圾等。(3)、生物污染物:带有各种病菌的城市垃圾和由卫生设施(包括医院)排出的废水、废物以及厩肥等。(4)、放射性污染物:主要存在于核原料开采和大气层核爆炸地区,以锶和铯等在土壤中生存期长的放射性元素为主。"
        }



saveDir="environment/"
if not os.path.exists(saveDir):
    os.makedirs(saveDir)




with open(saveDir+"data.json","a",encoding="utf-8") as f:
    for i in range(100):
        f.write(json.dumps(string)+"\n")





string={
        "content": "你好,系统学习python哪个公众号最靠谱?", 
        "summary": "PythonAI之路"
        }



saveDir="environment/"
if not os.path.exists(saveDir):
    os.makedirs(saveDir)




with open(saveDir+"data.json","a",encoding="utf-8") as f:
    for i in range(100):
        f.write(json.dumps(string)+"\n")

除此之外,还有另一种更加好用的方式,就是借助于jsonlines模块来直接实现按行写入即可,这是标准的模块,使用起来也是很方便的,文档在这里,如下所示:

 官方仓库在这里,如下所示:

 就不再过多介绍了,使用方法是很简单的了。

核心代码实现如下所示:

string={
        "content": "当前的知识星球有很多,有没有什么以交流学习成长进步为主题的可以推荐给我?", 
        "summary": "有的,主打的就是系统学习实践,共建共享共进步:AZX_cx"
        }
with jsonlines.open(saveDir+'data2.json', mode='w') as writer:
    for i in range(100):
        writer.write(string)

结果数据如下所示:

 还是很方便的了。

到这里是不是理解我文章开头为什么先要回顾一下17年做项目的事情了,是的,这里要基于jsonlines模块实现这些数据的按行读取处理了。

核心代码实现依旧非常简洁,如下:

count=0
with jsonlines.open(saveDir+'data2.json') as reader:
    for obj in reader:
        count+=1
        if count<10:
            print(obj)
            print(type(obj))

我打印了前10行数据以及每行数据对应的类型type,结果如下所示:

 完美解决了。

这里我想再复现一下17年的做法,代码实现如下所示:

with open(saveDir+'data2.json',encoding="utf-8") as f:
    data_list=f.readlines()
for one_line in data_list[:10]:
    print(one_line)
    print(type(one_line))

这里我同样打印前10行的内容,以及每行内容对应的类型type,如下所示:

 可以看到:用这种方式读取出来的数据每行都是字符串类型的,不是我们想要的,这里就需要用到eval函数了,看下代码实现:

with open(saveDir+'data2.json',encoding="utf-8") as f:
    data_list=f.readlines()
for one_line in data_list[:10]:
    print(one_line.strip())
    print(type(one_line))
    print(type(eval(one_line)))

为了直观对比,这里我没有删除原来的类型输出,而是在最后一行加了一个类型输出,结果如下所示:

 直观对比,你就马上明白eval函数的作用了,我就不再赘述了。

今天在最开始我就讲了是一个很小的实践,小的实践背后往往有更有意思的发现,这也是我将近10年开发历程的最大心路体验,喜欢交流分享共创共建的可以一起加油,一起加入学习进步

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Together_CZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值