อ่านข้อมูลไฟล์โดยไม่บันทึกลงใน Flask


112

ฉันกำลังเขียนแอปพลิเคชันขวดแรกของฉัน ฉันกำลังจัดการกับการอัปโหลดไฟล์และโดยพื้นฐานแล้วสิ่งที่ฉันต้องการคืออ่านข้อมูล / เนื้อหาของไฟล์ที่อัปโหลดโดยไม่บันทึกแล้วพิมพ์ในหน้าผลลัพธ์ ใช่ฉันสมมติว่าผู้ใช้อัปโหลดไฟล์ข้อความเสมอ

นี่คือฟังก์ชั่นอัปโหลดง่ายๆที่ฉันใช้:

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

ตอนนี้ฉันกำลังบันทึกไฟล์ แต่สิ่งที่ฉันต้องการคือตัวแปร 'a' เพื่อบรรจุเนื้อหา / ข้อมูลของไฟล์ .. มีความคิดอย่างไร

คำตอบ:


141

FileStorageมีstreamฟิลด์ อ็อบเจ็กต์นี้ต้องขยาย IO หรืออ็อบเจ็กต์ไฟล์ดังนั้นจึงต้องมีreadและวิธีการอื่นที่คล้ายคลึงกัน FileStorageยังขยายstreamแอตทริบิวต์ออบเจ็กต์ฟิลด์ดังนั้นคุณสามารถใช้file.read()แทนfile.stream.read()ได้ นอกจากนี้คุณยังสามารถใช้saveอาร์กิวเมนต์ที่มีdstพารามิเตอร์เป็นStringIOหรือ IO หรืออ็อบเจ็กต์ไฟล์FileStorage.streamอื่นเพื่อคัดลอกไปยัง IO หรืออ็อบเจ็กต์ไฟล์อื่น

เอกสารดู: http://flask.pocoo.org/docs/api/#flask.Request.filesและhttp://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage


1
ตัวอย่างสั้น ๆ :file = request.files.get('file') filetype = magic.from_buffer(file.read(1024))
endolith

7
สวัสดี @ user2480542 ฉันกำลังประสบปัญหาเดียวกัน คุณสามารถอธิบายได้ว่าคุณอ่านเนื้อหาของไฟล์ที่ไคลเอ็นต์อัปโหลดได้อย่างไร ฉันกำลังเรียก file.read () แต่ไม่ได้รับอะไรเลย ขอบคุณ!
tmthyjames

1
@tmthyjames f = request.files['file']ใส่ไฟล์ที่อัปโหลด (ในคำขอ) เป็น var ("f") จากf.read()นั้นทำงานโดยใช้รหัสด้านบน เมื่อไหร่ที่print f.read()ฉันพบขยะที่ถูกต้องในเทอร์มินัล หวังว่าจะช่วยได้
Marc

6
หากคุณกำลังอัปโหลดไฟล์และมีสตรีมไบนารีคุณสามารถแปลงเป็นสตรีมข้อความได้อย่างง่ายดายโดยการห่อใน TextIOWrapper: mystring = TextIOWrapper(binary_stream)
Dutch Masters

7
f.read()ไม่ได้ให้อะไรกับฉันด้วย การโทรครั้งแรกf.seek(0)เป็นเคล็ดลับสำหรับฉัน
177 น.

13

หากคุณต้องการใช้อุปกรณ์ Flask มาตรฐานไม่มีทางหลีกเลี่ยงการบันทึกไฟล์ชั่วคราวได้หากขนาดไฟล์ที่อัปโหลด> 500kb หากมีขนาดเล็กกว่า 500kb จะใช้ "BytesIO" ซึ่งเก็บเนื้อหาไฟล์ไว้ในหน่วยความจำและหากมีขนาดมากกว่า 500kb จะจัดเก็บเนื้อหาใน TemporaryFile () (ตามที่ระบุไว้ในเอกสาร werkzeug ) ในทั้งสองกรณีสคริปต์ของคุณจะบล็อกจนกว่าจะได้รับไฟล์ที่อัปโหลดทั้งหมด

วิธีที่ง่ายที่สุดในการแก้ไขปัญหานี้ที่ฉันพบคือ:

1) สร้างคลาส IO ที่เหมือนไฟล์ของคุณเองซึ่งคุณจะประมวลผลข้อมูลขาเข้าทั้งหมด

2) ในสคริปต์ของคุณให้แทนที่คลาสคำขอด้วยตัวคุณเอง:

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

3) แทนที่ request_class ของ Flask ด้วยของคุณเอง:

app.request_class = MyRequest

4) ไปดื่มเบียร์กันเถอะ :)


0

ฉันพยายามทำสิ่งเดียวกันทุกประการเปิดไฟล์ข้อความ (เป็น CSV สำหรับนุ่นจริง ๆ ) ไม่อยากทำสำเนาก็แค่อยากเปิด form-WTF มีเบราว์เซอร์ไฟล์ที่ดี แต่จากนั้นจะเปิดไฟล์และสร้างไฟล์ชั่วคราวซึ่งจะแสดงเป็นสตรีมหน่วยความจำ ด้วยการทำงานเล็กน้อยภายใต้ประทุน

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

ฉันแบ่งปันวิธีแก้ปัญหาของฉัน (สมมติว่าทุกอย่างได้รับการกำหนดค่าให้เชื่อมต่อกับ google bucket ในขวดแล้ว)

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

โพสต์ของฉัน

ตรงไปที่ Google Bucket ในขวด


-1

เราทำ:

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

ในฟังก์ชัน

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

ในไฟล์ 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>


-2

ในกรณีที่เราต้องการถ่ายโอนไฟล์ในหน่วยความจำไปยังดิสก์ รหัสนี้สามารถใช้ได้

  if isinstanceof(obj,SpooledTemporaryFile):
    obj.rollover()
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.