Làm thế nào để chuyển đổi tệp CSV sang JSON đa dòng?


98

Đây là mã của tôi, những thứ thực sự đơn giản ...

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)

Khai báo một số tên trường, trình đọc sử dụng CSV để đọc tệp và các tên đã phân loại để kết xuất tệp sang định dạng JSON. Đây là vấn đề ...

Mỗi bản ghi trong tệp CSV nằm trên một hàng khác nhau. Tôi muốn đầu ra JSON giống như vậy. Vấn đề là nó dồn tất cả vào một hàng dài, khổng lồ.

Tôi đã thử sử dụng một cái gì đó như for line in csvfile:và sau đó chạy mã của tôi bên dưới reader = csv.DictReader( line, fieldnames)mà lặp lại qua từng dòng, nhưng nó thực hiện toàn bộ tệp trên một dòng, sau đó lặp qua toàn bộ tệp trên dòng khác ... tiếp tục cho đến khi hết dòng .

Bất kỳ đề xuất để sửa chữa điều này?

Chỉnh sửa: Để làm rõ, hiện tại tôi có: (mọi bản ghi trên dòng 1)

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

Những gì tôi đang tìm kiếm: (2 bản ghi trên 2 dòng)

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

Không phải mỗi trường riêng lẻ được thụt lề / trên một dòng riêng biệt, mà mỗi bản ghi trên dòng riêng của nó.

Một số mẫu đầu vào.

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

tôi không chắc mã của bạn làm đúng như những gì bạn nói; nó nên sản xuất [{..row..},{..row..},...]không {..row..}{..row..}... Có nghĩa là, đầu ra trông giống như một mảng json của các đối tượng json, không phải một dòng các đối tượng json không được kết nối.
SingleNegationElimination

Câu trả lời:


143

Vấn đề với đầu ra mong muốn của bạn là nó không phải là tài liệu json hợp lệ ,; đó là một dòng tài liệu json !

Điều đó không sao, nếu nó là thứ bạn cần, nhưng điều đó có nghĩa là đối với mỗi tài liệu bạn muốn trong đầu ra của mình, bạn sẽ phải gọi json.dumps.

Vì dòng mới mà bạn muốn tách các tài liệu của mình không có trong các tài liệu đó, nên bạn đang ở trong tình trạng tự cung cấp nó. Vì vậy, chúng ta chỉ cần kéo vòng lặp ra khỏi lệnh gọi json.dump và xen kẽ các dòng mới cho mỗi tài liệu được viết.

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
Hoàn hảo! Xin lỗi, bạn đã phải đọc một chút suy nghĩ để hiểu được nó, và cảm ơn bạn đã sửa chữa / làm rõ. Điều này thật đúng với gì mà tôi đã tìm kiếm.
BeanBagKing

4
nhưng vấn đề là outfile được không phải là một json hợp lệ
MONTYHS

1
@MONTYHS: Ý kiến ​​đầu tiên của câu trả lời này giải thích rằng outfile không phải là một tài liệu json; và thay vào đó nó là gì. Bạn có đang gặp vấn đề khác với người đã hỏi câu hỏi này không?
SingleNegationElimination

6
@ abhi1610: nếu bạn đang mong đợi một tiêu đề trong đầu vào, bạn nên tạo DictReadermà không đưa ra fieldnamesđối số; sau đó nó sẽ đọc dòng đầu tiên để lấy tên trường từ tệp.
SingleNegationElimination

1
Và nó là tốt để thêm mã hóa cho các tập tin của bạn csvfile = open('file.csv', 'r',encoding='utf-8')jsonfile = open('file.json', 'w',encoding='utf-8')
Marek BERNAD

21

Bạn có thể sử dụng Pandas DataFrame để đạt được điều này, với Ví dụ sau:

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

Tôi đã nhận phản hồi của @ SingleNegationElimination và đơn giản hóa nó thành ba lớp lót có thể được sử dụng trong một đường ống:

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)

Tài liệu về json.dumps ()


6

Bạn có thể thử cái này

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)

Biên tập:

Cách tiếp cận đơn giản hơn

import csvmapper

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

converter = csvmapper.JSONConverter(parser)

print converter.doConvert(pretty=True)

3
Tôi nghĩ ít nhất bạn nên đề cập rõ ràng rằng bạn đang sử dụng mô-đun của bên thứ ba csvmapper, để làm điều này (và có thể lấy nó ở đâu) thay vì một thứ gì đó được tích hợp sẵn.
martineau

2

Thêm indenttham số vàojson.dumps

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

Cũng lưu ý rằng, bạn có thể chỉ cần sử dụng json.dumpvới mở jsonfile:

json.dump(data, jsonfile)

Không hoàn toàn như những gì tôi đang tìm kiếm. Tôi đã chỉnh sửa câu hỏi ban đầu của mình để làm rõ và hiển thị đầu ra mong muốn. Cảm ơn bạn vì mẹo này, điều này có thể hữu ích sau này.
BeanBagKing

2

Tôi thấy điều này đã cũ nhưng tôi cần mã từ SingleNegationElimination tuy nhiên tôi gặp sự cố với dữ liệu chứa các ký tự không phải utf-8. Những điều này xuất hiện trong các lĩnh vực tôi không quá quan tâm nên tôi đã chọn bỏ qua chúng. Tuy nhiên điều đó cần một số nỗ lực. Tôi mới sử dụng python nên với một số thử nghiệm và lỗi, tôi đã làm cho nó hoạt động. Mã này là một bản sao của SingleNegationElimination với việc xử lý thêm utf-8. Tôi đã cố gắng làm điều đó với https://docs.python.org/2.7/library/csv.html nhưng cuối cùng đã bỏ cuộc. Đoạn mã dưới đây đã hoạt động.

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

Làm thế nào về việc sử dụng Pandas để đọc tệp csv thành DataFrame ( pd.read_csv ), sau đó thao tác các cột nếu bạn muốn (bỏ chúng hoặc cập nhật giá trị) và cuối cùng chuyển đổi DataFrame trở lại JSON ( pd.DataFrame.to_json ).

Lưu ý: Tôi chưa kiểm tra mức độ hiệu quả của điều này nhưng đây chắc chắn là một trong những cách dễ nhất để thao tác và chuyển đổi một csv lớn thành json.


0

Như một cải tiến nhỏ đối với câu trả lời @MONTYHS, lặp lại qua một loạt các tên trường:

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)

Khi tôi cố gắng sử dụng cái này, tôi nhận được "KeyError: 'FirstName'". Có vẻ như khóa đang được thêm vào. Tôi không chắc chính xác những gì bạn đang cố gắng thực hiện ở đây, nhưng tôi không nghĩ đầu ra phù hợp với những gì tôi đang tìm kiếm vì bạn sử dụng cùng một thụt lề = 4 như Wayne. Tôi nên mong đợi đầu ra nào? Tôi đã chỉnh sửa bài đăng gốc của mình để làm rõ những gì tôi đang tìm kiếm.
BeanBagKing

Rất có thể lỗi chính là do mã này không chuyển đối số tiêu đề DictReader, vì vậy nó đoán tên trường từ dòng đầu tiên của tệp đầu vào: John, Doe, 5, "Không có" thay vì "FirstName, lastname" và vân vân ...
SingleNegationElimination

Lựa chọn tốt hơn, điều này thực sự phân tích các CSV cho các trường mong muốn (không chỉ theo thứ tự, như trong câu trả lời được đánh dấu)
GarciadelCastillo

Tôi nhận được một lỗi nóiTypeError: expected string or buffer
CodyBugstein
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.