Jak przekonwertować plik CSV na wielowierszowy JSON?


98

Oto mój kod, naprawdę proste rzeczy ...

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)

Zadeklaruj niektóre nazwy pól, czytnik używa CSV do odczytania pliku, a nazwy plików do zrzucenia pliku do formatu JSON. Oto problem ...

Każdy rekord w pliku CSV znajduje się w innym wierszu. Chcę, aby dane wyjściowe JSON były takie same. Problem w tym, że zrzuca to wszystko na jedną wielką, długą linię.

Próbowałem użyć czegoś podobnego, for line in csvfile:a następnie uruchomić mój kod poniżej tego, z reader = csv.DictReader( line, fieldnames)którym pętla przechodzi przez każdą linię, ale robi cały plik w jednej linii, a następnie przechodzi przez cały plik w innej linii ... kontynuuje, dopóki nie skończą się linie .

Jakieś sugestie, jak to naprawić?

Edycja: Aby wyjaśnić, obecnie mam: (każdy rekord w linii 1)

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

Czego szukam: (2 rekordy w 2 liniach)

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

Nie każde pole jest wcięte / w osobnym wierszu, ale każdy rekord w osobnym wierszu.

Niektóre przykładowe dane wejściowe.

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

nie jestem pewien, czy twój kod robi dokładnie to , co mówisz; powinien produkować [{..row..},{..row..},...]nie {..row..}{..row..}... Oznacza to, że dane wyjściowe wyglądają na tablicę json obiektów json, a nie strumień niepołączonych obiektów json.
— SingleNegationElimination

Odpowiedzi:


146

Problem z żądanym wyjściem polega na tym, że nie jest to prawidłowy dokument json; to strumień dokumentów json !

W porządku, jeśli tego potrzebujesz, ale oznacza to, że dla każdego dokumentu, który chcesz umieścić w wyniku, będziesz musiał zadzwonić json.dumps.

Ponieważ nowa linia, którą chcesz oddzielić dokumenty, nie jest zawarta w tych dokumentach, jesteś na haku, aby dostarczyć go samodzielnie. Musimy więc po prostu wyciągnąć pętlę z wywołania json.dump i wstawić nowe linie dla każdego napisanego dokumentu.

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
Idealny! Przepraszam, że musiałeś trochę poczytać w myślach, aby to uzyskać, i dzięki za poprawki / wyjaśnienia. To jest dokładnie to, czego szukałem.
— BeanBagKing

4
ale problem polega na tym, że plik
— wyjściowy

1
@MONTYHS: Pierwsze zdanie tej odpowiedzi wyjaśnia, że ​​plik wyjściowy nie jest dokumentem json; i co to jest zamiast tego. Czy masz inny problem niż osoba, która zadała to pytanie?
— SingleNegationElimination

6
@ abhi1610: jeśli spodziewasz się nagłówka na wejściu, powinieneś skonstruować DictReaderbez podawania fieldnamesargumentu; odczyta wtedy pierwszą linię, aby pobrać nazwy pól z pliku.
— SingleNegationElimination

2
I dobrze jest dodać kodowanie do swoich plików csvfile = open('file.csv', 'r',encoding='utf-8') i jsonfile = open('file.json', 'w',encoding='utf-8')
— Marek Bernád

22

Aby to osiągnąć, możesz użyć Pandas DataFrame, korzystając z następującego przykładu:

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

Dokumentacja json.dumps ()


Prawidłowa odpowiedź, imho.
— JohnnyFromBF

9

Wziąłem odpowiedź @ SingleNegationElimination i uprościłem ją do trzyliniówki, której można używać w potoku:

import csv
import json
import sys

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

6

Możesz tego spróbować

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)

Edytować:

Prostsze podejście

import csvmapper

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

converter = csvmapper.JSONConverter(parser)

print converter.doConvert(pretty=True)

3
Myślę, że powinieneś przynajmniej wyraźnie wspomnieć, że używasz modułu innej firmy csvmapper, aby to zrobić (i być może skąd go wziąć), w przeciwieństwie do czegoś wbudowanego.
— martineau

2

Dodaj indentparametr dojson.dumps

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

Pamiętaj również, że możesz po prostu użyć json.dumpz otwartym jsonfile:

json.dump(data, jsonfile)

Niezupełnie to, czego szukam. Zredagowałem moje oryginalne pytanie, aby wyjaśnić i pokazać pożądane wyniki. Dziękuję jednak za wskazówkę, może się później przydać.
— BeanBagKing

2

Widzę, że to jest stare, ale potrzebowałem kodu z SingleNegationElimination, ale miałem problem z danymi zawierającymi znaki inne niż utf-8. Pojawiły się one w dziedzinach, którymi się specjalnie nie przejmowałem, więc zdecydowałem się je zignorować. Jednak wymagało to pewnego wysiłku. Jestem nowy w Pythonie, więc dzięki kilku próbom i błędom udało mi się go uruchomić. Kod jest kopią SingleNegationElimination z dodatkową obsługą utf-8. Próbowałem to zrobić z https://docs.python.org/2.7/library/csv.html, ale w końcu się poddałem. Poniższy kod zadziałał.

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

Co powiesz na użycie Pandas do odczytania pliku csv do DataFrame ( pd.read_csv ), a następnie manipulowanie kolumnami, jeśli chcesz (upuszczanie ich lub aktualizowanie wartości) i wreszcie przekonwertowanie DataFrame z powrotem na JSON ( pd.DataFrame.to_json ).

Uwaga: nie sprawdziłem, jak wydajne będzie to, ale jest to zdecydowanie jeden z najłatwiejszych sposobów manipulowania i konwertowania dużego pliku csv na json.


0

Jako niewielkie ulepszenie odpowiedzi @MONTYHS, iteracja przez krotkę nazw pól:

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)

Kiedy próbuję tego użyć, otrzymuję komunikat „KeyError: 'FirstName'”. Wygląda na to, że klucz nie jest dodawany. Nie jestem pewien, co dokładnie próbujesz tutaj zrobić, ale nie sądzę, aby wynik był zgodny z tym, czego szukam, ponieważ używasz tego samego wcięcia = 4 co Wayne. Jakiego wyniku powinienem się spodziewać? Zredagowałem mój oryginalny post, aby wyjaśnić, czego szukam.
— BeanBagKing

Błąd klucza jest najprawdopodobniej spowodowany tym, że ten kod nie przekazuje argumentu nagłówka do DictReader, więc zgaduje nazwy pól z pierwszego wiersza pliku wejściowego: Jan, Kowalski, 5, „Brak” zamiast „Imię, nazwisko” i tak dalej ...
— SingleNegationElimination

Lepsza opcja, ten faktycznie analizuje plik CSV pod kątem żądanych pól (nie tylko w kolejności, jak w zaznaczonej odpowiedzi)
— GarciadelCastillo

TypeError: expected string or buffer
— Pojawia
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.