2013-05-26 5 views
7

सीखने के प्रयोजनों के लिए, मैं पाइथन + फ्लास्क का उपयोग कर एक साइट बना रहा हूं। मैं डेटाबेस से एक छवि को पुनर्प्राप्त करना चाहता हूं और इसे स्क्रीन पर दिखाऊंगा। लेकिन एक समय में एक कदम।पोस्टग्रेज़ डेटाबेस पर छवि फ़ाइल को कैसे सहेजना है?

मुझे नहीं पता कि मेरे डेटाबेस में पहली बार किसी छवि को कैसे सहेजना है। मेरी खोजों ने केवल यह खुलासा किया कि मुझे अपने डेटाबेस में bytea प्रकार का उपयोग करना है। तो मुझे अपनी छवि मिलती है और किसी भी तरह (??) इसे बाइट्स (बाइट्स == काटने की सरणी) में परिवर्तित कर देती है और किसी भी तरह (??) इस सरणी को एक सम्मिलित कमांड में उपयोग करती है।

मैं जावा (here) और सी # (here) में इसे कैसे करना (शायद) खोज सकता था, लेकिन मैं वास्तव में कम से कम पाइथन का उपयोग करना चाहता हूं।

क्या कोई मेरी मदद कर सकता है?

इस साइट में इस तरह के कई प्रश्न हैं। लेकिन उनमें से अधिकतर (आसानी से 85% से अधिक) को उत्तर दिया जाता है, "आपको अपने डेटाबेस में छवियों को सहेजना नहीं चाहिए, वे एफएस में हैं" और सवाल का जवाब देने में असफल रहे। बाकी मेरी समस्या को हल नहीं करते हैं। तो अगर डुप्लिकेट के इस तरह का जवाब है तो कृपया इसे डुप्लिकेट के रूप में चिह्नित न करें।

+0

बाइटा के अलावा, "बड़ी वस्तुओं" का उपयोग करने का विकल्प भी है। [मैन्युअल के लिंक के साथ विकल्पों की एक सूची यहां दी गई है।] (Http://stackoverflow.com/questions/7434530/storing-long-binary-raw-data-strings/7439642#7439642) हालांकि कोई पायथन विशिष्ट समाधान नहीं है। –

+0

ठीक है, कोई पायथन विशिष्ट नहीं है। तो आम तौर पर बोलते हुए, मुझे छवि के साथ क्या करना है? फ़ाइल प्राप्त करें और इसे एक स्ट्रिंग में बदल दें?स्ट्रिंग प्राप्त करें और इसे बाइनरी बनाएं? जो मुझे समझ में नहीं आता है वह आपके fs में "image.jpg" के बीच होता है और इसके बाइट डेटा को होता है। –

उत्तर

20

मैं सामान्य रूप से लोगों के लिए पूर्ण उदाहरण कार्यक्रमों लिखना नहीं है, लेकिन आप यह मांग नहीं की थी और यह तुम जाओ एक बहुत साधारण एक है, तो यहाँ:

#!/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) 

पायथन 3.3 के साथ लिखा गया। पायथन 2.7 का उपयोग करना आवश्यक है कि आप फ़ाइल को पढ़ लें और buffer ऑब्जेक्ट में कनवर्ट करें या बड़े ऑब्जेक्ट फ़ंक्शंस का उपयोग करें। Python 2.6 और पुराने में कनवर्ट करने के लिए Argparse की स्थापना की आवश्यकता है, शायद अन्य परिवर्तन।

यदि आप परीक्षण करने जा रहे हैं तो आप अपने सिस्टम के लिए उपयुक्त कुछ डेटाबेस कनेक्शन स्ट्रिंग को बदलना चाहेंगे।

आप बड़े चित्र के साथ काम कर रहे हैं psycopg2's large object support बजाय bytea उपयोग करने पर विचार - विशेष रूप से, दुकान के लिए lo_import, lo_export एक फाइल करने के लिए सीधे लिखने के लिए, और बड़ी वस्तु एक समय में छवि के छोटे-छोटे टुकड़ों को पढ़ने के लिए कार्यों को पढ़ने ।

+0

बढ़िया! यही वही है जो मैं ढूंढ रहा था! मैंने पिछले जवाब के बाद डेटाबेस में एक फ़ाइल डालने का प्रबंधन किया था, लेकिन इसे पुनर्प्राप्त करने का प्रयास करते समय भी मैं खो गया था। जैसा कि मैं पाइथन 2.7 का उपयोग कर रहा हूं, मुझे एक बफर ऑब्जेक्ट का उपयोग करना होगा, जैसा कि आपने कहा था, लेकिन वे उपयोग करने के लिए बहुत जटिल लग रहे हैं! मैं इसके बारे में कुछ शोध करूंगा। धन्यवाद, यह वास्तव में सहायक था! –

+0

@FelipeMatos ... या आप Python3 को अपडेट कर सकते हैं ;-) –

+0

@FelipeMatos इसके अलावा, ध्यान रखें कि ऊपर दिया गया उदाहरण डेटाबेस से लोड की गई छवि को फ़ाइल में सहेजता है, तो आप इसे आसानी से बफर से लोड कर सकते हैं प्रदर्शन के लिए एक पीआईएल छवि, इसे एक http क्लाइंट, आदि को भेजें। आपको इसे डिस्क पर लिखने की बहुत ही कम आवश्यकता है - और यदि आप करते हैं, तो आप आम तौर पर 'tempfile.TemporaryFile' का उपयोग करेंगे। –

0

आप पाइथन के base64 का उपयोग एन्कोडिंग और टेक्स्ट स्ट्रिंग में मनमाने ढंग से बाइनरी तारों को डीकोड करने के लिए कर सकते हैं।

+0

आप कर सकते हैं, लेकिन यह वास्तव में सही जवाब नहीं है। डेटाबेस कुशलतापूर्वक 'बाइटा' फ़ील्ड में बाइनरी डेटा संग्रहीत करता है, इसलिए बेस 64 एन्कोडिंग यह पूरी तरह से अनावश्यक है। –

3

मुझे आशा है कि यह आपके लिए काम करेगा।

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 Image

+0

ठीक है, मैंने कोशिश की और * लगभग * काम किया। भविष्य के संदर्भ के लिए, मैंने पहले [यहां] पाइथन छवि लाइब्रेरी स्थापित की है (http://www.lfd.uci.edu/~gohlke/pythonlibs/)। मैं आपके कोड के साथ एक क्वेरी चलाने में सक्षम था (जो एक महान संकेत है), लेकिन मेरा डेटाबेस यूएफटी -8 है, इसलिए मुझे एन्कोडिंग के साथ समस्याएं मिलीं। एन्कोडिंग के लिए निर्देशित थोड़ा सा शोध के बाद, मैंने पाया कि (आश्चर्य!) Psycopg इस तरह के ऑपरेशन का समर्थन करता है, ठीक [यहां] (http://initd.org/psycopg/docs/usage.html#adapt-binary)। मैं उन चरणों के बाद प्रविष्टि डालने का प्रबंधन करता हूं, अब मुझे यह पता लगाना होगा कि इसे कैसे पुनर्प्राप्त किया जाए। –

+1

वास्तव में पीआईएल में छवि को लोड करने की कोई आवश्यकता नहीं है, आपको केवल फ़ाइल को पढ़ने और डीबी में स्टोर करने की आवश्यकता है। फिर भी, एक उपयोगी उदाहरण के लिए +1। –

+0

@ क्रेग्रिंजर आप सही हैं। लेकिन अगर छवि को थंबनेल के रूप में संशोधित और संग्रहीत किया जाता है। मुझे लगता है कि यह उपयोगी होगा। :) – iraycd

3
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() 
+0

जब मैं इसे आजमा रहा हूं, तो मुझे '*** टाइपरर मिल रहा है: बाईरी ' – user208859

+0

को डेटा कास्टिंग' psycopg2 'पर कास्ट नहीं कर सकता। बाइनरी' मेरे लिए कुंजी थी, धन्यवाद! – Matt

0

मेरी समाधान है कि, यह मेरी वेबसाइट में काम कर सकते हैं:

@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 %} 

यह HTML फ़ाइल है। आप इसे HTML में एम्बेड कर सकते हैं।

संबंधित मुद्दे