วิธีการแปลงไฟล์ CSV เป็น JSON หลายบรรทัด


100

นี่คือรหัสของฉันสิ่งง่ายๆจริงๆ ...

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

คำตอบ:


149

ปัญหาเกี่ยวกับผลลัพธ์ที่คุณต้องการคือเอกสาร 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

1
@MONTYHS: ประโยคแรกของคำตอบนี้อธิบายว่า outfile ไม่ใช่เอกสาร json และมันคืออะไรแทน คุณกำลังมีปัญหาต่างจากคนที่ถามคำถามนี้หรือไม่?
SingleNegationElimination

6
@ abhi1610: หากคุณคาดหวังส่วนหัวในอินพุตคุณควรสร้างDictReaderโดยไม่ต้องfieldnamesโต้แย้ง จากนั้นจะอ่านบรรทัดแรกเพื่อรับชื่อฟิลด์จากไฟล์
SingleNegationElimination

2
และเป็นการดีที่จะเพิ่มการเข้ารหัสสำหรับไฟล์ของคุณcsvfile = open('file.csv', 'r',encoding='utf-8') และ jsonfile = open('file.json', 'w',encoding='utf-8')
Marek Bernád

24

คุณสามารถใช้ 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')

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)

เอกสารของ json.dumps ()


คำตอบที่ถูกต้อง imho
JohnnyFromBF

คุณต้องเลือกบรรทัดนี้: f.write(json.dumps(data, sort_keys=False, indent=4, separators=(',', ': '))) #for prettyหรือนี่: f.write(json.dumps(data))- ไม่ใช่ทั้งสองอย่าง!
SA

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)

4
ฉันคิดว่าอย่างน้อยคุณควรมีการพูดถึงอย่างชัดเจนว่าคุณกำลังใช้โมดูลของบุคคลที่สามcsvmapperเพื่อทำสิ่งนี้ (และอาจจะหาได้จากที่ใด) ซึ่งตรงข้ามกับสิ่งที่มีอยู่ในตัว
martineau

3

ฉันเห็นว่านี่เก่า แต่ฉันต้องการรหัสจาก 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

2

เพิ่มindentพารามิเตอร์ลงในjson.dumps

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

โปรดทราบว่าคุณสามารถใช้json.dumpกับ open jsonfile:

json.dump(data, jsonfile)

ไม่ใช่สิ่งที่ฉันกำลังมองหา ฉันแก้ไขคำถามเดิมของฉันเพื่อชี้แจงและแสดงผลลัพธ์ที่ต้องการ ขอบคุณสำหรับเคล็ดลับซึ่งอาจมีประโยชน์ในภายหลัง
BeanBagKing

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ดังนั้นจึงเป็นการคาดเดาชื่อฟิลด์จากบรรทัดแรกของไฟล์อินพุต: John, Doe, 5, "None" แทนที่จะเป็น "FirstName, lastname" และ อื่น ๆ ...
SingleNegationElimination

ตัวเลือกที่ดีกว่าอันนี้จะแยกวิเคราะห์ CSV สำหรับฟิลด์ที่ต้องการ (ไม่ใช่ตามลำดับเหมือนในคำตอบที่ทำเครื่องหมายไว้)
GarciadelCastillo

ฉันได้รับข้อผิดพลาดว่าTypeError: expected string or buffer
CodyBugstein
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.