O arquivo CSV gravado com Python possui linhas em branco entre cada linha

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 lê thefile.csv, faz alterações e grava resultados em thefile_subset1.

No entanto, quando abro o csv resultante no Microsoft Excel, há uma linha em branco extra após cada registro!

Existe uma maneira de fazê-lo não colocar uma linha em branco extra?

eu--''''''---------''''''''''''
fonte
4
Confirme que isso acontece quando você executa esse código no Windows
John Machin
Veja a resposta neste tópico: stackoverflow.com/questions/3348460/…
Febin Mathew

Respostas:

887

No Python 2, abra outfilecom mode em 'wb'vez de 'w'. As csv.writergravações \r\nno arquivo diretamente. Se você não abrir o arquivo no modo binário , ele gravará, \r\r\nporque no modo de texto do Windows converterá cada\n em\r\n .

No Python 3, a sintaxe necessária foi alterada (consulte os links de documentação abaixo), então abra outfile com o parâmetro adicional newline=''(string vazia).

Exemplos:

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

Links de documentação

Mark Tolonen
fonte
1
De qualquer forma, a resposta do @Mark Tolonen resolveu muitas perguntas relacionadas às linhas extras adicionadas ao salvar um arquivo de texto padrão (sem csv usado).
dlewin
1
Para compatibilidade entre 2.6 / 2.7 e 3, você pode usar io.opencom o newlinesargumento Se você ainda está escrevendo no 2.x, parece uma escolha melhor, pois é compatível com a frente.
precisa saber é o seguinte
@ jpmc26 Normalmente, esse é um bom conselho, mas o módulo csv não funciona corretamente io.open. Existe um unicodecsvmódulo de terceiros para o Python 2.7 que funciona melhor.
26618 Mark Tolonen
Alguma idéia de por que o newline=''truque não funciona em python3 com StringIO ou TemporaryFile?
fmoo 18/04
@fmoo define "não funciona". Ambos funcionam da maneira que eu esperava. StringIOarmazena em buffer os mesmos pontos de código que seriam codificados em um arquivo e TemporaryFilesuporta o newlineparâmetro, para que possa ser aberto como em open. Faça uma pergunta com um programa de amostra que não está funcionando.
Mark Tolonen 18/04
65

Abrir o arquivo no modo binário "wb" não funcionará no Python 3+. Ou melhor, você teria que converter seus dados em binários antes de escrevê-los. Isso é apenas um aborrecimento.

Em vez disso, você deve mantê-lo no modo de texto, mas substitua a nova linha como vazia. Igual a:

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

A resposta simples é que os arquivos csv sempre devem ser abertos no modo binário, seja para entrada ou saída, caso contrário, no Windows, há problemas com o final da linha. Especificamente na saída, o módulo csv gravará \r\n(o terminador de linha CSV padrão) e, em seguida (no modo de texto), o tempo de execução substituirá o\n by \r\n(o terminador de linha padrão do Windows), resultando em \r\r\n.

Brincar com o lineterminatorNÃO é a solução.

John Machin
fonte
Qual é esse "padrão" CSV do qual você fala?
Dan Breslau
3
@ Dan: Eu usei "standard" como um adjetivo, não um substantivo, significando "usual" ou "comum". Se você deseja uma aproximação a um padrão (substantivo), leia tools.ietf.org/html/rfc4180
John Machin
1
O ponto é (como você sugere) que não existe um padrão. Essa RFE é informativa. Embora \ r \ n possa ser "padrão" no Windows, tenho certeza que os aplicativos Unix normalmente não vêem dessa maneira.
Dan Breslau
2
@ Dan: Isso está correto - não há padrão. Os scripts devem especificar o determinador de linha [deveria ter sido nomeado ROWterminator] que eles desejam (se não o padrão) e ainda usar o modo binário, caso o script seja executado no Windows, caso contrário, o "determinador de linha" pode ser preenchido.
John Machin
8

Nota: Parece que essa não é a solução preferida devido ao modo como a linha extra foi adicionada em um sistema Windows. Conforme declarado no documento python :

Se csvfile é um objeto de arquivo, ele deve ser aberto com o sinalizador 'b' nas plataformas em que isso faz diferença.

O Windows é uma dessas plataformas em que isso faz a diferença. Embora a alteração do terminador de linha, como descrito abaixo, possa ter corrigido o problema, o problema pode ser evitado ao abrir o arquivo no modo binário. Pode-se dizer que esta solução é mais "elegente". "Brincar" com o terminador de linha provavelmente resultaria em código não transportável entre sistemas nesse caso, onde abrir um arquivo no modo binário em um sistema unix não resulta em nenhum efeito. ie resulta em código compatível entre sistemas.

Do Python Docs :

No Windows, 'b' anexado ao modo abre o arquivo no modo binário; também existem modos como 'rb', 'wb' e 'r + b'. O Python no Windows faz uma distinção entre arquivos de texto e binários; os caracteres de fim de linha nos arquivos de texto são automaticamente ligeiramente alterados quando os dados são lidos ou gravados. Essa modificação nos bastidores dos dados dos arquivos é boa para arquivos de texto ASCII, mas corrompe dados binários como os dos arquivos JPEG ou EXE. Tenha muito cuidado ao usar o modo binário ao ler e gravar esses arquivos. No Unix, não custa acrescentar um 'b' ao modo, para que você possa usá-lo independentemente da plataforma para todos os arquivos binários.

Original :

Como parte dos paramaters opcionais para o csv.writer, se você estiver recebendo linhas em branco extras, talvez seja necessário alterar o determinador de linha (informações aqui ). Exemplo abaixo adaptado da página python csv docs. Altere de '\ n' para o que for. Como isso é apenas uma facada no escuro, isso pode ou não funcionar, mas é o meu melhor palpite.

>>> 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
fonte
Eu estava prestes a postar sobre isso - lineterminator = '\ n' funcionou para mim em um teste simples.
Dan Breslau
posso fazer isso? com open ('/ pythonwork / thefile_subset11.csv', 'w'), lineterminator = '\ n' como
arquivo externo
1
@I__: Você realmente deve começar a ler os documentos do Python. Derek deu o link para você: docs.python.org/library/csv.html
Dan Breslau
5

Estou escrevendo esta resposta por escrito para python 3, pois inicialmente eu tenho o mesmo problema.

Eu deveria obter dados do arduino usando PySeriale gravá-los em um arquivo .csv. Cada leitura no meu caso terminava com '\r\n', então a nova linha estava sempre separando cada linha.

No meu caso, a newline=''opção não funcionou. Porque mostrou algum erro como:

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

ValueError: illegal newline value: ''

Portanto, parecia que eles não aceitam a omissão de nova linha aqui.

Vendo apenas uma das respostas aqui, mencionei o terminador de linha no objeto escritor, como,

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

e isso funcionou para mim por pular as novas linhas extras.

Debanjan Dey
fonte
2
Isto está incorreto. with open('my_file.csv', 'a',newline='') as csvfile: funciona absolutamente bem. O problema com a sua resposta é que aqui você está escrevendo ' 'em vez de''
Nasrin
2
with open(destPath+'\\'+csvXML, 'a+') as csvFile:
    writer = csv.writer(csvFile, delimiter=';', lineterminator='\r')
    writer.writerows(xmlList)

O "lineterminator = '\ r'" permite passar para a próxima linha, sem linha vazia entre duas.

SheRa
fonte
1

Tomando emprestado desta resposta , parece que a solução mais limpa é usar io.TextIOWrapper. Consegui resolver esse problema para mim da seguinte maneira:

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)

A resposta acima não é compatível com o Python 2. Para ter compatibilidade, suponho que seria necessário agrupar toda a lógica de escrita em um ifbloco:

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

Use o método definido abaixo para gravar dados no arquivo CSV.

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

Basta adicionar um newline=''parâmetro adicional dentro do openmétodo:

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

Isso gravará linhas CSV sem criar linhas adicionais!

Febin Mathew
fonte
-1

Ao usar o Python 3, as linhas vazias podem ser evitadas usando o módulo codecs . Conforme declarado na documentação, os arquivos são abertos no modo binário, portanto, nenhuma alteração no newwar kwarg é necessária. Eu estava enfrentando o mesmo problema recentemente e isso funcionou para mim:

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