Postgres如何存储文件
postgres提供了两种不同的方式存储二进制,要么是使用bytea类型直接存储二进制,要么就是使用postgres的LargeObject功能;决定使用哪中方式更加适合你,就需要了解这两种存储方式有哪些限制
bytea类型
bytea类型在单列中虽然可以支持1GB的容量,但是还是不建议使用bytea去储存比较大的对象,因为它会占用大量的内存
下面通过一个例子来说明,假如现在要在一个表中存储图片名和该图片的数据,创建表如下:
1
|
CREATE TABLE images (imgname text, img bytea); |
在表中插入一张图片:
1
2
3
4
5
6
7
8
|
File file = new File( "myimage.gif" ); FileInputStream fis = new FileInputStream(file); PreparedStatement ps = conn.prepareStatement( "INSERT INTO images VALUES (?, ?)" ); ps.setString( 1 , file.getName()); ps.setBinaryStream( 2 , fis, file.length()); ps.executeUpdate(); ps. close (); fis. close (); |
上面的setBinaryStream就会将图片内容设置到img字段上面,也可以使用setBytes()直接设置图片的内容
接下来,从表中取出图片,代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
PreparedStatement ps = con.prepareStatement( "SELECT img FROM images WHERE imgname = ?" ); ps.setString( 1 , "myimage.gif" ); ResultSet rs = ps.executeQuery(); if (rs != null) { while (rs.next()) { byte [] imgBytes = rs.getBytes( 1 ); // use the data in some way here } rs. close (); } ps. close (); |
Large Object
Large Object就可以存储大文件,存储的方式是在单独的一张表中存储大文件,然后通过oid在当前表中进行引用;下面通过一个例子来解释:
1
|
CREATE TABLE imageslo (imgname text, imgoid oid); |
首先是创建一张表,该表中第二个字段类型为oid,之后就是通过该字段引用大文件对象;下面我们在表中插入一张图片:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// All LargeObject API calls must be within a transaction block conn.setAutoCommit( false ); // Get the Large Object Manager to perform operations with LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI(); // Create a new large object int oid = lobj.create(LargeObjectManager.READ | LargeObjectManager.WRITE); // Open the large object for writing LargeObject obj = lobj.open(oid, LargeObjectManager.WRITE); // Now open the file File file = new File( "myimage.gif" ); FileInputStream fis = new FileInputStream(file); // Copy the data from the file to the large object byte buf[] = new byte [ 2048 ]; int s, tl = 0 ; while ((s = fis.read(buf, 0 , 2048 )) > 0 ) { obj.write(buf, 0 , s); tl += s; } // Close the large object obj. close (); // Now insert the row into imageslo PreparedStatement ps = conn.prepareStatement( "INSERT INTO imageslo VALUES (?, ?)" ); ps.setString( 1 , file.getName()); ps.setInt( 2 , oid); ps.executeUpdate(); ps. close (); fis. close (); |
在代码中需要使用lobp.open打开一个大文件,然后将图片的内容写入这个对象当中;下面从大文件对象中读取这个图片:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// All LargeObject API calls must be within a transaction block conn.setAutoCommit( false ); // Get the Large Object Manager to perform operations with LargeObjectManager lobj = ((org.postgresql.PGConnection)conn).getLargeObjectAPI(); PreparedStatement ps = con.prepareStatement( "SELECT imgoid FROM imageslo WHERE imgname = ?" ); ps.setString( 1 , "myimage.gif" ); ResultSet rs = ps.executeQuery(); if (rs != null) { while (rs.next()) { // Open the large object for reading int oid = rs.getInt( 1 ); LargeObject obj = lobj.open(oid, LargeObjectManager.READ); // Read the data byte buf[] = new byte [obj.size()]; obj.read(buf, 0 , obj.size()); // Do something with the data read here // Close the object obj. close (); } rs. close (); } ps. close (); |
需要注意的是,对于Large Object的操作都需要放在一个事务(Transaction)当中;如果要删除大文件所在行,在删除这行之后,还需要再执行删除大文件的操作
注:使用Large Object会有安全问题,连接到数据库的用户,即便没有包含大对象所在列的权限,也可以操作这个大对象
Beego orm如何存储图片
看完上面的postgres对于图片的存储,再来看下如何使用beego orm存储一张图片;在beego orm中支持了go的所有基础类型,但是不支持slice;所以,不能直接将[]byte映射到bytea字段上面
好在beego orm提供了一个Fielder接口,可以自定义类型,接口定义如下:
1
2
3
4
5
6
7
|
// Fielder define field info type Fielder interface { String () string FieldType() int SetRaw( interface {}) error RawValue() interface {} } |
所以,现在就需要定义一个字节数组的类型,然后实现这些接口就好了,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
type ByteArrayField [] byte // set value func (e *ByteArrayField) SetRaw(value interface {}) error { if value == nil { return nil } switch d := value.( type ) { case [] byte : *e = d case string : *e = [] byte (d) default : return fmt.Errorf( "[ByteArrayField] unsupported type" ) } return nil } func (e *ByteArrayField) RawValue() interface {} { return *e } // specified type func (f *ByteArrayField) FieldType() int { return orm.TypeTextField } func (f *ByteArrayField) String () string { return string (*f) } |
然后,我们就可以在struct中进行映射了,如下:
1
2
3
4
|
type ImageModel struct { ImageName string `orm: "column(image_name)" ` ImageData ByteArrayField `orm: "column(image_data);type(bytea)" ` } |
这样就可以使用orm的接口操作imageModel,向数据库插入图片,或者从数据库读出图片的内容了
以上就是详解如何使用beego orm在postgres中存储图片的详细内容,更多关于beego orm postgres存储图片的资料请关注服务器之家其它相关文章!
原文链接:https://juejin.cn/post/7225440252910501925