web-dev-qa-db-fra.com

Comment convertir un fichier CSV en JSON multiligne?

Voici mon code, des trucs vraiment simples ...

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)

Déclarez certains noms de champs, le lecteur utilise CSV pour lire le fichier et les noms de fichiers pour vider le fichier au format JSON. Voici le problème ...

Chaque enregistrement du fichier CSV se trouve sur une ligne différente. Je veux que la sortie JSON soit la même chose. Le problème, c’est que le tout repose sur une longue et gigantesque ligne.

J'ai essayé d'utiliser quelque chose comme for line in csvfile:, puis d'exécuter mon code ci-dessous avec reader = csv.DictReader( line, fieldnames) qui parcourt chaque ligne, mais le fichier entier est placé sur une ligne, puis en boucle par le biais du fichier entier. ... continue jusqu'à ce qu'il n'y ait plus de lignes.

Des suggestions pour corriger cela?

Edit: pour clarifier, actuellement j'ai: (chaque enregistrement sur la ligne 1)

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

Ce que je recherche: (2 enregistrements sur 2 lignes)

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

Pas chaque champ individuel en retrait/sur une ligne séparée, mais chaque enregistrement sur sa propre ligne.

Quelques exemples d’entrée.

"John","Doe","001","Message1"
"George","Washington","002","Message2"
75
BeanBagKing

Le problème avec votre sortie désirée est qu'il ne s'agit pas d'un document JSON valide; c'est un flux de documents json!

Ce n'est pas grave, si c'est ce dont vous avez besoin, mais cela signifie que pour chaque document que vous voulez dans votre sortie, vous devrez appeler json.dumps.

Comme la nouvelle ligne que vous souhaitez séparer de vos documents ne figure pas dans ces documents, vous êtes sur le point de le fournir vous-même. Il suffit donc de tirer la boucle de l'appel à json.dump et d'interposer des nouvelles lignes pour chaque document écrit.

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')
118

Vous pouvez utiliser Pandas DataFrame pour cela, avec l'exemple suivant:

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)
10
Naufal

J'ai pris la réponse de @ SingleNegationElimination et je l'ai simplifiée en trois lignes pouvant être utilisées dans un pipeline:

import csv
import json
import sys

for row in csv.DictReader(sys.stdin):
    json.dump(row, sys.stdout)
    sys.stdout.write('\n')
8
Lawrence I. Siden
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)

Documentation de json.dumps ()

6
Laxman

Vous pouvez essayer this

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)

Modifier:

Approche plus simple

import csvmapper

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

converter = csvmapper.JSONConverter(parser)

print converter.doConvert(pretty=True)
6
Snork S

Ajoutez le paramètre indent à json.dumps

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

Notez également que vous pouvez simplement utiliser json.dump avec le fichier jsonfile ouvert:

json.dump(data, jsonfile)
2
Wayne Werner

Que diriez-vous d'utiliser Pandas pour lire le fichier csv dans un DataFrame ( pd.read_csv ), puis manipuler les colonnes si vous le souhaitez (les supprimer ou les mettre à jour) et enfin convertir le DataFrame Retour à JSON ( pd.DataFrame.to_json ).

Remarque: Je n’ai pas vérifié son efficacité, mais c’est certainement l’un des moyens les plus simples de manipuler et de convertir un gros fichier .sv en json.

1
impiyush

Je vois que c'est vieux, mais j'avais besoin du code de SingleNegationElimination, mais j'avais un problème avec les données contenant des caractères non-utf-8. Celles-ci sont apparues dans des domaines qui ne me préoccupaient pas trop, alors j'ai choisi de les ignorer. Cependant, cela a pris quelques efforts. Je suis nouveau sur python donc avec quelques essais et erreurs, je l’ai obtenu. Le code est une copie de SingleNegationElimination avec le traitement supplémentaire de utf-8. J'ai essayé de le faire avec https://docs.python.org/2.7/library/csv.html mais à la fin j'ai abandonné. Le code ci-dessous a fonctionné.

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
1
Mark Channing

Comme une légère amélioration à la réponse @MONTYHS, itérant à travers une multitude de noms de champs:

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)
0