Come convertire il file CSV in JSON multilinea?


98

Ecco il mio codice, cose davvero semplici ...

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)

Dichiarare alcuni nomi di campo, il lettore utilizza CSV per leggere il file e i nomi archiviati per eseguire il dump del file in un formato JSON. Ecco il problema ...

Ogni record nel file CSV si trova su una riga diversa. Voglio che l'output JSON sia allo stesso modo. Il problema è che scarica tutto su una gigantesca, lunga fila.

Ho provato a utilizzare qualcosa di simile for line in csvfile:e quindi a eseguire il mio codice sotto quello con reader = csv.DictReader( line, fieldnames)cui scorre ogni riga, ma esegue l'intero file su una riga, quindi esegue il ciclo dell'intero file su un'altra riga ... continua fino a quando non si esaurisce le righe .

Qualche suggerimento per correggere questo?

Modifica: per chiarire, attualmente ho: (ogni record sulla riga 1)

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

Cosa sto cercando: (2 record su 2 righe)

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

Non ogni singolo campo rientrato / su una riga separata, ma ogni record sulla propria riga.

Alcuni input di esempio.

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

non sono sicuro che il tuo codice faccia esattamente quello che dici; dovrebbe produrre [{..row..},{..row..},...]non {..row..}{..row..}... Vale a dire, l'output sembra essere un array json di oggetti json, non un flusso di oggetti json non collegati.
SingleNegationElimination

Risposte:


144

Il problema con l'output desiderato è che non è un documento json valido; è un flusso di documenti JSON !

Va bene, se è ciò di cui hai bisogno, ma questo significa che per ogni documento che vuoi nel tuo output, dovrai chiamare json.dumps.

Poiché la nuova riga che desideri separare i tuoi documenti non è contenuta in quei documenti, sei pronto per fornirla tu stesso. Quindi dobbiamo solo estrarre il ciclo dalla chiamata a json.dump e interporre le nuove righe per ogni documento scritto.

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

1
Perfetto! Scusa hai dovuto leggere un po 'nel pensiero per ottenerlo e grazie per le correzioni / chiarimenti. Questo e 'esattamente quello che stavo cercando.
BeanBagKing

4
ma il problema è che outfile non è un json valido
MONTYHS

1
@MONTYHS: La prima frase di questa risposta spiega che outfile non è un documento json; e cos'è invece. Hai un problema diverso dalla persona che ha posto questa domanda?
SingleNegationElimination

6
@ abhi1610: se ti aspetti un'intestazione nell'input, dovresti costruire DictReadersenza fornire un fieldnamesargomento; leggerà quindi la prima riga per ottenere i nomi dei campi dal file.
SingleNegationElimination

1
Ed è bene aggiungere la codifica per i tuoi file csvfile = open('file.csv', 'r',encoding='utf-8') e jsonfile = open('file.json', 'w',encoding='utf-8')
Marek Bernád

21

Puoi utilizzare Pandas DataFrame per ottenere ciò, con il seguente esempio:

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

Ho preso la risposta di @ SingleNegationElimination e l'ho semplificata in un tre righe che può essere utilizzato in una pipeline:

import csv
import json
import sys

for row in csv.DictReader(sys.stdin):
    json.dump(row, sys.stdout)
    sys.stdout.write('\n')

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)

Documentazione di json.dumps ()


6

Puoi provare questo

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)

Modificare:

Approccio più semplice

import csvmapper

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

converter = csvmapper.JSONConverter(parser)

print converter.doConvert(pretty=True)

3
Penso che dovresti almeno menzionare esplicitamente che stai usando un modulo di terze parti csvmapper, per fare questo (e forse dove ottenerlo) invece di qualcosa di integrato.
martineau

2

Aggiungi il indentparametro ajson.dumps

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

Nota anche che puoi semplicemente usare json.dumpcon l'apertura jsonfile:

json.dump(data, jsonfile)

Non è proprio quello che sto cercando. Ho modificato la mia domanda originale per chiarire e mostrare l'output desiderato. Grazie per il suggerimento, potrebbe tornarti utile in seguito.
BeanBagKing

2

Vedo che questo è vecchio ma avevo bisogno del codice di SingleNegationElimination, tuttavia ho avuto problemi con i dati contenenti caratteri non utf-8. Questi sono apparsi in campi di cui non ero particolarmente preoccupato, quindi ho scelto di ignorarli. Tuttavia ciò ha richiesto un certo sforzo. Sono nuovo in Python, quindi con alcuni tentativi ed errori sono riuscito a farlo funzionare. Il codice è una copia di SingleNegationElimination con la gestione extra di utf-8. Ho provato a farlo con https://docs.python.org/2.7/library/csv.html ma alla fine ci ho rinunciato. Il codice seguente ha funzionato.

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

Che ne dici di usare Pandas per leggere il file csv in un DataFrame ( pd.read_csv ), quindi manipolare le colonne se lo desideri (rilasciandole o aggiornando i valori) e infine riconvertendo DataFrame in JSON ( pd.DataFrame.to_json ).

Nota: non ho verificato quanto sarà efficiente, ma questo è sicuramente uno dei modi più semplici per manipolare e convertire un csv di grandi dimensioni in json.


0

Come leggero miglioramento alla risposta @MONTYHS, iterando attraverso un insieme di nomi di campo:

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)

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

Quando provo a usarlo ottengo "KeyError: 'FirstName'". Non sembra che la chiave venga aggiunta. Non sono sicuro di cosa stai cercando di fare qui, ma non penso che l'output corrisponda a quello che sto cercando poiché usi lo stesso rientro = 4 di Wayne. Quale output dovrei aspettarmi? Ho modificato il mio post originale per chiarire cosa sto cercando.
BeanBagKing

L'errore chiave è molto probabile perché questo codice non passa un argomento di intestazione a DictReader, quindi sta cercando di indovinare i nomi dei campi dalla prima riga del file di input: John, Doe, 5, "Nessuno" invece di "FirstName, lastname" e così via ...
SingleNegationElimination

Opzione migliore, questa in realtà analizza il CSV per i campi desiderati (non solo in ordine, come nella risposta contrassegnata)
GarciadelCastillo

Ricevo un errore che diceTypeError: expected string or buffer
CodyBugstein
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.