Leer datos de archivos sin guardarlos en Flask

112

Estoy escribiendo mi primera solicitud de matraz. Estoy tratando con cargas de archivos, y básicamente lo que quiero es leer los datos / contenido del archivo cargado sin guardarlo y luego imprimirlo en la página resultante. Sí, asumo que el usuario carga un archivo de texto siempre.

Aquí está la función de carga simple que estoy 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)

En este momento, estoy guardando el archivo, pero lo que necesito es esa 'una' variable para contener el contenido / datos del archivo ... ¿alguna idea?

usuario2480542
fuente

Respuestas:

137

FileStoragecontiene streamcampo. Este objeto debe extender IO o objeto de archivo, por lo que debe contener ready otros métodos similares. FileStoragetambién amplía streamlos atributos del objeto de campo, por lo que puede usarlos file.read()en su lugar file.stream.read(). También puede usar un saveargumento con dstparámetro como StringIOu otro IO o objeto de archivo para copiar FileStorage.streama otro IO o objeto de archivo.

Consulte la documentación: http://flask.pocoo.org/docs/api/#flask.Request.files y http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage .

tbicr
fuente
1
ejemplo rápido:file = request.files.get('file') filetype = magic.from_buffer(file.read(1024))
endolito
7
hola @ user2480542. Me encuentro con el mismo problema. ¿Puede describir cómo leyó el contenido del archivo cargado por el cliente? Estoy llamando a file.read () pero no obtengo nada. ¡Gracias!
tmthyjames
1
@tmthyjames f = request.files['file']coloca el archivo cargado (en la solicitud) en una var ("f"). Luego f.read(), funciona usando el código anterior. ¿Cuándo print f.read()me sale la basura de aspecto correcto en la terminal? Espero que ayude.
Marc
6
Si está cargando un archivo y tiene un flujo binario, puede convertirlo fácilmente en un flujo de texto envolviéndolo en TextIOWrapper: mystring = TextIOWrapper(binary_stream)
Dutch Masters
6
f.read()tampoco me dio nada. Llamar primero f.seek(0)hizo el truco para mí.
w177us
11

Si desea utilizar material de Flask estándar, no hay forma de evitar guardar un archivo temporal si el tamaño del archivo cargado es> 500 kb. Si es menor de 500kb, usará "BytesIO", que almacena el contenido del archivo en la memoria, y si es más de 500kb, almacena el contenido en TemporaryFile () (como se indica en la documentación de werkzeug ). En ambos casos, su secuencia de comandos se bloqueará hasta que se reciba la totalidad del archivo cargado.

La forma más fácil de solucionar esto que he encontrado es:

1) Cree su propia clase IO similar a un archivo en la que realice todo el procesamiento de los datos entrantes

2) En su secuencia de comandos, anule la clase Request con la suya propia:

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

3) Reemplace request_class de Flask con el suyo:

app.request_class = MyRequest

4) Ve a tomar una cerveza :)

Dimitry Miles
fuente
0

Estaba tratando de hacer exactamente lo mismo, abrir un archivo de texto (en realidad, un CSV para Pandas). No quiero hacer una copia, solo quiero abrirlo. El formulario-WTF tiene un buen buscador de archivos, pero luego abre el archivo y crea un archivo temporal, que presenta como un flujo de memoria. Con un poco de trabajo bajo el 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) 
TGanoe
fuente
0

Comparto mi solución (asumiendo que todo ya está configurado para conectarse al cubo de Google en el matraz)

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

Mi publicacion

Directo a Google Bucket en matraz

jamartincelis
fuente
-1

En caso de que queramos volcar el archivo en memoria al disco. Este código se puede utilizar

  if isinstanceof(obj,SpooledTemporaryFile):
    obj.rollover()
lalit
fuente
-1

Simplemente hicimos:

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
Deepak Sharma
fuente
-1

en función

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

en archivo 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>

Triết Nguyễn Vĩnh
fuente