El archivo CSV escrito con Python tiene líneas en blanco entre cada fila

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)

Este código lee thefile.csv, realiza cambios y escribe resultados thefile_subset1.

Sin embargo, cuando abro el csv resultante en Microsoft Excel, ¡hay una línea en blanco adicional después de cada registro!

¿Hay alguna manera de hacer que no ponga una línea en blanco adicional?

l --''''''--------- '' '' '' '' '' ''
fuente
44
Confirme que esto sucede cuando ejecuta ese código en Windows
John Machin
Vea la respuesta en este hilo: stackoverflow.com/questions/3348460/…
Febin Mathew

Respuestas:

887

En Python 2, abra outfilecon modo en 'wb'lugar de 'w'. Las csv.writerescrituras \r\nen el archivo directamente. Si no se abre el archivo en binario modo, escribirá \r\r\nporque en Windows texto modo se traducirá cada uno \nen \r\n.

En Python 3, la sintaxis requerida cambió (consulte los enlaces de documentación a continuación), por lo tanto, abra outfilecon el parámetro adicional newline=''(cadena vacía).

Ejemplos:

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

Enlaces de documentación

Mark Tolonen
fuente
1
De todos modos, la respuesta de @Mark Tolonen resolvió muchas preguntas relacionadas con las líneas adicionales agregadas al guardar un archivo de texto estándar (no se utiliza csv).
dlewin
1
Para compatibilidad entre 2.6 / 2.7 y 3, puede usar io.opencon el newlinesargumento. Si todavía está escribiendo en 2.x, parece una mejor opción de todos modos, ya que es compatible con versiones anteriores.
jpmc26
@ jpmc26 Normalmente ese es un buen consejo, pero el módulo csv no funciona correctamente io.open. Hay un unicodecsvmódulo de terceros para Python 2.7 que funciona mejor.
Mark Tolonen
¿Alguna idea de por qué el newline=''truco no funciona en python3 con StringIO o TemporaryFile?
fmoo
@fmoo define "no funciona". Ambos trabajan como yo esperaba. StringIOalmacena los mismos puntos de código que se codificarían en un archivo y TemporaryFileadmite el newlineparámetro, por lo que puede abrirse como con open. Haga una pregunta con un programa de muestra que no funciona.
Mark Tolonen
65

Abrir el archivo en modo binario "wb" no funcionará en Python 3+. O más bien, tendría que convertir sus datos a binario antes de escribirlos. Eso es solo una molestia.

En cambio, debe mantenerlo en modo texto, pero anular la nueva línea como vacía. Al igual que:

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

La respuesta simple es que los archivos csv siempre deben abrirse en modo binario, ya sea para entrada o salida, ya que de lo contrario en Windows hay problemas con el final de la línea. Específicamente en la salida, el módulo csv escribirá \r\n(el terminador de fila CSV estándar) y luego (en modo de texto) el tiempo de ejecución reemplazará \npor \r\n(el terminador de línea estándar de Windows) dando un resultado de \r\r\n.

Jugar con el lineterminatorNO es la solución.

John Machin
fuente
¿Cuál es este "estándar" CSV del que hablas?
Dan Breslau
3
@Dan: Usé "estándar" como un adjetivo, no un sustantivo, que significa "habitual" o "lugar común". Si desea una aproximación a un estándar (sustantivo), lea tools.ietf.org/html/rfc4180
John Machin el
1
El punto es (como implica) que no hay un estándar. Esa RFE es informativa. Si bien \ r \ n puede ser "estándar" en Windows, estoy seguro de que las aplicaciones de Unix generalmente no lo ven de esa manera.
Dan Breslau
2
@Dan: Eso es correcto, no hay un estándar. Las secuencias de comandos deben especificar el lineterminator [debería haberse denominado ROWterminator] que desean (si no es el predeterminado) y seguir utilizando el modo binario en caso de que la secuencia de comandos se ejecute en Windows; de lo contrario, el "lineterminator" puede estar lleno.
John Machin
8

Nota: Parece que esta no es la solución preferida debido a cómo se agregó la línea adicional en un sistema Windows. Como se indica en el documento de Python :

Si csvfile es un objeto de archivo, debe abrirse con el indicador 'b' en las plataformas donde eso marca la diferencia.

Windows es una de esas plataformas donde eso hace la diferencia. Si bien cambiar el terminador de línea como describí a continuación puede haber solucionado el problema, el problema podría evitarse por completo abriendo el archivo en modo binario. Se podría decir que esta solución es más "elegante". "Jugar" con el terminador de línea probablemente habría resultado en un código no portable entre sistemas en este caso, donde abrir un archivo en modo binario en un sistema Unix no tiene ningún efecto. es decir. da como resultado un código compatible de sistema cruzado.

De Python Docs :

En Windows, 'b' agregado al modo abre el archivo en modo binario, por lo que también hay modos como 'rb', 'wb' y 'r + b'. Python en Windows distingue entre archivos de texto y binarios; Los caracteres de fin de línea en los archivos de texto se alteran automáticamente ligeramente cuando se leen o escriben los datos. Esta modificación detrás de escena de los datos de archivos está bien para los archivos de texto ASCII, pero corromperá datos binarios como ese en archivos JPEG o EXE. Tenga mucho cuidado de usar el modo binario al leer y escribir dichos archivos. En Unix, no está de más agregar una 'b' al modo, por lo que puede usarlo independientemente de la plataforma para todos los archivos binarios.

Original :

Como parte de los parámetros opcionales para csv.writer, si obtiene líneas en blanco adicionales, es posible que deba cambiar el terminador de línea (información aquí ). Ejemplo a continuación adaptado de la página de Python csv docs. Cámbielo de '\ n' a lo que sea. Como esto es solo una puñalada en la oscuridad del problema, esto puede o no funcionar, pero es mi mejor suposició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'])
Derek Litz
fuente
Estaba a punto de publicar sobre esto: lineterminator = '\ n' funcionó para mí en una prueba simple.
Dan Breslau
¿puedo hacer esto? con abierto ('/ pythonwork / thefile_subset11.csv', 'w'), lineterminator = '\ n' como outfile:
l --''''''--------- '' '' ' '' '' '' '
1
@I__: Realmente deberías comenzar a leer los documentos de Python. Derek te dio el enlace: docs.python.org/library/csv.html
Dan Breslau
5

Estoy escribiendo esta respuesta wrt para python 3, ya que inicialmente tuve el mismo problema.

Se suponía que debía obtener datos de arduino usando PySerialy escribirlos en un archivo .csv. Cada lectura en mi caso terminó con '\r\n', por lo que la nueva línea siempre separaba cada línea.

En mi caso, la newline=''opción no funcionó. Porque mostró algún error como:

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

ValueError: illegal newline value: ''

Por lo tanto, parece que no aceptan la omisión de nueva línea aquí.

Al ver una de las respuestas aquí solo, mencioné el terminador de línea en el objeto escritor, como,

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

y eso funcionó para mí por omitir las nuevas líneas adicionales.

Debanjan Dey
fuente
2
Esto es incorrecto. with open('my_file.csv', 'a',newline='') as csvfile: Funciona absolutamente bien. El problema con su respuesta es que aquí está escribiendo en ' 'lugar de''
Nasrin
2
with open(destPath+'\\'+csvXML, 'a+') as csvFile:
    writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
    writer.writerows(xmlList)

El "lineterminator = '\ r'" permite pasar a la siguiente fila, sin una fila vacía entre dos.

SheRa
fuente
1

Tomando prestado de esta respuesta , parece que la solución más limpia es usar io.TextIOWrapper. Logré resolver este problema por mí mismo de la siguiente manera:

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)

La respuesta anterior no es compatible con Python 2. Para tener compatibilidad, supongo que uno simplemente necesitaría envolver toda la lógica de escritura en un ifbloque:

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

Utilice el método definido a continuación para escribir datos en el archivo CSV.

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

Simplemente agregue un newline=''parámetro adicional dentro del openmétodo:

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

¡Esto escribirá filas CSV sin crear filas adicionales!

Febin Mathew
fuente
-1

Cuando se usa Python 3, se pueden evitar las líneas vacías usando el módulo de códecs . Como se indica en la documentación, los archivos se abren en modo binario, por lo que no es necesario cambiar el newline kwarg. Me encontré con el mismo problema recientemente y eso funcionó para mí:

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