Leia os dados do arquivo sem salvá-los no Flask


112

Estou escrevendo meu primeiro pedido de frasco. Estou lidando com uploads de arquivos e basicamente o que desejo é ler os dados / conteúdo do arquivo enviado sem salvá-lo e imprimi-lo na página resultante. Sim, estou assumindo que o usuário sempre carrega um arquivo de texto.

Aqui está a função de upload simples que estou usando:

@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        file = request.files['file']
        if file:
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            a = 'file uploaded'

    return render_template('upload.html', data = a)

No momento, estou salvando o arquivo, mas o que preciso é dessa variável 'a' para conter o conteúdo / dados do arquivo .. alguma ideia?

Respostas:


137

FileStoragecontém o streamcampo. Este objeto deve estender IO ou objeto de arquivo, portanto, deve conter reade outros métodos semelhantes. FileStoragetambém estende streamatributos de objeto de campo, para que você possa apenas usar em seu file.read()lugar file.stream.read(). Além disso, você pode usar o saveargumento com dstparâmetro como StringIOou outro IO ou objeto de arquivo para copiar FileStorage.streampara outro IO ou objeto de arquivo.

Veja a documentação: http://flask.pocoo.org/docs/api/#flask.Request.files e http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage .


1
exemplo rápido:file = request.files.get('file') filetype = magic.from_buffer(file.read(1024))
endolith

7
oi @ user2480542. Estou tendo o mesmo problema. Você pode descrever como leu o conteúdo do arquivo enviado pelo cliente? Estou chamando file.read (), mas não estou recebendo nada. Obrigado!
tmthyjames

1
@tmthyjames f = request.files['file']coloca o arquivo carregado (na solicitação) em um var ("f"). Em f.read()seguida, funciona usando o código acima. quando é print f.read()que recebo o lixo correto procurando no terminal. Espero que ajude.
Marc

6
Se você estiver enviando um arquivo e tiver um fluxo binário, poderá convertê-lo facilmente em um fluxo de texto envolvendo-o em TextIOWrapper: mystring = TextIOWrapper(binary_stream)
Dutch Masters

7
f.read()não rendeu nada para mim também. Ligar primeiro f.seek(0)fez o truque para mim.
w177us

11

Se você quiser usar o Flask padrão - não há como evitar o salvamento de um arquivo temporário se o tamanho do arquivo enviado for> 500kb. Se for menor que 500kb - ele usará "BytesIO", que armazena o conteúdo do arquivo na memória, e se for maior que 500kb - ele armazena o conteúdo em TemporaryFile () (conforme indicado na documentação do werkzeug ). Em ambos os casos, o script será bloqueado até que todo o arquivo carregado seja recebido.

A maneira mais fácil de contornar isso que encontrei é:

1) Crie sua própria classe IO semelhante a um arquivo, onde você faz todo o processamento dos dados de entrada

2) Em seu script, substitua a classe Request pela sua:

class MyRequest( Request ):
  def _get_file_stream( self, total_content_length, content_type, filename=None, content_length=None ):
    return MyAwesomeIO( filename, 'w' )

3) Substitua o request_class do Flask pelo seu:

app.request_class = MyRequest

4) Vá tomar uma cerveja :)


0

Eu estava tentando fazer exatamente a mesma coisa, abrir um arquivo de texto (um CSV para Pandas na verdade). Não quero fazer uma cópia dele, só quero abri-lo. O formulário-WTF tem um bom navegador de arquivos, mas depois abre o arquivo e cria um arquivo temporário, que apresenta como um fluxo de memória. Com um pouco de trabalho sob o capô,

form = UploadForm() 
 if form.validate_on_submit(): 
      filename = secure_filename(form.fileContents.data.filename)  
      filestream =  form.fileContents.data 
      filestream.seek(0)
      ef = pd.read_csv( filestream  )
      sr = pd.DataFrame(ef)  
      return render_template('dataframe.html',tables=[sr.to_html(justify='center, classes='table table-bordered table-hover')],titles = [filename], form=form) 

0

Eu compartilho minha solução (assumindo que tudo já está configurado para se conectar ao balde do google no frasco)

from google.cloud import storage

@app.route('/upload/', methods=['POST'])
def upload():
    if request.method == 'POST':
        # FileStorage object wrapper
        file = request.files["file"]                    
        if file:
            os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = app.config['GOOGLE_APPLICATION_CREDENTIALS']
            bucket_name = "bucket_name" 
            storage_client = storage.Client()
            bucket = storage_client.bucket(bucket_name)
            # Upload file to Google Bucket
            blob = bucket.blob(file.filename) 
            blob.upload_from_string(file.read())

Minha publicação

Direto para o Google Bucket em frasco


-1

No caso de desejarmos despejar o arquivo na memória para o disco. Este código pode ser usado

  if isinstanceof(obj,SpooledTemporaryFile):
    obj.rollover()

-1

Simplesmente fizemos:

import io
from pathlib import Path

    def test_my_upload(self, accept_json):
        """Test my uploads endpoint for POST."""
        data = {
            "filePath[]": "/tmp/bin",
            "manifest[]": (io.StringIO(str(Path(__file__).parent /
                                           "path_to_file/npmlist.json")).read(),
                           'npmlist.json'),
        }
        headers = {
            'a': 'A',
            'b': 'B'
        }
        res = self.client.post(api_route_for('/test'),
                               data=data,
                               content_type='multipart/form-data',
                               headers=headers,
                               )
        assert res.status_code == 200

-1

em função

def handleUpload():
    if 'photo' in request.files:
        photo = request.files['photo']
        if photo.filename != '':      
            image = request.files['photo']  
            image_string = base64.b64encode(image.read())
            image_string = image_string.decode('utf-8')
            #use this to remove b'...' to get raw string
            return render_template('handleUpload.html',filestring = image_string)
    return render_template('upload.html')

em arquivo html

<html>
<head>
    <title>Simple file upload using Python Flask</title>
</head>
<body>
    {% if filestring %}
      <h1>Raw image:</h1>
      <h1>{{filestring}}</h1>
      <img src="data:image/png;base64, {{filestring}}" alt="alternate" />.
    {% else %}
      <h1></h1>
    {% endif %}
</body>

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.