簡體   English   中英

如何在Postgres數據庫中保存圖像文件?

[英]How to save a image file on a Postgres database?

出於學習目的,我正在使用Python + Flask創建一個站點。 我想從數據庫中恢復圖像並在屏幕上顯示。 但是一步一步。

我不知道如何在我的數據庫中保存圖像。 我的搜索只顯示我必須在我的數據庫中使用bytea類型。 然后我得到我的圖像,並以某種方式(?)將其轉換為字節數組(bytea ==數組的咬?)並以某種方式(?)在插入命令中使用此數組。

我能夠發現(也許)如何在Java( 這里 )和C#( 這里 )中做到這一點,但我真的想使用Python,至少現在。

有人能幫我嗎?

這個網站有很多這類問題。 但大多數(很容易超過85%)的回復都是“您不應該在數據庫中保存圖像,它們屬於fs”並且無法回答問題。 其余的並沒有完全解決我的問題。 因此,如果副本有這樣的答案,請不要將其標記為重復。

我通常不會為人們編寫完整的示例程序,但是你沒有要求它,這是一個非常簡單的程序,所以在這里你去:

#!/usr/bin/env python3

import os
import sys
import psycopg2
import argparse

db_conn_str = "dbname=regress user=craig"

create_table_stm = """
CREATE TABLE files (
    id serial primary key,
    orig_filename text not null,
    file_data bytea not null
)
"""

def main(argv):
    parser = argparse.ArgumentParser()
    parser_action = parser.add_mutually_exclusive_group(required=True)
    parser_action.add_argument("--store", action='store_const', const=True, help="Load an image from the named file and save it in the DB")
    parser_action.add_argument("--fetch", type=int, help="Fetch an image from the DB and store it in the named file, overwriting it if it exists. Takes the database file identifier as an argument.", metavar='42')
    parser.add_argument("filename", help="Name of file to write to / fetch from")

    args = parser.parse_args(argv[1:])

    conn = psycopg2.connect(db_conn_str)
    curs = conn.cursor()

    # Ensure DB structure is present
    curs.execute("SELECT 1 FROM information_schema.tables WHERE table_schema = %s AND table_name = %s", ('public','files'))
    result = curs.fetchall()
    if len(result) == 0:
        curs.execute(create_table_stm)

    # and run the command
    if args.store:
        # Reads the whole file into memory. If you want to avoid that,
        # use large object storage instead of bytea; see the psycopg2
        # and postgresql documentation.
        f = open(args.filename,'rb')

        # The following code works as-is in Python 3.
        #
        # In Python 2, you can't just pass a 'str' directly, as psycopg2
        # will think it's an encoded text string, not raw bytes. You must
        # either use psycopg2.Binary to wrap it, or load the data into a
        # "bytearray" object.
        #
        # so either:
        #
        #   filedata = psycopg2.Binary( f.read() )
        #
        # or
        #
        #   filedata = buffer( f.read() )
        #
        filedata = f.read()
        curs.execute("INSERT INTO files(id, orig_filename, file_data) VALUES (DEFAULT,%s,%s) RETURNING id", (args.filename, filedata))
        returned_id = curs.fetchone()[0]
        f.close()
        conn.commit()
        print("Stored {0} into DB record {1}".format(args.filename, returned_id))

    elif args.fetch is not None:
        # Fetches the file from the DB into memory then writes it out.
        # Same as for store, to avoid that use a large object.
        f = open(args.filename,'wb')
        curs.execute("SELECT file_data, orig_filename FROM files WHERE id = %s", (int(args.fetch),))
        (file_data, orig_filename) = curs.fetchone()

            # In Python 3 this code works as-is.
            # In Python 2, you must get the str from the returned buffer object.
        f.write(file_data)
        f.close()
        print("Fetched {0} into file {1}; original filename was {2}".format(args.fetch, args.filename, orig_filename))

    conn.close()

if __name__ == '__main__':
    main(sys.argv)

用Python 3.3編寫。 使用Python 2.7要求您讀取文件並轉換為buffer對象或使用大對象函數。 轉換為Python 2.6及更早版本需要安裝argparse,可能還有其他更改。

如果要進行測試運行,您需要將數據庫連接字符串更改為適合您系統的字符串。

如果您正在使用大圖像,請考慮使用psycopg2的大對象支持而不是bytea - 特別是lo_import用於存儲, lo_export用於直接寫入文件,而大對象讀取函數用於一次讀取圖像的小塊。

我希望這對你有用。

import Image
import StringIO
im = Image.open("file_name.jpg") # Getting the Image
fp = StringIO.StringIO()
im.save(fp,"JPEG")
output = fp.getvalue() # The output is 8-bit String.

StringIO 圖片

import psycopg2
import sys

def readImage():
    try:
        fin = open("woman.jpg", "rb")
        img = fin.read()
        return img

    except IOError, e:
        print "Error %d: %s" % (e.args[0],e.args[1])
        sys.exit(1)

    finally:
        if fin:
            fin.close()
try:
    con = psycopg2.connect(database="testdb", user="abc")
    cur = con.cursor()
    data = readImage()
    binary = psycopg2.Binary(data)
    cur.execute("INSERT INTO images(id, data) VALUES (1, %s)", (binary,) )
    con.commit()
except psycopg2.DatabaseError, e:
    if con:
        con.rollback()
    print 'Error %s' % e    
    sys.exit(1)
finally: 
    if con:
        con.close()

這是我的解決方案,它可以在我的網站上工作:

@main.route('/upload', methods=['GET', 'POST'])
def upload_avatar():
    if request.method == 'POST':
        file = request.files['file']
        if file and allowed_file(file.filename):
            current_user.avatar_local = file.read()
            db.session.add(current_user)
            db.session.commit()
            return redirect(url_for('main.user_page', username=current_user.username))
    return render_template('upload_avatar.html', user=current_user)

使用Flask,Flask-Alchemy來處理數據庫。

{% block edit_avatar  %}
    <form action="" method=post enctype=multipart/form-data>
      <p><input type=file name=file>
         <input type=submit value=Upload>
    </form>
{% endblock %}

這是html文件。你可以將它嵌入你的HTML中。

您可以使用Python的base64將任意二進制字符串編碼和解碼為文本字符串。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM