You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改Flask多文件上传代码 将上传文件读取为脚本可用变量

实现方案

你现有代码的核心问题有两个:一是前端用两个独立表单,一次请求只能上传1个文件,HTTP无状态特性会导致第一次上传的文件在第二次请求时无法被读取;二是后端拿到文件后仅做了磁盘存储,没有读取内容对接原有处理逻辑。按以下步骤修改即可:


1. 修改前端模板button.html

把两个文件选择框合并到同一个表单,给两个文件输入框设置不同的name属性,实现一次提交同时上传两个文件:

<!doctype html>
<title>数据处理文件上传</title>
<h2>上传待处理文件</h2>
<form method="post" action="/" enctype="multipart/form-data">
    <dl>
        <p>
            <label>第一个文件:</label>
            <input type="file" name="file1" autocomplete="off" required accept=".tpi">
        </p>
        <p>
            <label>第二个文件:</label>
            <input type="file" name="file2" autocomplete="off" required accept=".tpi">
        </p>
    </dl>
    <p>
        <input type="submit" value="开始处理并下载CSV">
    </p>
</form>
{% with messages = get_flashed_messages() %}
  {% if messages %}
    <ul class=flashes>
    {% for message in messages %}
      <li>{{ message }}</li>
    {% endfor %}
    </ul>
  {% endif %}
{% endwith %}

说明:补充了原模板缺失的flash消息渲染逻辑,上传报错用户可直接看到提示;加了accept属性限制前端只能选tpi文件,减少非法上传。


2. 修改后端upload.py逻辑

直接读取上传文件的内容,无缝对接你原来的数据处理代码,处理完成后直接返回CSV文件供下载,不需要额外存临时文件:

import os
import pandas as pd
from flask import Flask, flash, request, redirect, render_template, make_response
from werkzeug.utils import secure_filename

app = Flask(__name__)
app.secret_key = "随便填一个随机字符串即可"  # flash功能必须配置密钥
ALLOWED_EXTENSIONS = {'tpi'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

# 原有数据处理函数,不需要做任何修改
def parse_value(txt):
    reclines = []
    for line in txt.split('\n'):
        if ':' not in line:
            if reclines:
                yield reclines
                reclines = []
        else:
            reclines.append(line)

def parse_fields(reclines):
    res = {}
    for line in reclines:
        key, val = line.strip().rstrip(',').split(':', 1)
        res[key.strip()] = val.strip()
    return res

@app.route('/', methods=['GET'])
def upload_form():
    return render_template('button.html')

@app.route('/', methods=['POST'])
def upload_file():
    # 校验两个文件是否都上传
    if 'file1' not in request.files or 'file2' not in request.files:
        flash('请同时上传两个文件')
        return redirect(request.url)
    
    f1 = request.files['file1']
    f2 = request.files['file2']

    # 校验文件名非空
    if f1.filename == '' or f2.filename == '':
        flash('请选择两个待上传的文件')
        return redirect(request.url)
    
    # 校验文件格式
    if not (allowed_file(f1.filename) and allowed_file(f2.filename)):
        flash('仅允许上传tpi格式文件')
        return redirect(request.url)
    
    # 直接读取文件内容,和本地open后read的结果完全一致
    # 如果你的文件是gbk编码,把utf-8换成gbk即可
    content = f1.read().decode('utf-8')
    content2 = f2.read().decode('utf-8')

    # 原有数据处理逻辑,不需要修改
    res = []
    for rec in parse_value(content):
        res.append(parse_fields(rec))    

    res2 = []
    for rec in parse_value(content2):
        res2.append(parse_fields(rec))    

    df = pd.json_normalize(res)
    df2 = pd.json_normalize(res2)

    # 替换成你自己的两个DataFrame映射匹配逻辑
    # 示例为简单拼接,按实际业务修改即可
    final_df = pd.concat([df, df2], axis=1)

    # 生成CSV并返回给用户下载
    output = make_response(final_df.to_csv(index=False, encoding='utf-8-sig'))
    output.headers["Content-Disposition"] = "attachment; filename=result.csv"
    output.headers["Content-type"] = "text/csv"
    return output

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

关键说明

  • 不需要把上传的文件先存到服务器磁盘再读取,Flask返回的文件对象是类文件对象,直接调用read()方法就能拿到内容,和你原来本地打开文件的读取结果完全兼容,原有解析函数零修改即可复用。
  • 不要用两个独立表单分两次上传:HTTP协议是无状态的,第一次请求上传的文件不会自动保留到第二次请求,要么用session/临时文件存储第一次上传的内容,要么像示例一样一次传两个,后者实现最简单、用户体验更好。
  • 如果你的tpi文件不是utf-8编码,把decode('utf-8')和CSV导出的encoding参数改成对应编码即可,避免中文乱码。

内容的提问来源于stack exchange,提问作者gcoder

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 21:31:10