Odczytuj dane pliku bez zapisywania ich w Flask

112

Piszę moją pierwszą aplikację na kolbę. Mam do czynienia z wgrywaniem plików iw zasadzie to czego chcę to odczytać dane / zawartość wgranego pliku bez jego zapisywania a następnie wydrukować na wynikowej stronie. Tak, zakładam, że użytkownik zawsze przesyła plik tekstowy.

Oto prosta funkcja przesyłania, której używam:

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

W tej chwili zapisuję plik, ale potrzebuję zmiennej „a”, która będzie zawierała zawartość / dane pliku… jakieś pomysły?

user2480542
źródło

Odpowiedzi:

137

FileStoragezawiera streampole. Ten obiekt musi rozszerzać IO lub obiekt plik, więc musi zawierać readi inne podobne metody. FileStoragerozszerzaj także streamatrybuty obiektu pola, więc możesz po prostu użyć file.read()zamiast tego file.stream.read(). Możesz również użyć saveargumentu z dstparametrem as StringIOlub innym IO lub obiektem pliku, aby skopiować FileStorage.streamdo innego IO lub obiektu pliku.

Zobacz dokumentację: http://flask.pocoo.org/docs/api/#flask.Request.files i http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage .

tbicr
źródło
1
szybki przykład:file = request.files.get('file') filetype = magic.from_buffer(file.read(1024))
endolit
7
cześć @ user2480542. Mam ten sam problem. Czy możesz opisać, w jaki sposób przeczytałeś zawartość pliku przesłanego przez klienta? Wywołuję file.read (), ale nic nie otrzymuję. Dzięki!
tmthyjames
1
@tmthyjames f = request.files['file']umieszcza przesłany plik (w żądaniu) do var ("f"). Następnie f.read()działa przy użyciu powyższego kodu. kiedy print f.read()mam poprawnie wyglądające śmieci w terminalu. Mam nadzieję, że to pomoże.
Marc
6
Jeśli przesyłasz plik i masz strumień binarny, możesz łatwo przekonwertować go na strumień tekstowy, pakując go w TextIOWrapper: mystring = TextIOWrapper(binary_stream)
Dutch Masters
7
f.read()dla mnie też nic nie dało. Pierwsza f.seek(0)rozmowa załatwiła mi sprawę.
w177us
12

Jeśli chcesz używać standardowych rzeczy z Flask - nie ma sposobu, aby uniknąć zapisywania pliku tymczasowego, jeśli rozmiar przesłanego pliku jest> 500kb. Jeśli jest mniejszy niż 500kb - użyje "BytesIO", które przechowuje zawartość pliku w pamięci, a jeśli jest więcej niż 500kb - przechowuje zawartość w TemporaryFile () (jak podano w dokumentacji werkzeug ). W obu przypadkach Twój skrypt będzie blokowany do momentu odebrania całego przesłanego pliku.

Najłatwiejszym sposobem obejścia tego, który znalazłem, jest:

1) Utwórz własną klasę IO podobną do pliku, w której będziesz przetwarzać wszystkie przychodzące dane

2) W swoim skrypcie zastąp klasę Request własną:

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

3) Zastąp request_class Flask swoim własnym:

app.request_class = MyRequest

4) Idź na piwo :)

Dimitry Miles
źródło
0

Próbowałem zrobić dokładnie to samo, otworzyć plik tekstowy (właściwie CSV dla Pand). Nie chcę robić kopii, po prostu chcę ją otworzyć. Form-WTF ma ładną przeglądarkę plików, ale potem otwiera plik i tworzy plik tymczasowy, który przedstawia jako strumień pamięci. Przy odrobinie pracy pod maską,

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
źródło
0

Udostępniam swoje rozwiązanie (zakładając, że wszystko jest już skonfigurowane do łączenia się z wiadrem Google w kolbie)

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

Mój post

Bezpośrednio do Google Bucket w kolbie

jamartincelis
źródło
-1

Po prostu zrobiliśmy:

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
źródło
-1

w działaniu

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

w pliku 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
źródło
-2

Na wypadek, gdybyśmy chcieli zrzucić plik w pamięci na dysk. Tego kodu można użyć

  if isinstanceof(obj,SpooledTemporaryFile):
    obj.rollover()
lalit
źródło