如何在java中读取oracle blob

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在java中读取oracle blob相关的知识,希望对你有一定的参考价值。

整个流程分为四步,连接oracle数据库 -> 读取blob图片字段 -> 对图片进行缩放 ->把图片展示在jsp页面上。

下面进行详细描述:
1. java连接Oracle

注:数据库是Oracle10g版本为10.2.0, 在数据库中,图片字段类型为BLOB。

java中通常使用的是通过jdbc驱动来连接数据库,oracle也不例外,因此必须下载一个Oracle驱动的jdbc需要去网上进行下载,名称为 ojdbc14.jar。

下载地址为:

下载了驱动之后,可以使用驱动里提供的接口进行连接,具体代码如下:

import java.sql.*;

import java.io.*;

import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;

import java.awt.image.AffineTransformOp;

import java.awt.geom.AffineTransform;

public class OracleQueryBean

private final String oracleDriverName = "oracle.jdbc.driver.OracleDriver";

private Connection myConnection = null;

/*图片表名*/

private String strTabName;

/*图片ID字段名*/

private String strIDName;

/*图片字段名*/

private String strImgName;

/**

* 加载java连接Oracle的jdbc驱动

*/

public OracleQueryBean()

try

Class.forName(oracleDriverName);

catch(ClassNotFoundException ex)

System.out.println("加载jdbc驱动失败,原因:" + ex.getMessage());





/**

* 获取Oracle连接对象

* @return Connection

*/

public Connection getConnection()

try

//用户名+密码; 以下使用的Test就是Oracle里的表空间

//从配置文件中读取数据库信息

GetPara oGetPara = new GetPara();

String strIP = oGetPara.getPara("serverip");

String strPort = oGetPara.getPara("port");

String strDBName = oGetPara.getPara("dbname");

String strUser = oGetPara.getPara("user");

String strPassword = oGetPara.getPara("password");

this.strTabName = oGetPara.getPara("tablename");

this.strIDName = oGetPara.getPara("imgidname");

this.strImgName = oGetPara.getPara("imgname");

String oracleUrlToConnect ="jdbc:oracle:thin:@"+strIP+":"+strPort+":"+strDBName;

this.myConnection = DriverManager.getConnection(oracleUrlToConnect, strUser, strPassword);

catch(Exception ex)

System.out.println("Can not get connection:" + ex.getMessage());

System.out.println("请检测配置文件中的数据库信息是否正确." );



return this.myConnection;




2. 读取blob字段

在OracleQueryBean类中增加一个函数,来进行读取,具体代码如下:

/**

* 根据图片在数据库中的ID进行读取

* @param strID图片字段ID

* @param w 需要缩到的宽度

* @param h 需要缩到高度

* @return

*/

public byte[] GetImgByteById(String strID, int w, int h)

//System.out.println("Get img data which id is " + nID);

if(myConnection == null)

this.getConnection();

byte[] data = null;

try

Statement stmt = myConnection.createStatement();

ResultSet myResultSet = stmt.executeQuery("select " + this.strIDName + " from " + this.strTabName + " where " + this.strIDName + "=" + strID);

StringBuffer myStringBuffer = new StringBuffer();

if (myResultSet.next())

java.sql.Blob blob = myResultSet.getBlob(this.strImgName);

InputStream inStream = blob.getBinaryStream();

try

long nLen = blob.length();

int nSize = (int) nLen;

//System.out.println("img data size is :" + nSize);

data = new byte[nSize];

inStream.read(data);

inStream.close();

catch (IOException e)

System.out.println("获取图片数据失败,原因:" + e.getMessage());



data = ChangeImgSize(data, w, h);



System.out.println(myStringBuffer.toString());

myConnection.commit();

myConnection.close();

catch (SQLException ex)

System.out.println(ex.getMessage());



return data;



3. 缩放图片

因为图片的大小可能不一致,但是在页面中输出的大小需要统一,所以需要

在OracleQueryBean类中增加一个函数,来进行缩放,具体代码如下:

/**

* 缩小或放大图片

* @param data 图片的byte数据

* @param w 需要缩到的宽度

* @param h 需要缩到高度

* @return 缩放后的图片的byte数据

*/

private byte[] ChangeImgSize(byte[] data, int nw, int nh)

byte[] newdata = null;

try

BufferedImage bis = ImageIO.read(new ByteArrayInputStream(data));

int w = bis.getWidth();

int h = bis.getHeight();

double sx = (double) nw / w;

double sy = (double) nh / h;

AffineTransform transform = new AffineTransform();

transform.setToScale(sx, sy);

AffineTransformOp ato = new AffineTransformOp(transform, null);

//原始颜色

BufferedImage bid = new BufferedImage(nw, nh, BufferedImage.TYPE_3BYTE_BGR);

ato.filter(bis, bid);

//转换成byte字节

ByteArrayOutputStream baos = new ByteArrayOutputStream();

ImageIO.write(bid, "jpeg", baos);

newdata = baos.toByteArray();

catch(IOException e)

e.printStackTrace();



return newdata;



4. 展示在页面

页面使用OracleQueryBean来根据用户提供的图片id进行查询,在读取并进行缩放后,通过jsp页面进行展示,具体代码如下:

<%@ page language="java" contentType="text/html;;charset=gbk" %>

<jsp:useBean id="OrcleQuery" scope="page" class="HLFtiDemo.OracleQueryBean" />

<%

response.setContentType("image/jpeg");

//图片在数据库中的 ID

String strID = request.getParameter("id");

//要缩略或放大图片的宽度

String strWidth = request.getParameter("w");

//要缩略或放大图片的高度

String strHeight = request.getParameter("h");

byte[] data = null;

if(strID != null)

int nWith = Integer.parseInt(strWidth);

int nHeight = Integer.parseInt(strHeight);

//获取图片的byte数据

data = OrcleQuery.GetImgByteById(strID, nWith, nHeight);

ServletOutputStream op = response.getOutputStream();

op.write(data, 0, data.length);

op.close();

op = null;

response.flushBuffer();

//清除输出流,防止释放时被捕获异常

out.clear();

out = pageContext.pushBody();



%>

5. OracleQueryBean查询类的整体代码

OracleQueryBean.java文件代码如下所示:

import java.sql.*;

import java.io.*;

import javax.imageio.ImageIO;

import java.awt.image.BufferedImage;

import java.awt.image.AffineTransformOp;

import java.awt.geom.AffineTransform;

public class OracleQueryBean

private final String oracleDriverName = "oracle.jdbc.driver.OracleDriver";

private Connection myConnection = null;

/*图片表名*/

private String strTabName;

/*图片ID字段名*/

private String strIDName;

/*图片字段名*/

private String strImgName;

/**

* 加载java连接Oracle的jdbc驱动

*/

public OracleQueryBean()

try

Class.forName(oracleDriverName);

catch(ClassNotFoundException ex)

System.out.println("加载jdbc驱动失败,原因:" + ex.getMessage());





/**

* 获取Oracle连接对象

* @return Connection

*/

public Connection getConnection()

try

//用户名+密码; 以下使用的Test就是Oracle里的表空间

//从配置文件中读取数据库信息

GetPara oGetPara = new GetPara();

这文章确实写的不错,你可以看原文
参考技术A byte[] content = null;
java.sql.Blob blob = rs.getBlob("字段名");
if (blob != null)
inStream = blob.getBinaryStream();
bot = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int len = 0;
while ((len = inStream.read(b)) != -1) 
bot.write(b, 0, len);

content = bot.toByteArray();

使用 JAVA 从 Oracle 数据库中读取网络文件

【中文标题】使用 JAVA 从 Oracle 数据库中读取网络文件【英文标题】:read network file from Oracle database using JAVA 【发布时间】:2015-12-11 08:44:13 【问题描述】:

我正在尝试在 Oracle 数据库中创建一个函数,该函数使用 JAVA 类从网络驱动器读取文件并将文件内容作为 BLOB 返回。

到目前为止,这是进展

JAVA 代码 - FileAPI.java

import java.lang.*;
import java.io.*;
import java.sql.*;

public class FileAPI
  
  public static String readFile (String path, Blob[] outLob)
  
    FileInputStream fileStream = null;
    try        
        fileStream = new FileInputStream(path);

        byte[] buffer = new byte[100];
        int i = 0;
        /* for testing just read 100 bytes */
        /* code required for reading full file */
        i = fileStream.read(buffer, 1, 100);        
        outLob[0] = new javax.sql.rowset.serial.SerialBlob(buffer); 

        if(fileStream != null)
                fileStream.close();         

        return "success";
        
    catch (Exception e)        
        return e.getMessage();
        
  
;

Oracle PL/SQL 函数

CREATE OR REPLACE FUNCTION readFile (p_path IN VARCHAR2, p_outlob IN OUT NOCOPY BLOB)
RETURN VARCHAR2
AS LANGUAGE JAVA
NAME 'FileAPI.readFile(
        java.lang.String,
        java.sql.Blob[]) return java.lang.String';

PL/SQL 匿名块来测试上述函数

SET SERVEROUTPUT ON;
DECLARE
    l_temp BLOB;
    l_res VARCHAR2(1000);
BEGIN   
    l_res := readFile('/mnt/servername/foldername/filename.txt',l_temp);
    IF l_res = 'success'
    THEN
        DBMS_OUTPUT.PUT_LINE('Success, length '||dbms_lob.getlength(l_temp));
    ELSE
        DBMS_OUTPUT.PUT_LINE('Error info '|| l_res);
    END IF;
END;
/

当我在块上方运行时,我没有收到任何错误信息。它只是打印“错误信息”。没有打印详细的异常。

有人能指出这里出了什么问题吗?

您还可以建议读取完整文件的内容并将其附加到 JAVA 中的 BLOB 变量 (outLob[0]) 中吗?

JAVA 细节

java 版本“1.7.0_79” Java(TM) SE 运行时环境 (build 1.7.0_79-b15) Java HotSpot(TM) 64 位服务器 VM(内部版本 24.79-b02,混合模式)

Oracle DB - Oracle 11g r2 EE

最好的问候,

[更新的JAVA代码]

import java.lang.*;
import java.io.*;
import java.sql.*;

public class FileAPI
  
  public static String readFile (String path, Blob[] outLob)
  
    FileInputStream fileStream = null;
    Blob tmp = outLob[0];
    try        
        fileStream = new FileInputStream(path);

        byte[] buffer = new byte[100];
        int i = 0;
        /* for testing just read 100 bytes */
        /* code required for reading full file */
        i = fileStream.read(buffer, 0, 100);        
        tmp = new javax.sql.rowset.serial.SerialBlob(buffer);
        outLob[0] = tmp;

        if(fileStream != null)
                fileStream.close();         

        return "success";
        
    catch (Exception e)        
        //return e.getMessage();
        return e.toString();
        
  
;

【问题讨论】:

尝试e.toString() 而不是e.getMessage()。在某些情况下异常消息为空。 感谢您的回复。数组存在一些问题。我已经修好了。现在,当我运行 pl/sql 块时,出现以下错误 ORA-00932:不一致的数据类型:预期位置 2 的 OUT 参数是可转换为 Oracle 类型的用户定义 Java 类的实例,得到了一个不能被转换 在 JAVA 中 Oracle 数据类型 BLOB 的正确数据映射是什么?或者我需要更改我的 JAVA 代码吗? 【参考方案1】:

要直接从 Java 创建 Blob,您必须访问 Connection 对象并告诉数据库通过它创建一个 Blob;然后获取blob对象的输出流并写入它。

import oracle.jdbc.OracleDriver;

import oracle.sql.BLOB;

import java.io.FileInputStream;
import java.io.OutputStream;

import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;

public class FileAPI

    public static String readFile(String path, Blob[] outLob)
    
        try
        
            DriverManager.registerDriver(new OracleDriver());
            Connection conn = DriverManager.getConnection("jdbc:default:connection:");
            FileInputStream fileStream = null;
            fileStream = new FileInputStream(path);

            outLob[0] = BLOB.createTemporary(conn, true, BLOB.DURATION_SESSION);
            OutputStream BlobOS = outLob[0].setBinaryStream(0);
            byte[] buffer = new byte[100];

            int len = fileStream.read(buffer, 0, 100);
            while (len > -1)
            
                BlobOS.write(buffer, 0, len);
                len = fileStream.read(buffer, 0, 100);
            
            BlobOS.close();
            fileStream.close();

            return "success";
        
        catch (Exception e)
        
            e.printStackTrace();
            return e.toString();
        
    

您需要包含 Oracle JDBC 才能进行编译。 BLOB.createTemporary() 甚至适用于 Java 1.4.2 (oracle 10);从 1.6 开始,sql.Connection 中有 createBlob 函数,应该也是这样。

另外,这与您的问题有点无关,但请注意,您可以在数据库服务器上的udump 日志中读取 Java 存储过程的标准输出(System.out 和 System.err),所以不要犹豫使用e.printStackTrace() - 它极大地帮助调试。

【讨论】:

非常感谢!同时,我尝试了另一种方法并且效果很好。我很快就会在这里发布【参考方案2】:

JAVA代码

import java.lang.*;
import java.io.*;
import java.sql.Blob;

public class FileAPI 
    public static String readFile(String path, Blob[] outLob) 
        FileInputStream fileStream = null;
        Blob tmp = outLob[0];
        OutputStream ous = null;
        try 
            ous = tmp.setBinaryStream(1);
            fileStream = new FileInputStream(path);
            //System.out.println("fileStream:" + fileStream);           
            byte[] buffer = new byte[4096];
            int read = 0;
            while ((read = fileStream.read(buffer)) != -1) 
                ous.write(buffer, 0, read);
            
            outLob[0] = tmp;            
         catch (Exception e) 
            return e.toString();
            //System.out.println(e.toString());
         finally 
            try 
                if (fileStream != null) fileStream.close();
                if (ous != null) ous.close();
             catch (IOException e) 
        
        return "success";
    

Oracle 函数

CREATE OR REPLACE FUNCTION readFile (p_path IN VARCHAR2
    , p_outlob IN OUT NOCOPY BLOB
    )
RETURN VARCHAR2
AS LANGUAGE JAVA
NAME 'FileAPI.readFile(
        java.lang.String,
        java.sql.Blob[]) return java.lang.String';

用于测试的匿名块

SET SERVEROUTPUT ON;
DECLARE
    l_temp BLOB;
    l_res VARCHAR2(1000);
BEGIN
    -- important, this is required so that LOB pointer is passed to JAVA
    DBMS_LOB.CREATETEMPORARY(l_temp,TRUE);
    l_res := readFile('/mnt/servername/foldername/filename.txt',l_temp);
    IF l_temp IS NOT NULL
    THEN
        DBMS_OUTPUT.PUT_LINE('Success, length '||dbms_lob.getlength(l_temp));
    ELSE
        DBMS_OUTPUT.PUT_LINE('Error info '|| l_res);
    END IF;
    DBMS_LOB.FREETEMPORARY(l_temp);
END;
/

注意:应使用 dbms_java.grant_permission API 向 Oracle 用户授予所需的访问权限。服务器用户(运行 Oracle 的用户)应具有网络共享的读取权限。

【讨论】:

以上是关于如何在java中读取oracle blob的主要内容,如果未能解决你的问题,请参考以下文章

Oracle中存储图片的类型为BLOB类型,Java中如何将其读取并转为字符串?

如何在oracle中的blob字段下读取jpg格式文件保存

如何在 Oracle 中读取很长的 BLOB 列?

python如何保存从oracle数据库中读取的BLOB文件

java 读取blob类型存成.doc操作!!

如何使用 PL/SQL 读取 Oracle 目录的所有文件并更新 BLOB 列