안녕하세요.😊
오늘은 flask 인메모리에서 파일 업로드/파일 다운로드/zip 파일로 묶는 법/데이터 파일 변환 등에 대해서 작성하겠습니다
회사에서 반복되는 작업을 줄이기 위해 flask로 이를 자동화 하였고
(실제로 사용될 지 여부는 알 수 없으나...개발자적 해결을 시도해봤습니다)
그 과정에서 DB/파일 관리를 줄이고자 하여 모든 파일 관련 작업들을
서버에 따로 저장하지 않고 인메모리에서 진행하도록 했습니다!
파일 업로드
간단하게 file 을 전송할 수 있는 form을 만들었습니다
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action = "http://localhost:8787/file-upload" onSubmit = "return form_submit()" method = "post" enctype="multipart/form-data">
<input type = 'file' name = 'file' id = 'file'/>
<select name = "type">
<option value = "main">main</option>
</select>
<input type = "submit" value = "파일 업로드"/>
</form>
</body>
</html>
그리고 file을 받는 flask 앱을 만들었습니다
참고로 아래 코드는 이해를 돕기 위해 flask 에서 file을 받는 부분을 제외한 부분은 생략 했습니다
from flask import Flask, request, send_file
...(생략)
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 #file 최대 크기
api = Api(app)
@app.route('/file-upload', methods=['POST'])
def file_upload():
...(생략)
try:
file_storage = request.files['file']
except (Exception) as error:
print(error)
return "file 첨부 여부 및 api key값이 명확한지 확인해주세요"
if type == 'main' or type == 'sub':
if file_storage and file_storage.filename != '':
... (생략)
if __name__ == "__main__":
...(생략)
validation에는 아래와 같은 함수들을 사용했습니다
def file_validation(filename):
ALLOWED_EXTENSIONS = set(['xlsx', 'csv'])
file_extension = filename.rsplit('.', 1)[1]
return '.' in filename and file_extension in ALLOWED_EXTENSIONS , file_extension
def file_process(file_storage):
is_file_allowed, extension = file_validation(file_storage.filename)
...(생략)
위와 같은 방식으로 파일 업로드를 진행할 수 있었습니다
파일 변환
이후 file storage에서 file을 읽고 이를 excel, csv 파일로 변환했습니다
def file_process(file_storage):
is_file_allowed, extension = file_validation(file_storage.filename)
if not is_file_allowed:
raise Exception("xlsx, csv 파일만 허용됩니다")
file = file_storage.read()
return file, extension
def file_read(file, extension):
if extension == 'xlsx' or extension == 'xls':
return pd.read_excel(file, sheet_name = None)
elif extension == 'csv':
return pd.read_csv(file, sheet_name = None)
dataFrame -> file 객체
from pandas import DataFrame
import pandas as pd
import io
def export_dataframe_to_excel(dataFrame:DataFrame, sheet_name:str, org_file_extension:str):
try:
output = io.BytesIO()
excel_result = pd.ExcelWriter(output)
dataFrame.to_excel(excel_result, sheet_name = sheet_name)
excel_result.save()
output.seek(0)
file = output.read()
return file
file 객체 합쳐서 zipfile로 만들기
import zipfile
def file_list_to_zip_file(file_list):
file_folder = io.BytesIO()
with zipfile.ZipFile(file_folder, 'w') as zip_folder:
if file_list:
for file, file_name in file_list:
try:
if file and file_name:
zip_folder.writestr(file_name, file)
except (Exception) as error:
print(error)
file_folder.seek(0)
return file_folder
file download 구현(zip file)
@app.route('/file-upload', methods=['POST'])
def file_upload():
...(생략)
try:
return send_file(file, download_name= 'file이름' + '.zip')
except (Exception) as error:
print(error)
return str(error)
위와 같은 과정을 거쳐 flask에서 파일 처리 등을 진행할 수 있었습니다
참고로 위 프로젝트에서는 아래와 같은 라이브러리들을 사용했습니다
python:3 이용(docker), flask
postgresql 이용
pip 버전 정보
pandas : 1.4.3
openpyxl : 3.0.10
pyyaml : 6.0
psycopg2 : 2.9.3
flask : 2.1.2
flask_restx : 0.5.1
(위 코드들에서 다루어지지 않은 라이브러리도 있으니 참고해서 사용하시면 될 듯 합니다
글이 누군가에게는 도움이 되었으면 좋겠습니다
그럼 모두 즐거운 코딩 하세요!
(●'◡'●)