I've to save a pdf file represented as a ByteArrayOutputStream into a Blob SQL field of a table, here's my code:
public boolean savePDF(int version, ByteArrayOutputStream baos) throws Exception{
boolean completed = false;
ConnectionManager conn = new ConnectionManager();
try {
PreparedStatement statement = conn.getConnection().prepareStatement(INSERT_PDF);
statement.setLong(1, version);
statement.setBlob(2, (Blob)baos);
statement.execute();
conn.commit();
completed = true;
} catch (SQLException e) {
conn.rollbackQuietly();
e.printStackTrace();
throw e;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally{
conn.close();
}
return completed;
}
But I get a java.lang.ClassCastException:
java.io.ByteArrayOutputStream cannot be cast to java.sql.Blob
How can I manage that? Thanks
There is a setBlob that takes an InputStream, so
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
statement.setBlob(2, bais);
You can't cast ByteArrayOutputStream to Blob. Try creating the Blob instance as below:
SerialBlob blob = new SerialBlob(baos.toByteArray());
and then
statement.setBlob(2, blob);
Related
I have a java class (Shell) that stores all the information I need to load for my application. Currently, it is saved into a .txt file and loaded from said file.
This class is responsible for saving and loading the Shell:
public void saveShell() throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
new FileOutputStream(getPath()));
objectOutputStream.writeObject(new Date());
objectOutputStream.writeBoolean(true);
objectOutputStream.writeFloat(1.0f);
objectOutputStream.writeObject(shl);
objectOutputStream.flush();
objectOutputStream.close();
System.out.println("Successfully saved");
}
public Shell loadShell() throws FileNotFoundException, IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(
new FileInputStream(getPath()));
Date date = (Date) objectInputStream.readObject();
System.out.println(date);
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readFloat());
Shell readShell = (Shell) objectInputStream.readObject();
System.out.println("Shell Loaded");
objectInputStream.close();
System.out.println("Object output stream closed");
return readShell;
}
However, now that I'm trying to distribute the application, using a file seems less viable than using a database so I have already set up SQLite.
Since Shell has everything I need, I'd like to store it as a BLOB and be able to retrieve the object later. I am new to databases so I don't quite know the specific java methods that I should use. I know that this question is very similar to How do i store and retrieve a blob from sqlite but its answer is in C#. Plus, most examples I've found are always storing pictures and images with a certain URL, there aren't many examples with objects.
I got it working. Basically I added two functions: saveShellDB and loadShellDB:
public void saveShellDB() throws ClassNotFoundException, IOException {
Class.forName(classForName);
Connection connection = null;
try
{
// create a database connection
connection = DriverManager.getConnection(connectionPath);
Statement statement = connection.createStatement();
statement.setQueryTimeout(30); // set timeout to 30 sec.
File file = new File("shell.txt");
FileInputStream fis = new FileInputStream(file);
PreparedStatement ps = connection.prepareStatement("INSERT INTO shell (name, shl) VALUES (?, ?)");
ps.setString(1, file.getName());
ps.setBinaryStream(2, fis, (int)file.length());
ps.executeUpdate();
ps.close();
fis.close();
System.out.println("SQL save done");
}
catch(SQLException e)
{
// if the error message is "out of memory",
// it probably means no database file is found
System.err.println(e.getMessage());
}
finally
{
try
{
if(connection != null)
connection.close();
}
catch(SQLException e)
{
// connection close failed.
System.err.println(e);
}
}
}
public void loadShellDB() throws ClassNotFoundException, SQLException, IOException {
Class.forName(classForName);
Connection conn = DriverManager.getConnection(connectionPath);
String sql = "SELECT name, shl FROM shell";
PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet resultSet = stmt.executeQuery();
while (resultSet.next()) {
File shl = new File(fileOutputPath);
FileOutputStream fos = new FileOutputStream(shl);
byte[] buffer = new byte[1];
InputStream is = resultSet.getBinaryStream(2);
while (is.read(buffer) > 0) {
fos.write(buffer);
}
fos.close();
}
conn.close();
System.out.println("SQL Load Done");
}
Then, I just had to call them from my old save functions:
public void saveShell() throws IOException {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
new FileOutputStream(getPath()));
objectOutputStream.writeObject(new Date());
objectOutputStream.writeBoolean(true);
objectOutputStream.writeFloat(1.0f);
objectOutputStream.writeObject(shl);
objectOutputStream.flush();
objectOutputStream.close();
System.out.println("Successfully saved");
saveShellDB(); //here!
}
public Shell loadShell() throws FileNotFoundException, IOException, ClassNotFoundException {
loadShellDB(); //here!
ObjectInputStream objectInputStream = new ObjectInputStream(
new FileInputStream(getPath()));
Date date = (Date) objectInputStream.readObject();
System.out.println(date);
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readFloat());
Shell readShell = (Shell) objectInputStream.readObject();
System.out.println("Shell Loaded");
objectInputStream.close();
System.out.println("Object output stream closed");
return readShell;
}
I have a FootballPlayer entity class which implements the Serializable interface. I am saving the objects from this class to a database table using the longblob type.
That is working fine, but when retrieving the objects from the database, I am getting a StreamCorruptedException.
Here is my code:
public FootballPlayer searchFBPlayer(String id){
try {
String sql = "SELECT * FROM player";
ResultSet rs = DBConnection.getData(sql);
// search for player
while (rs.next()) {
ByteArrayInputStream bais = new ByteArrayInputStream(rs.getBytes("fbPlayer"));
//test
if(bais==null) System.out.println("Null BAIS");
else System.out.println("No Null BAIS");
//test
FootballPlayer fbp = (FootballPlayer) toObject(bais);
if(fbp.getPlayerID().equals(id))
return fbp;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
private Object toObject(ByteArrayInputStream arr){
ObjectInputStream ins;
try{
ins = new ObjectInputStream(arr);
return ins.readObject();
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
Code to save:
public int addFootballPlayer(FootballPlayer player){
byte[] data=toByte(player);
String sql="INSERT INTO footballplayer(footballPlayer) VALUES('"+data+"')";
return DBConnection.setData(sql);
}
private byte[] toByte(Object obj){
try{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(obj);
oos.flush();
oos.close();
bos.close();
byte[] data = bos.toByteArray();
return data;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
Here is my stack trace:
java.io.StreamCorruptedException: invalid stream header: 5B424037
at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
at java.io.ObjectInputStream.<init>(Unknown Source)
at com.league.database.DBAccess.toObject(DBAccess.java:67)
at com.league.database.DBAccess.searchPlayer(DBAccess.java:34)
at com.league.main.Test.main(Test.java:20)
I don't have any kind of networking in my code such as sockets. What am I doing wrong, and how can I fix this issue?
The problem is the point where you create the SQL. You should be using a PreparedStatement at this point, and passing the data as an argument: not converting the data to String.
I am trying to upload an image file with the code below, but the file is not being uploaded. The console still shows the message "1 Record Successfully Inserted."
Create table image
(
name varchar2(20),
photo blob
);
import java.sql.*;
import java.io.*;
public class ImageWriter {
static Connection connection = null;
static CallableStatement pstat = null;
static String connectionURL = null;
public static void main(String[] args) {
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
connection = DriverManager.getConnection("jdbc:oracle:thin:#localhost:1521:xe", "SYSTEM", "SYSTEM");
PreparedStatement pstat = connection.prepareStatement("insert into image(name,photo) values(?,?)");
FileInputStream fin = new FileInputStream("E:\\test.jpg");
pstat.setString(1, "ABC");
pstat.setBinaryStream(2, fin,fin.available());
int result = pstat.executeUpdate();
System.out.println(result + " Record Successfully Inserted");
connection.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
The above code works fine.
I dont know how you verified the contents of database.
Here is my code to verify the db(blob column): Try with this method. I used your code to insert the image and I could retrieve the image successfully. (note : file extension should be same)
public static void getPic() {
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:#localhost:1521:orcl", "sys as sysdba",
"Oracle123");
ResultSet rs = null;
Statement stmt = null;
oracle.sql.BLOB photo = null;
conn.setAutoCommit(false);
stmt = conn.createStatement();
String name="ABC";
rs = stmt.executeQuery("select photo from image where name = '" + name + "'" );
rs.next();
photo = ((OracleResultSet) rs).getBLOB(1);
File f = new File("E:/image2.jpg");
f.getParentFile().mkdirs();
f.createNewFile();
InputStream in = photo.getBinaryStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStream outputStream = new FileOutputStream(f);
int bufferSize = 1024;
int length = (int) photo.length();
byte[] buffer = new byte[bufferSize];
while((length = in.read(buffer)) != -1) {
out.write(buffer,0,length);
}
out.writeTo(outputStream);
System.out.println("Image Retrieved");
out.close();
rs.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
I have a table with bytea data type on a PostgreSQL table.
I am trying to write and retrieve a pdf file from the bytea data using JDBC resultset.
However the file is corrupted while trying to display it after retrieving it.
Here is my code:
private void insertBytea(java.io.File file) {
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
Logger.getLogger(BeteaTest.class.getName()).log(Level.SEVERE, null, ex);
}
try {
java.sql.Connection connectDB = java.sql.DriverManager.getConnection("jdbc:postgresql://localhost:5433/funsoft", "postgres", "xxx");
connectDB.setAutoCommit(false);
java.sql.PreparedStatement pstmt = connectDB.prepareStatement("INSERT INTO test_binary (test_bytea) VALUES(?)");
java.io.FileInputStream fis;
try {
fis = new java.io.FileInputStream(file);
pstmt.setBinaryStream(1, fis, (int) file.length());
pstmt.executeUpdate();
connectDB.commit();
pstmt.close();
java.sql.PreparedStatement pstmtR = connectDB.prepareStatement("SELECT * FROM test_binary LIMIT 1");
// pstmtR.setString(1, file.getName());
java.sql.ResultSet rs = pstmtR.executeQuery();
while (rs.next()) {
byte[] imgBytes = rs.getBytes(2);
//java.io.InputStream ios = rs.getBinaryStream(2);
java.io.ByteArrayInputStream byteaStream = new java.io.ByteArrayInputStream(imgBytes);
java.io.File tempFile;
try {
tempFile = java.io.File.createTempFile("REP" + com.afrisoftech.lib.DateLables.getDateLabel() + "_", ".pdf");
java.io.FileOutputStream fileIS = new java.io.FileOutputStream(tempFile);
fileIS.write(imgBytes);
fileIS.close();
// this is where i am trying to display the file
com.afrisoftech.lib.PDFRenderer.renderPDF(tempFile);
} catch (IOException ex) {
Logger.getLogger(BeteaTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
fis.close();
} catch (IOException ex) {
ex.printStackTrace();
Logger.getLogger(BeteaTest.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (FileNotFoundException ex) {
Logger.getLogger(BeteaTest.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (SQLException ex) {
ex.printStackTrace();
Logger.getLogger(BeteaTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
I have a DB procedure which returns a BLOB. Can anyone tell me how to manipulate the BLOB? Is there any specific API for this?
Is there any specific API for this ?
Sure, the JDBC API.
Trail: JDBC™ Database Access
You get hold of the Blob instance just as you get hold of any value from a result set. You should then use the get...- and set... methods on this Blob.
Here you basically have two options:
Work with a byte-array:
Get hold of a byte[] containing the data through Blob.getBytes
Manipulate this byte-array
Set it back using Blob.setBytes.
Work with InputStream / OutputStream:
Get hold a an InputStream through Blob.getBinaryStream
Manipulate this stream as you see fit
Use Blob.setBinaryStream.
An alternative approach is to skip messing with Blob in the first place, and instead use the second approach (with streams) directly through the ResultSet-interface.
It depends on which kind of blob contains (image, video) and it's extension. I wrote a simple program to retrieve an image from DB and show it in JSP page. Hope it helps.
JSP Page
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>JSP Page</title>
</head>
<body>
<image src="blobAction"/>
</body>
Servlet Page
byte[] imgData = blobDao.getInstance().getPhoto();
response.setContentType("image/gif");
OutputStream o = response.getOutputStream();
o.write(imgData);
o.flush();
o.close();
Calling Procedure
public byte[] getPhoto() {
byte[] imgData = null;
Blob img = null;
ResultSet rs = null;
Statement stmt = null;
try {
conn = getConnection();
String sqlQ = "SELECT CONTENT_FILE FROM CONTENT where id = 'something';
stmt = conn.createStatement();
rs = stmt.executeQuery(sqlQ);
while (rs.next()) {
img = rs.getBlob("CONTENT_FILE");
imgData = img.getBytes(1, (int) img.length());
}
rs.close();
stmt.close();
conn.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
return imgData;
}
}
With Simple Java JDBC Api, you can get a java.sql.Blob back from a ResultSet.
ResultSet.getBlob(index) or
ResultSet.getBlob(String columnName).
Both returns a Blob.
Once you get a Blob, you can get the byte[] back from the Blob.getBytes() method or set using setBytes() method.
Update: Seeing that some Database driver vendors don't support Blob, you can use ResultSet.getBinaryStream().
You can use javax.sql.rowset.serial.SerialBlob.
I'm using it in my SpringBoot & Angular4 application like this:
get Base64String from Angular4 app
decode Base64String to byte[]
create SerialBlob like this: SerialBlob serialBlob = new SerialBlob(byte[])
store it in the database with JpaRepository
Example
public void Insert(Object obj){
try {
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(byteArray);
oos.writeObject(obj);
PreparedStatement ps= conn1.prepareStatement("insert into vehiculos values(?)");
ps.setBytes(1, byteArray.toByteArray());
ps.execute();
ps.close();
} catch (SQLException ex) {
System.out.println("ERROR:al hacer un Insert");
ex.printStackTrace();
} catch (IOException ex) {
Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void ShowData(){
try {
Statement stmt = conn1.createStatement();
String query = "SELECT * FROM vehiculos";
ResultSet rs = stmt.executeQuery(query);
Object obj;
while(rs.next()){
//Coche c = (Coche)rs.getBlob("coches");
Blob blob = rs.getBlob("coches");
ObjectInputStream ois = new ObjectInputStream(blob.getBinaryStream());
obj = ois.readObject();
System.out.println(obj.toString());
System.out.println("");
/*Blob blob = rs.getBlob("coches");
byte[] data = blob.getBytes(1, (int)blob.length());*/
}
rs.close();
stmt.close();
} catch (SQLException ex) {
System.out.println("ERROR:al consultar");
ex.printStackTrace();
} catch (IOException ex) {
Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(Conexion.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void cerrar_Conexion (){
try {
conn1.close();
} catch (SQLException ex) {
System.out.println("ERROR:al cerrar la conexión");
ex.printStackTrace();
}
}