Bagaimana cara mengonversi file CSV ke multiline JSON?

98

Ini kode saya, hal yang sangat sederhana ...

import csv
import json

csvfile = open('file.csv', 'r')
jsonfile = open('file.json', 'w')

fieldnames = ("FirstName","LastName","IDNumber","Message")
reader = csv.DictReader( csvfile, fieldnames)
out = json.dumps( [ row for row in reader ] )
jsonfile.write(out)

Deklarasikan beberapa nama kolom, pembaca menggunakan CSV untuk membaca file, dan nama kolom untuk membuang file ke format JSON. Inilah masalahnya ...

Setiap record di file CSV berada di baris yang berbeda. Saya ingin keluaran JSON dengan cara yang sama. Masalahnya adalah ia membuang semuanya dalam satu garis besar dan panjang.

Saya sudah mencoba menggunakan sesuatu seperti for line in csvfile:dan kemudian menjalankan kode saya di bawah yang reader = csv.DictReader( line, fieldnames)dengannya loop melalui setiap baris, tetapi itu melakukan seluruh file pada satu baris, kemudian loop melalui seluruh file di baris lain ... berlanjut sampai kehabisan baris .

Ada saran untuk memperbaiki ini?

Sunting: Untuk memperjelas, saat ini saya memiliki: (setiap catatan di baris 1)

[{"FirstName":"John","LastName":"Doe","IDNumber":"123","Message":"None"},{"FirstName":"George","LastName":"Washington","IDNumber":"001","Message":"Something"}]

Apa yang saya cari: (2 catatan pada 2 baris)

{"FirstName":"John","LastName":"Doe","IDNumber":"123","Message":"None"}
{"FirstName":"George","LastName":"Washington","IDNumber":"001","Message":"Something"}

Tidak setiap bidang individu menjorok / pada baris terpisah, tetapi setiap catatan pada barisnya sendiri.

Beberapa masukan sampel.

"John","Doe","001","Message1"
"George","Washington","002","Message2"
BeanBagKing
sumber
saya tidak yakin kode Anda tidak persis apa yang Anda katakan; itu seharusnya [{..row..},{..row..},...]tidak menghasilkan {..row..}{..row..}... Artinya, outputnya akan terlihat seperti array json dari objek json, bukan aliran objek json yang tidak terhubung.
SingleNegationElimination

Jawaban:

145

Masalah dengan keluaran yang Anda inginkan adalah bahwa itu bukan dokumen json yang valid ,; itu aliran dokumen json !

Tidak apa-apa, jika itu yang Anda butuhkan, tetapi itu berarti bahwa untuk setiap dokumen yang Anda inginkan dalam keluaran Anda, Anda harus memanggil json.dumps.

Karena baris baru yang Anda inginkan untuk memisahkan dokumen Anda tidak terdapat dalam dokumen-dokumen itu, Anda siap untuk memasoknya sendiri. Jadi kita hanya perlu menarik loop keluar dari panggilan ke json.dump dan memasukkan baris baru untuk setiap dokumen yang ditulis.

import csv
import json

csvfile = open('file.csv', 'r')
jsonfile = open('file.json', 'w')

fieldnames = ("FirstName","LastName","IDNumber","Message")
reader = csv.DictReader( csvfile, fieldnames)
for row in reader:
    json.dump(row, jsonfile)
    jsonfile.write('\n')
SingleNegationElimination
sumber
1
Sempurna! Maaf Anda harus melakukan sedikit pembacaan pikiran untuk mendapatkannya, dan terima kasih atas koreksi / klarifikasi. Inilah yang saya cari.
BeanBagKing
4
tapi masalahnya outfile bukan json yang valid
MONTYHS
1
@MONTYHS: Kalimat pertama dari jawaban ini menjelaskan bahwa outfile bukanlah dokumen json; dan apa itu sebagai gantinya. Apakah Anda mengalami masalah yang berbeda dari orang yang mengajukan pertanyaan ini?
SingleNegationElimination
6
@ abhi1610: jika Anda mengharapkan sebuah header dalam masukan, Anda harus membangun DictReadertanpa memberikan fieldnamesargumen; itu kemudian akan membaca baris pertama untuk mendapatkan nama field dari file.
SingleNegationElimination
1
Dan itu bagus untuk menambahkan pengkodean untuk file Anda csvfile = open('file.csv', 'r',encoding='utf-8') dan jsonfile = open('file.json', 'w',encoding='utf-8')
Marek Bernád
21

Anda dapat menggunakan Pandas DataFrame untuk melakukannya, dengan Contoh berikut:

import pandas as pd
csv_file = pd.DataFrame(pd.read_csv("path/to/file.csv", sep = ",", header = 0, index_col = False))
csv_file.to_json("/path/to/new/file.json", orient = "records", date_format = "epoch", double_precision = 10, force_ascii = True, date_unit = "ms", default_handler = None)
Naufal
sumber
9

Saya mengambil respons @ SingleNegationElimination dan menyederhanakannya menjadi tiga baris yang dapat digunakan dalam pipeline:

import csv
import json
import sys

for row in csv.DictReader(sys.stdin):
    json.dump(row, sys.stdout)
    sys.stdout.write('\n')
Lawrence I. Siden
sumber
8
import csv
import json

file = 'csv_file_name.csv'
json_file = 'output_file_name.json'

#Read CSV File
def read_CSV(file, json_file):
    csv_rows = []
    with open(file) as csvfile:
        reader = csv.DictReader(csvfile)
        field = reader.fieldnames
        for row in reader:
            csv_rows.extend([{field[i]:row[field[i]] for i in range(len(field))}])
        convert_write_json(csv_rows, json_file)

#Convert csv data into json
def convert_write_json(data, json_file):
    with open(json_file, "w") as f:
        f.write(json.dumps(data, sort_keys=False, indent=4, separators=(',', ': '))) #for pretty
        f.write(json.dumps(data))


read_CSV(file,json_file)

Dokumentasi json.dumps ()

Laxman
sumber
6

Anda dapat mencoba ini

import csvmapper

# how does the object look
mapper = csvmapper.DictMapper([ 
  [ 
     { 'name' : 'FirstName'},
     { 'name' : 'LastName' },
     { 'name' : 'IDNumber', 'type':'int' },
     { 'name' : 'Messages' }
  ]
 ])

# parser instance
parser = csvmapper.CSVParser('sample.csv', mapper)
# conversion service
converter = csvmapper.JSONConverter(parser)

print converter.doConvert(pretty=True)

Edit:

Pendekatan yang lebih sederhana

import csvmapper

fields = ('FirstName', 'LastName', 'IDNumber', 'Messages')
parser = CSVParser('sample.csv', csvmapper.FieldMapper(fields))

converter = csvmapper.JSONConverter(parser)

print converter.doConvert(pretty=True)
Snork S
sumber
3
Saya pikir Anda harus memiliki, setidaknya, secara eksplisit menyebutkan bahwa Anda menggunakan modul pihak ketiga csvmapper,, untuk melakukan ini (dan mungkin di mana mendapatkannya) sebagai lawan dari sesuatu yang ada di dalamnya.
martineau
2

Tambahkan indentparameter kejson.dumps

 data = {'this': ['has', 'some', 'things'],
         'in': {'it': 'with', 'some': 'more'}}
 print(json.dumps(data, indent=4))

Perhatikan juga bahwa, Anda dapat menggunakan json.dumpdengan terbuka jsonfile:

json.dump(data, jsonfile)
Wayne Werner
sumber
Tidak seperti yang saya cari. Saya mengedit pertanyaan asli saya untuk mengklarifikasi dan menunjukkan keluaran yang diinginkan. Terima kasih atas tipnya, ini mungkin berguna nanti.
BeanBagKing
2

Saya melihat ini sudah tua tetapi saya membutuhkan kode dari SingleNegationElimination namun saya memiliki masalah dengan data yang mengandung karakter non utf-8. Ini muncul di bidang yang tidak terlalu saya pedulikan, jadi saya memilih untuk mengabaikannya. Namun itu membutuhkan usaha. Saya baru mengenal python jadi dengan beberapa trial and error saya membuatnya berfungsi. Kode tersebut adalah salinan SingleNegationElimination dengan penanganan ekstra utf-8. Saya mencoba melakukannya dengan https://docs.python.org/2.7/library/csv.html tetapi pada akhirnya menyerah. Kode di bawah ini berfungsi.

import csv, json

csvfile = open('file.csv', 'r')
jsonfile = open('file.json', 'w')

fieldnames = ("Scope","Comment","OOS Code","In RMF","Code","Status","Name","Sub Code","CAT","LOB","Description","Owner","Manager","Platform Owner")
reader = csv.DictReader(csvfile , fieldnames)

code = ''
for row in reader:
    try:
        print('+' + row['Code'])
        for key in row:
            row[key] = row[key].decode('utf-8', 'ignore').encode('utf-8')      
        json.dump(row, jsonfile)
        jsonfile.write('\n')
    except:
        print('-' + row['Code'])
        raise
Mark Channing
sumber
1

Bagaimana dengan menggunakan Pandas untuk membaca file csv menjadi DataFrame ( pd.read_csv ), kemudian memanipulasi kolom jika Anda mau (menghapusnya atau memperbarui nilai) dan terakhir mengubah DataFrame kembali ke JSON ( pd.DataFrame.to_json ).

Catatan: Saya belum memeriksa seberapa efisien ini akan tetapi ini jelas merupakan salah satu cara termudah untuk memanipulasi dan mengonversi csv besar ke json.

impiyush
sumber
0

Sebagai sedikit peningkatan pada jawaban @MONTYHS, iterasi melalui tup nama bidang:

import csv
import json

csvfilename = 'filename.csv'
jsonfilename = csvfilename.split('.')[0] + '.json'
csvfile = open(csvfilename, 'r')
jsonfile = open(jsonfilename, 'w')
reader = csv.DictReader(csvfile)

fieldnames = ('FirstName', 'LastName', 'IDNumber', 'Message')

output = []

for each in reader:
  row = {}
  for field in fieldnames:
    row[field] = each[field]
output.append(row)

json.dump(output, jsonfile, indent=2, sort_keys=True)
GarciadelCastillo
sumber
-1
import csv
import json
csvfile = csv.DictReader('filename.csv', 'r'))
output =[]
for each in csvfile:
    row ={}
    row['FirstName'] = each['FirstName']
    row['LastName']  = each['LastName']
    row['IDNumber']  = each ['IDNumber']
    row['Message']   = each['Message']
    output.append(row)
json.dump(output,open('filename.json','w'),indent=4,sort_keys=False)
MONTYHS
sumber
Ketika saya mencoba menggunakan ini, saya mendapatkan "KeyError: 'FirstName'". Sepertinya kuncinya tidak ditambahkan. Saya tidak yakin persis apa yang Anda coba lakukan di sini, tetapi menurut saya hasilnya tidak cocok dengan apa yang saya cari karena Anda menggunakan indentasi = 4 yang sama dengan Wayne. Output apa yang harus saya harapkan? Saya mengedit posting asli saya untuk mengklarifikasi apa yang saya cari.
BeanBagKing
Kesalahan kunci kemungkinan besar karena kode ini tidak meneruskan argumen header ke DictReader, jadi kode ini menebak nama kolom dari baris pertama file input: John, Doe, 5, "None", bukan "FirstName, lastname," dan seterusnya ...
SingleNegationElimination
Pilihan yang lebih baik, yang ini benar-benar mem-parsing CSV untuk bidang yang diinginkan (tidak hanya dalam urutan, seperti pada jawaban yang ditandai)
GarciadelCastillo
Saya mendapatkan pesan kesalahan yang mengatakanTypeError: expected string or buffer
CodyBugstein