Como gravo dados no formato CSV como string (não arquivo)?


119

Quero lançar dados como [1,2,'a','He said "what do you mean?"']uma string formatada em CSV.

Normalmente seria usado csv.writer()para isso, porque ele lida com todos os casos extremos malucos (escape de vírgula, escape de aspas, dialetos CSV, etc.) O problema é que csv.writer()espera a saída para um objeto de arquivo, não para uma string.

Minha solução atual é esta função um tanto hacky:

def CSV_String_Writeline(data):
    class Dummy_Writer:
        def write(self,instring):
            self.outstring = instring.strip("\r\n")
    dw = Dummy_Writer()
    csv_w = csv.writer( dw )
    csv_w.writerow(data)
    return dw.outstring

Alguém pode dar uma solução mais elegante que ainda lide bem com os casos extremos?

Edit: Veja como acabei fazendo isso:

def csv2string(data):
    si = StringIO.StringIO()
    cw = csv.writer(si)
    cw.writerow(data)
    return si.getvalue().strip('\r\n')

2
No Python 3, StringIO()está na iobiblioteca.
Aristide

Respostas:


66

Você pode usar em StringIOvez do seu Dummy_Writer:

Este módulo implementa uma classe semelhante a um arquivo StringIO, que lê e grava um buffer de string (também conhecido como arquivos de memória).

Existe também cStringIO, que é uma versão mais rápida da StringIOaula.


164

Em Python 3:

>>> import io
>>> import csv
>>> output = io.StringIO()
>>> csvdata = [1,2,'a','He said "what do you mean?"',"Whoa!\nNewlines!"]
>>> writer = csv.writer(output, quoting=csv.QUOTE_NONNUMERIC)
>>> writer.writerow(csvdata)
59
>>> output.getvalue()
'1,2,"a","He said ""what do you mean?""","Whoa!\nNewlines!"\r\n'

Alguns detalhes precisam ser alterados um pouco para o Python 2:

>>> output = io.BytesIO()
>>> writer = csv.writer(output)
>>> writer.writerow(csvdata)
57L
>>> output.getvalue()
'1,2,a,"He said ""what do you mean?""","Whoa!\nNewlines!"\r\n'

Bom exemplo. :) Como nota lateral, qual é o comportamento normal ao encontrar novas linhas em um arquivo CSV? É \nnormal ter no meio dos dados, mas \r\nindica o fim de um registro, não importa onde ele apareça? (Supondo que você esteja em uma plataforma que usa \r\ncomo terminador de linha.)
Li-aung Yip

2
Deveria ser output = StringIO.StringIO(), io.StringIO()levantará TypeError: argumento de string esperado, obtido 'str'.
Marboni

2
@Marboni: StringIO desapareceu no Python 3 (que é onde minha solução está escrita), e não posso reproduzir esse erro no Python 2.7.3 - embora receba um TypeError na writer.writerow(...)linha ( unicode argument expected, got 'str'). Vou analisar isso.
Tim Pietzcker

1
@Marboni: Obrigado pelo aviso: encontrei o problema com a ajuda do StackOverflow. No Python 2, você precisa em io.BytesIO()vez de io.StringIO().
Tim Pietzcker

1
@Marboni: No Python 2.7.9 ele funciona com StringIO.StringIO () ou io.BytesIO ().
início de

6

Achei as respostas, no geral, um pouco confusas. Para Python 2, esse uso funcionou para mim:

import csv, io

def csv2string(data):
    si = io.BytesIO()
    cw = csv.writer(si)
    cw.writerow(data)
    return si.getvalue().strip('\r\n')

data=[1,2,'a','He said "what do you mean?"']
print csv2string(data)

2

como eu uso muito isso para transmitir resultados de forma assíncrona de sanic de volta para o usuário como dados csv, escrevi o seguinte trecho para Python 3 .

O snippet permite reutilizar o mesmo buffer StringIo indefinidamente.


import csv
from io import StringIO


class ArgsToCsv:
    def __init__(self, seperator=","):
        self.seperator = seperator
        self.buffer = StringIO()
        self.writer = csv.writer(self.buffer)

    def stringify(self, *args):
        self.writer.writerow(args)
        value = self.buffer.getvalue().strip("\r\n")
        self.buffer.seek(0)
        self.buffer.truncate(0)
        return value + "\n"

exemplo:

csv_formatter = ArgsToCsv()

output += csv_formatter.stringify(
    10,
    """
    lol i have some pretty
    "freaky"
    strings right here \' yo!
    """,
    [10, 20, 30],
)

Confira o uso adicional no github gist: fonte e teste


0
import csv
from StringIO import StringIO
with open('file.csv') as file:
    file = file.read()

stream = StringIO(file)

csv_file = csv.DictReader(stream)

3
Respostas apenas em código são desencorajadas, você deve acrescentar alguns esclarecimentos à sua resposta
Raniz

-1

Esta é a versão que funciona para utf-8. csvline2string para apenas uma linha, sem quebras de linha no final, csv2string para muitas linhas, com quebras de linha:

import csv, io

def csvline2string(one_line_of_data):
    si = BytesIO.StringIO()
    cw = csv.writer(si)
    cw.writerow(one_line_of_data)
    return si.getvalue().strip('\r\n')

def csv2string(data):
    si = BytesIO.StringIO()
    cw = csv.writer(si)
    for one_line_of_data in data:
        cw.writerow(one_line_of_data)
    return si.getvalue()
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.