ไฟล์ CSV ที่เขียนด้วย Python มีบรรทัดว่างระหว่างแต่ละแถว


446
import csv

with open('thefile.csv', 'rb') as f:
  data = list(csv.reader(f))
  import collections
  counter = collections.defaultdict(int)

  for row in data:
        counter[row[10]] += 1


with open('/pythonwork/thefile_subset11.csv', 'w') as outfile:
    writer = csv.writer(outfile)
    for row in data:
        if counter[row[10]] >= 504:
           writer.writerow(row)

รหัสนี้อ่านthefile.csv, thefile_subset1ทำให้เกิดการเปลี่ยนแปลงและเขียนผล

อย่างไรก็ตามเมื่อฉันเปิด csv ที่ได้ใน Microsoft Excel จะมีบรรทัดว่างเพิ่มเติมหลังจากบันทึกแต่ละชุด!

มีวิธีทำให้ไม่ใส่บรรทัดว่างพิเศษหรือไม่?


4
โปรดยืนยันว่าสิ่งนี้เกิดขึ้นเมื่อคุณเรียกใช้รหัสนั้นบนWindows
John Machin

สำเนาซ้ำที่เป็นไปได้ของPython 2 CSV writer จะสร้างตัวคั่นบรรทัดผิดบน Windows
John Y

ดูคำตอบในหัวข้อนี้: stackoverflow.com/questions/3348460/…
Febin Mathew

คำตอบ:


887

ในหลาม 2 เปิดoutfileด้วยโหมดแทน'wb' 'w'การcsv.writerเขียน\r\nลงไฟล์โดยตรง หากคุณไม่ได้เปิดแฟ้มในไบนารีโหมดก็จะเขียน\r\r\nเพราะบน Windows ข้อความโหมดจะแปลแต่ละเข้าไป\n\r\n

ใน Python 3 ไวยากรณ์ที่ต้องการเปลี่ยนไป (ดูลิงค์เอกสารด้านล่าง) ดังนั้นให้เปิดoutfileด้วยพารามิเตอร์เพิ่มเติมnewline=''(สตริงว่าง) แทน

ตัวอย่าง:

# Python 2
with open('/pythonwork/thefile_subset11.csv', 'wb') as outfile:
    writer = csv.writer(outfile)

# Python 3
with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:
    writer = csv.writer(outfile)

ลิงค์เอกสาร


1
อย่างไรก็ตามคำตอบของ @Mark Tolonen ได้แก้ไขคำถามมากมายที่เกี่ยวข้องกับบรรทัดพิเศษที่เพิ่มเมื่อบันทึกไฟล์ข้อความมาตรฐาน (ไม่ใช้ csv)
dlewin

1
สำหรับความเข้ากันได้ระหว่าง 2.6 / 2.7 และ 3 คุณสามารถใช้io.openกับnewlinesอาร์กิวเมนต์ หากคุณยังคงเขียนด้วย 2.x ดูเหมือนว่าจะเป็นทางเลือกที่ดีกว่าเพราะมันใช้งานได้จริง
jpmc26

@ jpmc26 ปกติว่าเป็นคำแนะนำที่ดี แต่โมดูล CSV io.openไม่ทำงานอย่างถูกต้องกับ มีunicodecsvโมดูลบุคคลที่สามสำหรับ Python 2.7 ที่ทำงานได้ดีขึ้น
Mark Tolonen

ความคิดใด ๆ ที่ว่าทำไมnewline=''กลอุบายไม่ทำงานใน python3 กับ StringIO หรือ TemporaryFile
fmoo

@fmoo define "ไม่ทำงาน" พวกเขาทำงานอย่างที่ฉันคาดหวัง StringIOบัฟเฟอร์จุดรหัสเดียวกับที่จะได้รับการเข้ารหัสไฟล์และTemporaryFileสนับสนุนพารามิเตอร์ดังนั้นจึงสามารถเปิดได้เช่นเดียวกับnewline openถามคำถามด้วยโปรแกรมตัวอย่างที่ไม่ทำงาน
Mark Tolonen

65

การเปิดไฟล์ในโหมดไบนารี "wb" จะไม่ทำงานใน Python 3+ หรือคุณต้องแปลงข้อมูลของคุณให้เป็นไบนารี่ก่อนที่จะเขียน นั่นเป็นเพียงความยุ่งยาก

แต่คุณควรเก็บไว้ในโหมดข้อความ แต่แทนที่ newline ว่าว่างเปล่า ชอบมาก

with open('/pythonwork/thefile_subset11.csv', 'w', newline='') as outfile:

13

คำตอบง่ายๆคือไฟล์ csv ควรเปิดในโหมดไบนารี่เสมอไม่ว่าจะเป็นอินพุทหรือเอาท์พุทมิฉะนั้นบน Windows มีปัญหากับการสิ้นสุดบรรทัด โดยเฉพาะการส่งออกโมดูล CSV จะเขียน\r\n(เทอร์มิแถว CSV มาตรฐาน) แล้ว (ในโหมดข้อความ) รันไทม์จะเข้ามาแทนที่\nโดย\r\n(เทอร์มิเส้นมาตรฐานของ Windows) \r\r\nให้เป็นผลมาจาก

การเล่นซอlineterminatorไม่ได้เป็นวิธีแก้ปัญหา


CSV "มาตรฐาน" ที่คุณพูดคืออะไร
Dan Breslau

3
@ ด่าน: ฉันใช้ "มาตรฐาน" เป็นคำคุณศัพท์ไม่ใช่คำนามหมายถึง "ปกติ" หรือ "ธรรมดา" หากคุณต้องการการประมาณมาตรฐาน (คำนาม) อ่านtools.ietf.org/html/rfc4180
John Machin

1
จุดคือ (ตามที่คุณบ่งบอก) ว่าไม่มีมาตรฐาน RFE นั้นเป็นข้อมูล แม้ว่า \ r \ n อาจเป็น "มาตรฐาน" บน Windows แต่ฉันแน่ใจว่าโดยทั่วไปแล้วแอปพลิเคชัน Unix จะไม่เห็นอย่างนั้น
Dan Breslau

2
@ ด่าน: ถูกต้อง - ไม่มีมาตรฐาน สคริปต์ควรระบุ lineterminator [ควรมีชื่อว่า ROWterminator] ที่พวกเขาต้องการ (หากไม่ใช่ค่าเริ่มต้น) และยังคงใช้โหมดไบนารีในกรณีที่สคริปต์ทำงานบน Windows มิฉะนั้น "lineterminator" อาจถูกยัดไว้
John Machin

8

หมายเหตุ: ดูเหมือนว่านี่ไม่ใช่โซลูชันที่ต้องการเนื่องจากวิธีการเพิ่มบรรทัดพิเศษในระบบ Windows ตามที่ระบุไว้ในเอกสารหลาม :

หาก csvfile เป็นวัตถุไฟล์จะต้องเปิดด้วยการตั้งค่าสถานะ 'b' บนแพลตฟอร์มที่สร้างความแตกต่าง

Windows เป็นแพลตฟอร์มหนึ่งที่สร้างความแตกต่าง ในขณะที่เปลี่ยน line terminator ดังที่ฉันอธิบายด้านล่างอาจแก้ไขปัญหาได้ปัญหานี้สามารถหลีกเลี่ยงได้ทั้งหมดโดยการเปิดไฟล์ในโหมดไบนารี่ อาจกล่าวได้ว่าวิธีการแก้ปัญหานี้มี "ความสง่างาม" มากกว่า "การเล่นซอ" กับตัวยุติบรรทัดอาจทำให้โค้ดไม่สามารถแปลได้ระหว่างระบบในกรณีนี้โดยที่การเปิดไฟล์ในโหมดไบนารีบนระบบยูนิกซ์นั้นจะไม่มีผลใด ๆ กล่าวคือ มันส่งผลในรหัสเข้ากันได้ข้ามระบบ

จากPython Docs :

บน Windows 'b' ต่อท้ายโหมดจะเปิดไฟล์ในโหมดไบนารีดังนั้นจึงมีโหมดเช่น 'rb', 'wb' และ 'r + b' Python บน Windows สร้างความแตกต่างระหว่างข้อความและไฟล์ไบนารี อักขระสิ้นสุดบรรทัดในไฟล์ข้อความจะเปลี่ยนแปลงโดยอัตโนมัติเล็กน้อยเมื่อมีการอ่านหรือเขียนข้อมูล การปรับเปลี่ยนข้อมูลไฟล์หลังนี้เป็นสิ่งที่ดีสำหรับไฟล์ข้อความ ASCII แต่จะทำให้ข้อมูลไบนารีเสียหายเช่นนั้นในไฟล์ JPEG หรือ EXE ระมัดระวังในการใช้โหมดไบนารีเมื่ออ่านและเขียนไฟล์ดังกล่าว บน Unix ไม่ได้เป็นการยากที่จะผนวก 'b' เข้ากับโหมดดังนั้นคุณจึงสามารถใช้เป็นแพลตฟอร์มได้อย่างอิสระสำหรับไฟล์ไบนารีทั้งหมด

ต้นฉบับ :

ในฐานะที่เป็นส่วนหนึ่งของพารามิเตอร์เสริมสำหรับ csv.writer หากคุณได้รับบรรทัดว่างเปล่าเพิ่มเติมคุณอาจต้องเปลี่ยน lineterminator (ข้อมูลที่นี่ ) ตัวอย่างด้านล่างปรับจากหน้า python csv docs เปลี่ยนจาก '\ n' เป็นอะไรก็ได้ เนื่องจากนี่เป็นเพียงการแทงในที่มืดที่ปัญหานี้อาจหรือไม่อาจใช้งานได้ แต่เป็นการคาดเดาที่ดีที่สุดของฉัน

>>> import csv
>>> spamWriter = csv.writer(open('eggs.csv', 'w'), lineterminator='\n')
>>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans'])
>>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])

ฉันกำลังจะโพสต์เกี่ยวกับเรื่องนี้ - lineterminator = '\ n' ทำงานให้ฉันในการทดสอบอย่างง่าย
Dan Breslau

ฉันทำสิ่งนี้ได้ไหม ด้วย open ('/ pythonwork / thefile_subset11.csv', 'w'), lineterminator = '\ n' เป็น outfile:
l

1
@I__: คุณจริงๆควรจะเริ่มต้น perusing เอกสารหลาม Derek ให้ลิงก์แก่คุณ: docs.python.org/library/csv.html
Dan Breslau

5

ฉันเขียนคำตอบนี้ไปที่ python 3 เนื่องจากตอนแรกฉันมีปัญหาเดียวกัน

ฉันควรได้รับข้อมูลจาก arduino โดยใช้PySerialและเขียนลงในไฟล์. csv การอ่านแต่ละครั้งในกรณีของฉันจบลง'\r\n'ดังนั้นการขึ้นบรรทัดใหม่จึงแยกแต่ละบรรทัดเสมอ

ในกรณีของฉันnewline=''ตัวเลือกไม่ทำงาน เนื่องจากพบข้อผิดพลาดบางอย่างเช่น:

with open('op.csv', 'a',newline=' ') as csv_file:

ValueError: illegal newline value: ''

ดังนั้นดูเหมือนว่าพวกเขาไม่ยอมรับการไม่ขึ้นบรรทัดใหม่ที่นี่

เห็นหนึ่งในคำตอบที่นี่เท่านั้นฉันพูดถึงตัวยุติบรรทัดในวัตถุผู้เขียนเช่น

writer = csv.writer(csv_file, delimiter=' ',lineterminator='\r')

และนั่นก็เหมาะกับฉันสำหรับการข้ามบรรทัดใหม่ที่เพิ่มขึ้น


2
สิ่งนี้ไม่ถูกต้อง with open('my_file.csv', 'a',newline='') as csvfile: ทำงานได้ดีอย่างแน่นอน ปัญหากับคำตอบของคุณคือที่นี่คุณกำลังเขียน' 'แทน''
Nasrin

2
with open(destPath+'\\'+csvXML, 'a+') as csvFile:
    writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
    writer.writerows(xmlList)

"lineterminator = '\ r'" อนุญาตให้ส่งผ่านไปยังแถวถัดไปโดยไม่มีแถวว่างระหว่างสอง


1

การกู้ยืมเงินจากคำตอบนี้io.TextIOWrapperดูเหมือนว่าทางออกที่สะอาดคือการใช้งาน ฉันจัดการเพื่อแก้ปัญหานี้สำหรับตัวเองดังนี้

from io import TextIOWrapper

...

with open(filename, 'wb') as csvfile, TextIOWrapper(csvfile, encoding='utf-8', newline='') as wrapper:
    csvwriter = csv.writer(wrapper)
    for data_row in data:
        csvwriter.writerow(data_row)

คำตอบข้างต้นไม่เข้ากันได้กับ Python 2 เพื่อให้มีความเข้ากันได้ฉันคิดว่าหนึ่งจะต้องห่อตรรกะการเขียนทั้งหมดในifบล็อก:

if sys.version_info < (3,):
    # Python 2 way of handling CSVs
else:
    # The above logic

0

ใช้วิธีการที่กำหนดไว้ด้านล่างเพื่อเขียนข้อมูลไปยังไฟล์ CSV

open('outputFile.csv', 'a',newline='')

เพียงเพิ่มnewline=''พารามิเตอร์เพิ่มเติมภายในopenเมธอด:

def writePhoneSpecsToCSV():
    rowData=["field1", "field2"]
    with open('outputFile.csv', 'a',newline='') as csv_file:
        writer = csv.writer(csv_file)
        writer.writerow(rowData)

สิ่งนี้จะเขียนแถว CSV โดยไม่ต้องสร้างแถวเพิ่มเติม!


-1

เมื่อใช้ Python 3 บรรทัดว่างสามารถหลีกเลี่ยงได้โดยใช้โมดูลตัวแปลงสัญญาณ ตามที่ระบุในเอกสารประกอบไฟล์จะถูกเปิดในโหมดไบนารีดังนั้นจึงไม่จำเป็นต้องทำการเปลี่ยนแปลง newline kwarg ฉันพบปัญหาเดียวกันนี้เมื่อไม่นานมานี้และได้ผลกับฉัน:

with codecs.open( csv_file,  mode='w', encoding='utf-8') as out_csv:
     csv_out_file = csv.DictWriter(out_csv)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.