Як конвертувати CSV-файл у багаторядковий JSON?


98

Ось мій код, дуже прості речі ...

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)

Заявіть деякі імена полів, зчитувач використовує CSV для читання файлу, а імена полів для скидання файлу у формат JSON. Ось проблема ...

Кожен запис у файлі CSV знаходиться в іншому рядку. Я хочу, щоб вихід JSON був таким самим. Проблема в тому, що це все скидає на одну гігантську довгу чергу.

Я спробував використати щось на зразок, for line in csvfile:а потім запустити мій код нижче того, з reader = csv.DictReader( line, fieldnames)яким проходить цикл через кожен рядок, але він робить весь файл в одному рядку, а потім цикл через весь файл в іншому рядку ... продовжується, поки не закінчиться рядки .

Будь-які пропозиції щодо виправлення цього?

Редагувати: Для уточнення, наразі я маю: (кожен запис у рядку 1)

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

Що я шукаю: (2 записи в 2 рядки)

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

Не кожне окреме поле з відступом / на окремому рядку, а кожен запис у своєму власному рядку.

Деякі зразки вводу.

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

я не впевнений, що ваш код робить саме те , що ви говорите; вона повинна виробляти [{..row..},{..row..},...]НЕ {..row..}{..row..}... Тобто результат виглядає так, ніби це буде масив json із об’єктів json, а не потік не пов’язаних об’єктів json.
SingleNegationElimination

Відповіді:


143

Проблема з вашим бажаним результатом полягає в тому, що він не є дійсним json-документом; це потік JSON-документів !

Це нормально, якщо це те, що вам потрібно, але це означає, що для кожного документа, який ви хочете у своєму висновку, вам доведеться зателефонувати json.dumps.

Оскільки новий рядок, який ви хочете розділити між вашими документами, не міститься в цих документах, ви готові подати його самостійно. Тому нам просто потрібно витягнути цикл із виклику json.dump і вставити нові рядки для кожного написаного документа.

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
Ідеально! Вибачте, що вам довелося трохи почитати, щоб отримати його, і дякую за виправлення / роз'яснення. Це саме те, що я шукав.
BeanBagKing

4
але проблема в тому, що outfile не є дійсним json
MONTYHS 07.03.14

1
@MONTYHS: Перший сенс цієї відповіді пояснює, що outfile не є json-документом; і що це натомість. У вас проблема відрізняється від людини, яка задала це запитання?
SingleNegationElimination

6
@ abhi1610: якщо ви очікуєте заголовок у вхідних даних, вам слід побудувати DictReaderбез наведення fieldnamesаргументу; потім він прочитає перший рядок, щоб отримати імена полів із файлу.
SingleNegationElimination

1
І добре додати кодування для своїх файлів csvfile = open('file.csv', 'r',encoding='utf-8') і jsonfile = open('file.json', 'w',encoding='utf-8')
Marek Bernád

21

Ви можете використати Pandas DataFrame для досягнення цього, з наступним прикладом:

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

Я взяв відповідь @ SingleNegationElimination і спростив її до трилінійної лінії, яку можна використовувати в конвеєрі:

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)

Документація json.dumps ()


6

Ви можете спробувати це

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)

Редагувати:

Простіший підхід

import csvmapper

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

converter = csvmapper.JSONConverter(parser)

print converter.doConvert(pretty=True)

3
Я думаю, вам слід, принаймні, прямо вказати, що ви використовуєте сторонній модуль csvmapper, щоб зробити це (і, можливо, де його взяти), на відміну від чогось вбудованого.
martineau

2

Додайте indentпараметр доjson.dumps

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

Також зверніть увагу, що ви можете просто використовувати json.dumpз відкритим jsonfile:

json.dump(data, jsonfile)

Не зовсім те, що я шукаю. Я відредагував своє оригінальне запитання, щоб пояснити і показати бажаний результат. Дякую за пораду, хоча це може стати в нагоді пізніше.
BeanBagKing

2

Я бачу, що це старе, але мені потрібен був код з SingleNegationElimination, однак у мене виникла проблема з даними, що містять символи не utf-8. Вони з’явились у полях, якими я не надто займався, тому я вирішив їх ігнорувати. Однак це потребувало певних зусиль. Я новачок у python, тому з деякими спробами та помилками я змусив його працювати. Код є копією SingleNegationElimination з додатковою обробкою utf-8. Я намагався зробити це за допомогою https://docs.python.org/2.7/library/csv.html, але врешті-решт відмовився. Наведений нижче код спрацював.

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

Як щодо використання Pandas для зчитування CSV-файлу в DataFrame ( pd.read_csv ), потім маніпулювання стовпцями, якщо хочете (скидання їх або оновлення значень) і, нарешті, перетворення DataFrame назад у JSON ( pd.DataFrame.to_json ).

Примітка: Я не перевіряв, наскільки це буде ефективно, але це, безумовно, один з найпростіших способів маніпулювати та перетворити великий CSV у json.


0

Як невелике вдосконалення відповіді @MONTYHS, ітерація через безліч імен полів:

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)

Коли я намагаюся використовувати це, я отримую "KeyError: 'FirstName'". Здається, ключ не додається. Я не впевнений, що саме ви намагаєтесь зробити тут, але я не думаю, що результат відповідає тому, що я шукаю, оскільки ви використовуєте той самий відступ = 4, що і Уейн. Який результат слід очікувати? Я відредагував своє оригінальне повідомлення, щоб пояснити, що я шукаю.
BeanBagKing

Ключова помилка, швидше за все, тому, що цей код не передає аргумент заголовків DictReader, тому він вгадує імена полів із першого рядка вхідного файлу: Джон, Лань, 5, "Немає" замість "Ім'я, прізвище" та так далі ...
SingleNegationElimination

Кращий варіант, цей насправді аналізує CSV для потрібних полів (не лише в порядку, як у позначеній відповіді)
GarciadelCastillo

TypeError: expected string or buffer
Повідомлення
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.