Python 如何在Postgres数据库中保存图像文件?
出于学习目的,我正在使用Python+Flask创建一个站点。我想从数据库中恢复图像并在屏幕上显示。但是一步一个脚印Python 如何在Postgres数据库中保存图像文件?,python,database,image,postgresql,bytea,Python,Database,Image,Postgresql,Bytea,出于学习目的,我正在使用Python+Flask创建一个站点。我想从数据库中恢复图像并在屏幕上显示。但是一步一个脚印 import psycopg2 import sys def readImage(): try: fin = open("woman.jpg", "rb") img = fin.read() return img except IOError, e: print "Error %d: %s" %
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()
首先,我不知道如何在数据库中保存图像。我的搜索结果显示我必须在数据库中使用bytea
类型。然后我得到我的图像,并以某种方式(?)将其转换为字节数组(bytea==比特数组?),然后以某种方式(?)在insert命令中使用该数组
我能够发现(也许)如何在Java()和C#()中实现这一点,但我真的很想使用Python,至少现在是这样
有人能帮我吗
在这个网站上有很多这样的问题。但其中大多数(很容易超过85%)被回答为“您不应该在数据库中保存图像,它们属于fs”,并且没有回答这个问题。其余的并不能完全解决我的问题。因此,如果副本有此类答案,请不要将其标记为重复。您可以使用Python将任意二进制字符串编码和解码为文本字符串。我希望这对您有用
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.
我通常不会为人们编写完整的示例程序,但您并不要求,而且这是一个非常简单的示例程序,所以您可以这样做:
#!/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编写。使用Python2.7需要读取文件并转换为缓冲区
对象或使用大型对象函数。转换为Python2.6及更早版本需要安装argparse,可能还有其他更改
如果要测试运行数据库连接字符串,则需要将其更改为适合系统的字符串
如果您使用大图像,请考虑使用“代替代码”> ByTea/Cuff>——特别是
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)
使用烧瓶,烧瓶炼金术来处理数据库
{% block edit_avatar %}
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
{% endblock %}
{%block edit_avatar%}
{%endblock%}
这是html文件。您可以将其嵌入html。除了bytea,还可以选择使用“大对象”。但是没有特定于Python的解决方案。好的,没有特定于Python的解决方案。所以一般来说,我和图像有什么关系?获取文件并将其转换为字符串?获取字符串并使其成为二进制?我不明白的是在fs中的“image.jpg”和它的bytea数据之间会发生什么。你可以,但这确实不是正确的答案。数据库有效地将二进制数据存储在
bytea
字段中,因此base64编码完全没有必要。好的,我尝试了这个,几乎成功了。为了将来参考,我首先从安装了Python映像库。我可以用你的代码运行一个查询(这是一个很好的信号),但是我的数据库是UFT-8,所以我发现编码有问题。在对编码进行了一点研究之后,我发现(令人惊讶!)psycopg支持这种操作,对吧。我按照这些步骤插入了条目,现在我必须找到如何恢复它。没有必要在PIL中实际加载图像,您只需要读取文件并将其存储在DB中。然而,+1是一个有用的例子。@CraigRinger你是对的。但是如果图像被修改并存储为缩略图。我想这会有用的伟大的那正是我要找的!根据前面的回答,我已经成功地在数据库中插入了一个文件,但在试图恢复它时仍然丢失了它。当我使用Python2.7时,我必须使用缓冲区对象,正如您所说的,但是它们看起来太复杂了!我要做一些研究。谢谢,这真的很有帮助@FelipeMatos还请记住,虽然上面的示例将从数据库加载的图像保存到文件中,但您也可以轻松地将其从缓冲区加载到PIL图像中进行显示,将其发送到http客户端等。您很少需要将其写入磁盘,如果您这样做,您通常会使用tempfile.TemporaryFile
。当我尝试此操作时,我得到了***类型错误:无法将实例转义为二进制
将数据转换为psycopg2。二进制
是我的关键,谢谢!