File CSV yang ditulis dengan Python memiliki garis kosong di antara setiap baris

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)

Kode ini membaca thefile.csv, membuat perubahan, dan menulis hasilnya thefile_subset1.

Namun, ketika saya membuka csv yang dihasilkan di Microsoft Excel, ada baris kosong tambahan setelah setiap catatan!

Apakah ada cara untuk membuatnya tidak membuat garis kosong tambahan?

l - '' '' '' '
sumber
4
Harap konfirmasi bahwa ini terjadi ketika Anda menjalankan kode itu di Windows
John Machin
Lihat jawaban di utas ini: stackoverflow.com/questions/3348460/…
Febin Mathew

Jawaban:

887

Dalam Python 2, buka outfiledengan mode 'wb'alih-alih 'w'. The csv.writermenulis \r\nke dalam file secara langsung. Jika Anda tidak membuka file dalam mode biner , itu akan menulis \r\r\nkarena pada mode teks Windows akan menerjemahkan masing \n- masing ke dalam \r\n.

Dalam Python 3 sintaks yang diperlukan berubah (lihat tautan dokumentasi di bawah), jadi buka outfiledengan parameter tambahan newline=''(string kosong).

Contoh:

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

Tautan Dokumentasi

Mark Tolonen
sumber
1
Bagaimanapun jawaban @Mark Tolonen telah menyelesaikan banyak pertanyaan terkait dengan baris tambahan yang ditambahkan ketika menyimpan file teks standar (tidak digunakan csv).
dlewin
1
Untuk kompatibilitas antara 2,6 / 2,7 dan 3, Anda dapat menggunakan io.opendengan newlinesargumen. Jika Anda masih menulis dalam 2.x, itu sepertinya pilihan yang lebih baik karena ini kompatibel ke depan.
jpmc26
@ jpmc26 Biasanya itu saran yang bagus, tetapi modul csv tidak bekerja dengan benar io.open. Ada unicodecsvmodul pihak ke - 3 untuk Python 2.7 yang berfungsi lebih baik.
Mark Tolonen
newline=''Adakah yang tahu mengapa trik ini tidak bekerja di python3 dengan StringIO atau TemporaryFile?
fmoo
@ fmoo mendefinisikan "tidak berfungsi". Mereka berdua bekerja seperti yang saya harapkan. StringIObuffer poin kode yang sama yang akan dikodekan ke file, dan TemporaryFilemendukung newlineparameter, sehingga dapat dibuka seperti open. Ajukan pertanyaan dengan program sampel yang tidak berfungsi.
Mark Tolonen
65

Membuka file dalam mode biner "wb" tidak akan berfungsi dalam Python 3+. Atau lebih tepatnya, Anda harus mengubah data Anda menjadi biner sebelum menulisnya. Itu hanya merepotkan.

Sebagai gantinya, Anda harus menyimpannya dalam mode teks, tetapi menimpa baris baru sebagai kosong. Seperti itu:

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

Jawaban sederhananya adalah bahwa file csv harus selalu dibuka dalam mode biner apakah untuk input atau output, karena jika tidak pada Windows ada masalah dengan baris yang berakhir. Khusus pada output modul csv akan menulis \r\n(terminator baris CSV standar) dan kemudian (dalam mode teks) runtime akan menggantikan \noleh \r\n(terminator jalur standar Windows) memberikan hasil \r\r\n.

Mengotak-atik lineterminatorBUKAN solusinya.

John Machin
sumber
Apa "standar" CSV ini yang Anda gunakan?
Dan Breslau
3
@ Dan: Saya menggunakan "standar" sebagai kata sifat, bukan kata benda, yang berarti "biasa" atau "biasa". Jika Anda ingin aproksimasi ke standar (kata benda), baca tools.ietf.org/html/rfc4180
John Machin
1
Poinnya adalah (seperti yang Anda maksudkan) bahwa tidak ada standar. RFE itu informatif. Walaupun \ r \ n mungkin "standar" pada Windows, saya yakin aplikasi Unix biasanya tidak melihatnya seperti itu.
Dan Breslau
2
@ Dan: Itu benar - tidak ada standar. Skrip harus menentukan lineterminator [seharusnya dinamai ROWterminator] yang mereka inginkan (jika bukan default) dan masih menggunakan mode biner jika skrip dijalankan pada Windows jika tidak, "lineterminator" dapat diisi.
John Machin
8

Catatan: Tampaknya ini bukan solusi yang disukai karena cara garis tambahan ditambahkan pada sistem Windows. Sebagaimana dinyatakan dalam dokumen python :

Jika csvfile adalah objek file, itu harus dibuka dengan tanda 'b' pada platform di mana itu membuat perbedaan.

Windows adalah salah satu platform di mana itu membuat perbedaan. Sementara mengubah terminator garis seperti yang saya jelaskan di bawah ini mungkin telah memperbaiki masalah, masalahnya dapat dihindari sama sekali dengan membuka file dalam mode biner. Orang mungkin mengatakan solusi ini lebih "elegan". "Mengutak-atik" dengan terminator garis kemungkinan akan menghasilkan kode yang tidak dapat diakses antara sistem dalam kasus ini, di mana membuka file dalam mode biner pada sistem unix tidak menghasilkan efek. yaitu. itu menghasilkan kode yang kompatibel lintas sistem.

Dari Python Documents :

Pada Windows, 'b' ditambahkan ke mode membuka file dalam mode biner, jadi ada juga mode seperti 'rb', 'wb', dan 'r + b'. Python pada Windows membuat perbedaan antara teks dan file biner; karakter end-of-line dalam file teks secara otomatis diubah sedikit ketika data dibaca atau ditulis. Modifikasi di belakang layar untuk file data ini baik untuk file teks ASCII, tetapi itu akan merusak data biner seperti itu dalam file JPEG atau EXE. Berhati-hatilah untuk menggunakan mode biner saat membaca dan menulis file seperti itu. Pada Unix, tidak ada salahnya menambahkan 'b' ke mode, sehingga Anda dapat menggunakannya platform-independen untuk semua file biner.

Asli :

Sebagai bagian dari paramaters opsional untuk csv.writer jika Anda mendapatkan baris kosong tambahan Anda mungkin harus mengubah lineterminator (info di sini ). Contoh di bawah ini diadaptasi dari halaman python csv docs. Ubah dari '\ n' menjadi apa pun yang seharusnya. Karena ini hanya tikaman dalam gelap pada masalah ini mungkin atau mungkin tidak berhasil, tapi itu tebakan terbaik saya.

>>> import csv
>>> spamWriter = csv.writer(open('eggs.csv', 'w'), lineterminator='\n')
>>> spamWriter.writerow(['Spam'] * 5 + ['Baked Beans'])
>>> spamWriter.writerow(['Spam', 'Lovely Spam', 'Wonderful Spam'])
Derek Litz
sumber
Saya akan memposting tentang ini - lineterminator = '\ n' bekerja untuk saya dalam tes sederhana.
Dan Breslau
bisakah saya melakukan ini> ?? dengan open ('/ pythonwork / thefile_subset11.csv', 'w'), lineterminator = '\ n' sebagai outfile:
l --''''''''----------------- '' '' ' '' '' '' ''
1
@I__: Anda benar-benar harus mulai meneliti dokumen Python. Derek memberi Anda tautan: docs.python.org/library/csv.html
Dan Breslau
5

Saya menulis jawaban ini ke python 3, karena saya awalnya punya masalah yang sama.

Saya seharusnya mendapatkan data dari arduino menggunakan PySerial, dan menulisnya dalam file .csv. Setiap pembacaan dalam kasus saya berakhir dengan '\r\n', jadi baris baru selalu memisahkan setiap baris.

Dalam kasus saya, newline=''opsi tidak berfungsi. Karena itu menunjukkan beberapa kesalahan seperti:

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

ValueError: illegal newline value: ''

Jadi sepertinya mereka tidak menerima penghilangan baris baru di sini.

Melihat salah satu jawaban di sini saja, saya sebutkan terminator garis dalam objek penulis, seperti,

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

dan itu berhasil bagi saya karena melewatkan baris baru tambahan.

Debanjan Dey
sumber
2
Ini salah. with open('my_file.csv', 'a',newline='') as csvfile: bekerja dengan sangat baik. Masalah dengan jawaban Anda adalah bahwa di sini Anda menulis ' 'alih-alih''
Nasrin
2
with open(destPath+'\\'+csvXML, 'a+') as csvFile:
    writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
    writer.writerows(xmlList)

"Lineterminator = '\ r'" mengizinkan untuk beralih ke baris berikutnya, tanpa baris kosong di antara dua.

SheRa
sumber
1

Meminjam dari jawaban ini , sepertinya solusi terbersih adalah menggunakan io.TextIOWrapper. Saya berhasil memecahkan masalah ini untuk diri saya sebagai berikut:

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)

Jawaban di atas tidak kompatibel dengan Python 2. Untuk memiliki kompatibilitas, saya kira orang hanya perlu membungkus semua logika penulisan dalam sebuah ifblok:

if sys.version_info < (3,):
    # Python 2 way of handling CSVs
else:
    # The above logic
phantom-99w
sumber
0

Gunakan metode yang ditentukan di bawah ini untuk menulis data ke file CSV.

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

Cukup tambahkan newline=''parameter tambahan di dalam openmetode:

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

Ini akan menulis baris CSV tanpa membuat baris tambahan!

Febin Mathew
sumber
-1

Saat menggunakan Python 3, baris kosong dapat dihindari dengan menggunakan modul codec . Sebagaimana dinyatakan dalam dokumentasi, file dibuka dalam mode biner sehingga tidak diperlukan perubahan kwarg baris baru. Saya mengalami masalah yang sama baru-baru ini dan itu berhasil bagi saya:

with codecs.open( csv_file,  mode='w', encoding='utf-8') as out_csv:
     csv_out_file = csv.DictWriter(out_csv)
JBa
sumber