保存图像文件时在Flask中出现错误“ ValueError:读取关闭的文件”

时间:2019-08-16 20:41:20

标签: python flask

我有一个flask应用程序,正在从上载的jpeg文件中读取元数据。然后,它将元数据写入文本文件。我不断收到我正在读取已关闭文件的错误,但我知道我正在打开文件。

我有一个python脚本,可以成功从文件夹中的所有文件读取元数据并将其写入文件。但是,当我将该代码放入Flask应用程序中时,我得到了错误。

我的烧瓶应用程序具有一个python文件:

app.py:

import PIL
import PIL.Image
import PIL.ExifTags
import pandas
import os
from os import path
import shutil
import json
import requests
import datetime
from datetime import datetime
from datetime import timedelta
from flask import Flask , render_template, request

app = Flask(__name__)

a = datetime(1970,1,1,0,1,1)

api_token = 'donotputactualkey'
api_url_base = 'https://api.darksky.net/forecast/'

APP_ROOT = os.path.dirname(os.path.abspath(__file__))

LOG_ROOT = os.path.join(APP_ROOT,'logs')
if not os.path.isdir(LOG_ROOT):
    os.mkdir(LOG_ROOT)


if not path.isfile('logs/ErrorLog.txt'):
    err = open('logs/ErrorLog.txt','a')
    err.write('FileName, ErrorDesc,DateTime \n')
    err.close()
else:
    err = open('logs/ErrorLog.txt','a')



if not path.isfile('logs/PhotoLatLong.txt'):
    log = open('logs/PhotoLatLong.txt','a')
    log.write('FileName,DateTaken,Lat,Long,precipIntensity,PrecipProbability,temperature,apparentTemperature,dewPoint,humidity,pressure,windSpeed,windGust,windBearing,CloudCover,uvIndex,visibility,nearest-station \n')
    log.close()
else:
    log = open('logs/PhotoLatLong.txt','a')


@app.route('/')
def index():
    return render_template('upload.html')

@app.route('/upload', methods = ['GET','POST'])
def upload():
    target = os.path.join(APP_ROOT,'images/')
    print(target)

    if not os.path.isdir(target):
        os.mkdir(target)
    CurDate = str(datetime.now()).split('.')[0]
    if err.closed:
        open(err)
    if log.closed:
        open(log)
    for file in request.files.getlist('file'):
        FileName = file.name
        print(FileName)
        img = PIL.Image.open(file)
        exif_data = img._getexif()
        if 306 not in exif_data.keys():
            print(str(File)+' has no datetime stamp')
            err.write(str(FileName+', No Date found,'+CurDate+'\n'))
            err.close()
        else:
            DateTaken =   exif_data[306]
            ApiDate = DateTaken[:4]+'-'+DateTaken[5:7]+'-'+DateTaken[8:10]+'T'+DateTaken[11:19]
            FileDate = DateTaken[:4]+'-'+DateTaken[5:7]+'-'+DateTaken[8:10]+' '+DateTaken[11:19]
            b = datetime(int(DateTaken[:4]),int(DateTaken[5:7]),int(DateTaken[8:10]),int(DateTaken[11:13]),int(DateTaken[14:16]),int(DateTaken[17:20]))
            newval = exif_data.get(34853)
        if 2 not in newval:
            err.write(str(str(FileName) +', GPS info not found,'+str(datetime.now()).split('.')[0]+'\n'))
            err.close()
        else:
            latdegs = exif_data[34853][2][0][0]
            latmins = exif_data[34853][2][1][0]
            latsecs = exif_data[34853][2][2][0]  / exif_data[34853][2][2][1]
            latcoords = latdegs + latmins/60 + latsecs/3600
            longdegs = exif_data[34853][4][0][0]
            longmins = exif_data[34853][4][1][0]
            longsecs = exif_data[34853][4][2][0]  / exif_data[34853][4][2][1]
            longcoords = longdegs + longmins/60 + longsecs/3600
            longcoords = longcoords * -1
            api_url_latlon = str(latcoords) +','+str(longcoords)
            time = ',' +ApiDate
            response = requests.get(api_url_base+api_token+'/'+api_url_latlon+time)
            dataapi = json.loads(response.content.decode('utf-8'))
            TT = (b-a).total_seconds()
            T1 = dataapi['hourly']['data'][0]['time']
            T2 = dataapi['hourly']['data'][1]['time']
            T3 = dataapi['hourly']['data'][2]['time']
            T4 = dataapi['hourly']['data'][3]['time']
            T5 = dataapi['hourly']['data'][4]['time']
            d = {0:TT-T1, 1:TT-T2, 2:TT-T3, 3:TT-T4, 4:TT-T5}
            k = min(d.items(),key=lambda x: x[1])
            pi = str(dataapi['hourly']['data'][k[0]]['precipIntensity'])
            pp = str(dataapi['hourly']['data'][k[0]]['precipProbability'])
            t = str(dataapi['hourly']['data'][k[0]]['temperature'])
            at = str(dataapi['hourly']['data'][k[0]]['apparentTemperature'])
            dp = str(dataapi['hourly']['data'][k[0]]['dewPoint'])
            hum = str(dataapi['hourly']['data'][k[0]]['humidity'])
            pr = str(dataapi['hourly']['data'][k[0]]['pressure'])
            ws = str(dataapi['hourly']['data'][k[0]]['windSpeed'])
            wg = str(dataapi['hourly']['data'][k[0]]['windGust'])
            wb = str(dataapi['hourly']['data'][k[0]]['windBearing'])
            cc = str(dataapi['hourly']['data'][k[0]]['cloudCover'])
            uv = str(dataapi['hourly']['data'][k[0]]['uvIndex'])
            vi = str(dataapi['hourly']['data'][k[0]]['visibility'])
            log.write(str(str(FileName) +','+str(FileDate)+','+str(latcoords)+','+str(longcoords)+','+pi+','+pp+','+t+','+at+','+dp+','+hum+','+pr+','+ws+','+wb+','+cc+','+uv+','+vi+'\n') )
            img.close()
            log.close()

        print(file)
        filename = file.filename
        destination = '/'.join([target, filename])
        print(destination)
        file.save(destination)

    return render_template('complete.html')


if __name__ == "__main__":
    app.run(debug = True)

期望被重定向到“ complete.html”,但控制台显示此错误:

 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 964-871-100
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
C:\Users\denjs\Documents\UdemyFlaskReview\PicUpload\images/
file
<FileStorage: 'P5040063.JPG' ('image/jpeg')>
C:\Users\denjs\Documents\UdemyFlaskReview\PicUpload\images//P5040063.JPG
127.0.0.1 - - [16/Aug/2019 13:39:02] "POST /upload HTTP/1.1" 500 -
Traceback (most recent call last):
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\app.py", line 2309, in __call__
    return self.wsgi_app(environ, start_response)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\app.py", line 2295, in wsgi_app
    response = self.handle_exception(e)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\app.py", line 1741, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\_compat.py", line 35, in reraise
    raise value
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\_compat.py", line 35, in reraise
    raise value
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\flask\app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Users\denjs\Documents\UdemyFlaskReview\PicUpload\app.py", line 123, in upload
    file.save(destination)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\site-packages\werkzeug\datastructures.py", line 2728, in save
    copyfileobj(self.stream, dst, buffer_size)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\shutil.py", line 79, in copyfileobj
    buf = fsrc.read(length)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\tempfile.py", line 740, in read
    return self._file.read(*args)
  File "C:\Users\denjs\AppData\Local\conda\conda\envs\mynewflaskenv\lib\tempfile.py", line 485, in func_wrapper
    return func(*args, **kwargs)
ValueError: read of closed file
127.0.0.1 - - [16/Aug/2019 13:39:02] "GET /upload?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 -
127.0.0.1 - - [16/Aug/2019 13:39:02] "GET /upload?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 -
127.0.0.1 - - [16/Aug/2019 13:39:02] "GET /upload?__debugger__=yes&cmd=resource&f=jquery.js HTTP/1.1" 200 -
127.0.0.1 - - [16/Aug/2019 13:39:02] "GET /upload?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
127.0.0.1 - - [16/Aug/2019 13:39:02] "GET /upload?__debugger__=yes&cmd=resource&f=ubuntu.ttf HTTP/1.1" 200 -

1 个答案:

答案 0 :(得分:1)

这是因为您已经使用PIL关闭了基础文件对象:

for file in request.files.getlist('file'):
    FileName = file.name
    print(FileName)
    img = PIL.Image.open(file)
    ...
    else:
        ...
        img.close() # <------ 

    # At this point, the file object is already closed.
    file.save(destination)

尝试在获取filefile.save之间删除所有图像元数据处理代码,它应该会成功。

for file in request.files.getlist('file'):
    destination = '/'.join([target, filename])
    file.save(destination)

来自Image.close() docs

  

如果可能,关闭文件指针。

     

此操作将破坏图像核心并释放其内存。的   图片数据以后将无法使用。

这会影响request.files中的FileStorage object,后者本身只是基础文件对象的包装。

由于无论for循环内图像元数据提取发生什么情况,图像文件都被保存,因此只需将其移至for循环的开始即可。

for file in request.files.getlist('file'):
    filename = file.filename
    destination = '/'.join([target, filename])
    file.save(destination)

    FileName = file.name
    img = PIL.Image.open(file)
    # proceed with image data extraction
    ...

    # do not forget to close
    img.close()