Wie konvertiere ich eine CSV-Datei in mehrzeiliges JSON?


98

Hier ist mein Code, wirklich einfaches Zeug ...

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)

Deklarieren Sie einige Feldnamen, der Leser verwendet CSV zum Lesen der Datei und die Dateinamen zum Speichern der Datei in ein JSON-Format. Hier ist das Problem ...

Jeder Datensatz in der CSV-Datei befindet sich in einer anderen Zeile. Ich möchte, dass die JSON-Ausgabe genauso ist. Das Problem ist, dass alles auf eine riesige, lange Schlange gestellt wird.

Ich habe versucht, so etwas wie zu verwenden for line in csvfile:und dann meinen Code unter dem Code auszuführen, mit reader = csv.DictReader( line, fieldnames)dem jede Zeile durchlaufen wird, aber es wird die gesamte Datei in einer Zeile ausgeführt und dann die gesamte Datei in einer anderen Zeile durchlaufen ... wird fortgesetzt, bis keine Zeilen mehr vorhanden sind .

Irgendwelche Vorschläge zur Korrektur?

Bearbeiten: Zur Verdeutlichung habe ich derzeit: (jeden Datensatz in Zeile 1)

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

Was ich suche: (2 Datensätze in 2 Zeilen)

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

Nicht jedes einzelne Feld wird in einer separaten Zeile eingerückt, sondern jeder Datensatz in einer eigenen Zeile.

Einige Beispieleingaben.

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

Ich bin nicht sicher, ob Ihr Code genau das tut , was Sie sagen. es sollte [{..row..},{..row..},...]nicht produzieren {..row..}{..row..}... Das heißt, die Ausgabe sieht so aus, als wäre es ein JSON-Array von JSON-Objekten, kein Stream von nicht verbundenen JSON-Objekten.
SingleNegationElimination

Antworten:


143

Das Problem mit Ihrer gewünschten Ausgabe ist, dass es sich nicht um ein gültiges JSON-Dokument handelt. Es ist ein Strom von JSON-Dokumenten !

Das ist in Ordnung, wenn es das ist, was Sie brauchen, aber das bedeutet, dass Sie für jedes Dokument, das Sie in Ihrer Ausgabe haben möchten, anrufen müssen json.dumps.

Da die neue Zeile, in der Sie Ihre Dokumente trennen möchten, nicht in diesen Dokumenten enthalten ist, müssen Sie sie selbst bereitstellen. Wir müssen also nur die Schleife aus dem Aufruf von json.dump ziehen und für jedes geschriebene Dokument Zeilenumbrüche einfügen.

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
Perfekt! Tut mir leid, dass Sie ein bisschen Gedanken lesen mussten, um es zu bekommen, und danke für die Korrekturen / Klarstellungen. Genau das habe ich gesucht.
BeanBagKing

4
aber das Problem ist outfile ist kein gültiger json
MONTYHS

1
@MONTYHS: Die erste Aussage dieser Antwort erklärt, dass outfile kein json-Dokument ist. und was es stattdessen ist. Haben Sie ein anderes Problem als die Person, die diese Frage gestellt hat?
SingleNegationElimination

6
@ abhi1610: Wenn Sie einen Header in der Eingabe erwarten, sollten Sie den DictReaderohne fieldnamesArgument konstruieren . Anschließend wird die erste Zeile gelesen, um die Feldnamen aus der Datei abzurufen.
SingleNegationElimination

1
Und es ist gut, Codierung für Ihre Dateien hinzuzufügen csvfile = open('file.csv', 'r',encoding='utf-8') und jsonfile = open('file.json', 'w',encoding='utf-8')
Marek Bernád

21

Sie können Pandas DataFrame verwenden, um dies mit dem folgenden Beispiel zu erreichen:

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

Ich nahm die Antwort von @ SingleNegationElimination und vereinfachte sie zu einem Dreiliner, der in einer Pipeline verwendet werden kann:

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)

Dokumentation von json.dumps ()


6

Sie können versuchen , diese

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)

Bearbeiten:

Einfacherer Ansatz

import csvmapper

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

converter = csvmapper.JSONConverter(parser)

print converter.doConvert(pretty=True)

3
Ich denke, Sie sollten zumindest ausdrücklich erwähnen, dass Sie ein Modul eines Drittanbieters verwenden csvmapper, um dies zu tun (und möglicherweise, wo Sie es bekommen können), im Gegensatz zu etwas Eingebautem.
Martineau

2

Fügen Sie den indentParameter zu hinzujson.dumps

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

Beachten Sie auch, dass Sie einfach json.dumpmit dem offenen verwenden können jsonfile:

json.dump(data, jsonfile)

Nicht ganz das, wonach ich suche. Ich habe meine ursprüngliche Frage bearbeitet, um die gewünschte Ausgabe zu verdeutlichen und anzuzeigen. Vielen Dank für den Tipp, dies kann später nützlich sein.
BeanBagKing

2

Ich sehe, dass dies alt ist, aber ich brauchte den Code von SingleNegationElimination, aber ich hatte ein Problem mit den Daten, die keine utf-8-Zeichen enthielten. Diese tauchten in Feldern auf, mit denen ich mich nicht allzu sehr beschäftigte, und ich beschloss, sie zu ignorieren. Dies erforderte jedoch einige Anstrengungen. Ich bin neu in Python, also habe ich es mit einigem Ausprobieren zum Laufen gebracht. Der Code ist eine Kopie von SingleNegationElimination mit der zusätzlichen Behandlung von utf-8. Ich habe versucht, es mit https://docs.python.org/2.7/library/csv.html zu tun, aber am Ende gab ich auf. Der folgende Code hat funktioniert.

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

Wie wäre es, wenn Sie Pandas verwenden, um die CSV-Datei in einen DataFrame ( pd.read_csv ) einzulesen , dann die Spalten zu bearbeiten , wenn Sie möchten (sie löschen oder Werte aktualisieren) und den DataFrame schließlich wieder in JSON ( pd.DataFrame.to_json ) zu konvertieren .

Hinweis: Ich habe nicht überprüft, wie effizient dies sein wird, aber dies ist definitiv eine der einfachsten Möglichkeiten, eine große CSV zu manipulieren und in JSON zu konvertieren.


0

Als leichte Verbesserung der Antwort von @MONTYHS, die durch eine Reihe von Feldnamen iteriert:

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)

Wenn ich versuche, dies zu verwenden, erhalte ich "KeyError: 'FirstName'". Es scheint nicht, dass der Schlüssel hinzugefügt wird. Ich bin mir nicht sicher, was Sie hier genau versuchen, aber ich glaube nicht, dass die Ausgabe dem entspricht, wonach ich suche, da Sie denselben Einzug = 4 wie Wayne verwenden. Welche Ausgabe sollte ich erwarten? Ich habe meinen ursprünglichen Beitrag bearbeitet, um zu verdeutlichen, wonach ich suche.
BeanBagKing

Der Schlüsselfehler ist höchstwahrscheinlich darauf zurückzuführen, dass dieser Code kein Header-Argument an DictReaderübergibt, sodass die Feldnamen aus der ersten Zeile der Eingabedatei erraten werden: John, Doe, 5, "None" anstelle von "FirstName, lastname" und so weiter ...
SingleNegationElimination

Bessere Option, diese analysiert tatsächlich die CSV für die gewünschten Felder (nicht nur in der Reihenfolge, wie in der markierten Antwort)
GarciadelCastillo

Ich erhalte eine Fehlermeldung,TypeError: expected string or buffer
CodyBugstein
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.