I've got a Table where i store my pdf files as blob.
I get the InputStream and insert it like this.
pstmt.setBinaryStream(1, inputStream);
For this I created a Model with Integer ID and InputStream blob; as variables.
I read the blob like this out of my DB.
blob.setBlob(rs.getBinaryStream("blob_file"));
Now I tried to create the PDF file again with this.
byte[] buffer = new byte[4096];
File file= new File("c:\\MyPath\\myPDF.pdf");
try{
FileOutputStream output= new FileOutputStream(file);
int b = 0;
while ((b = blob.getBlob().read()) != -1) {
output.write(buffer);
}
output.close();
}catch(IOException ex){
System.err.println("Blob Error: " + ex.getMessage());
}
With this method I get a corrupt PDF file which I can't open.
I found an alternative which worked very well like this.
IOUtils.copy(blob.getBlob(), output);
But I don't get why my first Version didn't work and what's the difference between These two.
Try this:
FileOutputStream output = null;
InputStream is = blob.getBlob();
try{
output= new FileOutputStream(file);
int b = 0;
while ((b = is.read(buffer)) != -1) {
output.write(buffer, 0, b);
}
} catch(IOException ex){
System.err.println("Blob Error: " + ex.getMessage());
} finally {
is.close();
if (output != null) {
output.close();
}
}
The problem in your initial code is the fact that you don't use the value of b (which is the the total number of bytes read into the buffer) so you probably write more bytes than you should which is probably the cause of the corruption of your file.
Related
I have a BLOB file which I have got from the DB team. I know that its a PDF document (I opened using Notepad++ and I could see the file name) and I need to convert the same using java. I have checked for few examples and I couldn't find any example where the BLOB file itself is taken as an input instead of taking directly from the DB (Resultset). Can anyone please give some pointers as to how I can accomplish this?
Thanks in advance!
I have tried below,
File file = new File("C:/Users/User1/Desktop/0LK54E33K1477e2MCEU25JV0G8MG418S007N45JU.BLOB0");
FileInputStream fis = new FileInputStream(file);
//System.out.println(file.exists() + "!!");
//InputStream in = resource.openStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try {
for (int readNum; (readNum = fis.read(buf)) != -1;) {
bos.write(buf, 0, readNum); //no doubt here is 0
//Writes len bytes from the specified byte array starting at offset off to this byte array output stream.
System.out.println("read " + readNum + " bytes,");
}
} catch (IOException ex) {
//Logger.getLogger(genJpeg.class.getName()).log(Level.SEVERE, null, ex);
}
byte[] bytes = bos.toByteArray();
//below is the different part
File someFile = new File("C:/Users/User1/Desktop/Test.pdf");
FileOutputStream fos = new FileOutputStream(someFile);
fos.write(bytes);
fos.flush();
fos.close();
I am writing a file storage and transfer system using Java. Here's the code on the client side to receive a file:
public static void receiveFile(Socket socket) throws IOException{
String fileLocation="/home/limafoxtrottango/Downloads/receivedFile";
int bytesRead=0;
int current = 0;
FileOutputStream fileOutputStream = null;
BufferedOutputStream bufferedOutputStream = null;
try {
// receive file
byte [] byteArray = new byte [60022386];
System.out.println("Waiting to receive a file...");
//reading file from socket
InputStream inputStream = socket.getInputStream();
fileOutputStream = new FileOutputStream(fileLocation);
bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
bytesRead = inputStream.read(byteArray,0,byteArray.length); //copying file from socket to byteArray
current = bytesRead;
do {
bytesRead =inputStream.read(byteArray, current, (byteArray.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
bufferedOutputStream.write(byteArray, 0 , current); //writing byteArray to file
bufferedOutputStream.flush(); //flushing buffers
System.out.println("File " + fileLocation + " downloaded ( size: " + current + " bytes read)");
} catch(SocketException e){
System.out.println("Some error occured");
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
if (fileOutputStream != null) fileOutputStream.close();
if (bufferedOutputStream != null) bufferedOutputStream.close();
if (socket != null) socket.close();
}
}
While receiving a file, I get the following error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
at java.lang.System.arraycopy(Native Method)
at java.io.BufferedOutputStream.write(BufferedOutputStream.java:128)
at Test.receiveFile(Test.java:211)
at Test.main(Test.java:70)
Note: The error is in the following line of the code:
bufferedOutputStream.write(byteArray, 0 , current);
After debugging, I found-out that the client does not have any data in it's input stream, and hence, the read() method always returns -1 (eof). But the server is sending the file successfully.
Here is the code for the server:
public static void sendFile(Socket socket, String fileLocation)
{
FileInputStream fileInputStream = null;
BufferedInputStream bufferedInputStream = null;
OutputStream outputStream = null;
File file = new File (fileLocation);
byte [] byteArray = new byte [(int)file.length()];
try {
socket=new Socket(socket.getInetAddress(),port_no);
fileInputStream = new FileInputStream(file);
bufferedInputStream = new BufferedInputStream(fileInputStream);
bufferedInputStream.read(byteArray,0,byteArray.length); // copied file into byteArray
//sending file through socket
outputStream = socket.getOutputStream();
System.out.println("Sending " + fileLocation + "( size: " + byteArray.length + " bytes)");
outputStream.write(byteArray,0,byteArray.length); //copying byteArray to socket
outputStream.flush(); //flushing socket
System.out.println("Done sending!");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
And here is my call to the above method:
sendFile(clientSocket, "/home/limafoxtrottango/Downloads/serverDownloads/"+sender);
The thing is that the server is successfully writing the byte into the stream, but the client doesn't seem to have any data in it's input stream.
https://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#read(byte[],%20int,%20int)
inputStream.read(byteArray,0,byteArray.length); may return -1 in some cases as given in documentation above. Please cater for such situations.
In addition, I would suggest to use solution given here for both client and server: Efficient way to write InputStream to a File in Java (Version 6)
Client code:
final Path destination = Paths.get(fileLocation);
try (
final InputStream in = socket.getInputStream();
) {
Files.copy(in, destination);
}
Server code:
try (
final InputStream in = new FileInputStream(fileLocation);
) {
Files.copy(in, socket.getOutputStream());
}
Kind regards,
Bala
The server isn't sending anything, contrary to your title. It is closing the connection immediately, so bytesRead is initially -1 and never changes, and you aren't defending against that, so you get the ArrayIndexOutOfBoundsException.
However in the code you posted, the server is sending something but never closing the socket, which is another bug you need to fix. It is also ignoring the count returned by FileInputStream.read() and assuming it filled the buffer, which isn't part of the specification.
So either this is not the real server code or you are connecting to something else, or the server got an IOException that you haven't mentioned.
It's curious that you use two different pieces of code for copying. The standard way to copy a stream in Java is this:
char buffer = new char[8192]; // or whatever size you prefer > 0
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Use this at both ends. There is no need for heroically sized buffers, or buffers the size of the file, or assuming that the file size fits into an int.
I can't use ImageIO.read() because of my own restrictions. I can only load bytes after GET request and I need to save this bytes to file as image. But it seems to me, that there also loads some extra data, which browser usually filter (maybe response headers). So I get the array of raw bytes which I even can't open as image.
What should I do with this bytes?
Example:
byte[] buf = ContentLoader.loadBytes(new URL("http://images.visitcanberra.com.au/images/canberra_hero_image.jpg"));
try {
FileOutputStream fileOutputStream = new FileOutputStream(new File("D:\\image.jpg"));
fileOutputStream.write(buf);
fileOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
loadBytes() method:
public static byte[] loadBytes(URL url) {
ByteArrayOutputStream boutArray = new ByteArrayOutputStream();
try {
URLConnection connection = url.openConnection();
BufferedInputStream bin = new BufferedInputStream(connection.getInputStream());
byte[] buffer = new byte[1024 * 16];
while (bin.read(buffer) != -1) {
boutArray.write(buffer);
boutArray.flush();
}
bin.close();
} catch (Exception e) {
return null;
}
return boutArray.toByteArray();
}
Usual problems. The standard way to copy a stream in Java is:
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
out.close();
in.close();
Note that you need to store the result returned by read() into a variable; that you need to use it in the next write() call; that you shouldn't flush() inside a loop; and that you need to close the input and output streams.
And why you're using a ByteArrayInputStream at all is a mystery. It's just a waste of time and space. Read directly from the URL input stream, and write directly to the FileOutputStream.
The following code works for me:-
URL url = new URL("my url...");
InputStream is = url.openStream();
OutputStream os = new FileOutputStream("img.jpg");
byte[] b = new byte[2048];
int length;
while ((length = is.read(b)) != -1) {
os.write(b, 0, length);
}
is.close();
os.close();
I follow several example from SO to get image file from zip, and put each file bytes into a hashmap:
final byte[] zip_file = ((CommonsMultipartFile) zip_file).getBytes();
zip_stream = new ZipInputStream(new ByteArrayInputStream(zip_file));
try {
while ((entry = zip_stream.getNextEntry()) != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
BufferedOutputStream dest = new BufferedOutputStream(baos, BUFFER_SIZE);
try {
int count = 0;
byte[] data = new byte[BUFFER_SIZE];
while ((count = zip_stream.read(data, 0, BUFFER_SIZE)) > 0) {
dest.write(data, 0, count);
}
dest.flush();
filelist.put(entry.getName(), baos.toByteArray());
baos.reset();
} finally {
dest.close();
}
} finally {
baos.close();
}
}
} finally {
zip_stream.close();
}
Later when reading from filelist, the byte array will persist into a java bean, just like this
Customer customer = new Customer();
byte[] image = fileist.get(imageFileName);
customer.setImage(image);
Customer is an JPA entity that field image is with #Lob type. So this part shouldn't have any issue.
The sad party is after the whole transaction there did some data write into 'image' field but from Oracle (using SQL developer) the bytes cannot compose to image file, which means from oracle the file is broken. There must be something wrong make the bytes corrupted. How can I make it work?
UPDATE
change inputstream-outputstream transfer using IOUtils.copy but still not working...But I feel something wrong here but don't know how to fix. in following code the looping seems to work on each entry of the zipInputStream, entry is never visited instead of the file name, is it look normal?
try {
while ((entry = zip_stream.getNextEntry()) != null) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
IOUtils.copy(zip_stream, baos);
} finally {
baos.close();
}
filelist.put(entry.getName(), baos.toByteArray());
}
} finally {
zip_stream.close();
}
Remove baos.set and move the filelist.put after baos.close.
Honestly I think one should nest dest and baos inversely, and dest.close should suffice, imply closing baos.
Also instead of getBytes one could do getInputStream.
Certainly there is IOUtils with a copy; somewhere there should be a copy with a flag "keep opened."
Directory entries were not skipped and closeEntry not called.
try {
ZipInputStream zipInputStream = new ZipInputStream(
new FileInputStream("D:/dev/... .zip"));
ZipEntry zipEntry;
while ((zipEntry = zipInputStream.getNextEntry()) != null) {
System.out.println("- " + zipEntry.getName()
+ " #" + zipEntry.getSize());
if (zipEntry.isDirectory()) {
zipInputStream.closeEntry();
continue;
}
long size = zipEntry.getSize();
if (size > Integer.MAX_VALUE) {
throw new IOException("File too large: " + zipEntry.getName());
}
int reserved = size == -1L ? 8192 : (int)size;
ByteArrayOutputStream baos = new ByteArrayOutputStream(reserved);
IOUtils.copy(zipInputStream, baos);
zipInputStream.closeEntry();
baos.close();
File file = new File("D:/dev/data/temp/" + zipEntry.getName());
file.getParentFile().mkdirs();
FileUtils.writeByteArrayToFile(file, baos.toByteArray());
}
} catch (IOException ex) {
Logger.getLogger(Stackoverflow.class.getName()).log(Level.SEVERE, null, ex);
}
Well i am trying to transfer a file using sockets in java
Here is the code
Client Code
try{
// get streams
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
DataInputStream din = new DataInputStream (socket.getInputStream());
dos.writeUTF(fileName);
dos.flush();
boolean isOk = din.readBoolean();
if(!isOk){
throw new StocFileNotFound("Fisierul: " + fileName +" was not found on:" + address.toString());
} else {
baos = new ByteArrayOutputStream();
byte biti [] = new byte[1024];
while(din.read(biti,0,1024) != -1){
baos.write(biti,0,biti.length);
}
}
}
catch(IOException e){}
finally {
try{ socket.close(); } catch (IOException e){}
}
and then I return the baos.toByteArray() and write it to a file with the OutputStream`s write method.
Server code
try{
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
DataInputStream din = new DataInputStream (socket.getInputStream());
// check if it is really a file or if it is an existing file
File file = new File(din.readUTF());
// write false
if ( !file.exists() || !file.isFile() ){
dos.writeBoolean(false);
dos.flush();
}
// write true and write the file
else {
byte biti[] = new byte[1024];
dos.writeBoolean(true);
FileInputStream fis = new FileInputStream(file);
while(fis.read(biti,0,1024) != -1){
dos.write(biti,0,biti.length);
}
dos.flush();
try{ fis.close(); } catch (IOException e){}
}
} catch (IOException e){}
finally {
try{socket.close();}catch(IOException e){}
}
The problem
When i transfer a .txt file and view it in gedit it shows the text followed by multiple \00\00\00, though when i open it using notepad(in wine) it shows only the text. Plus viewing images and .doc works also. So is it something with gedit or is it with my program?
Edit
i was sending something like "hi, hope it works!"
This is the problem (or at least a problem):
while(fis.read(biti,0,1024) != -1)
{
dos.write(biti,0,biti.length);
}
You're always writing out the whole buffer, however many bytes were actually read. You should have:
int bytesRead;
while ((bytesRead = fis.read(biti, 0, 1024)) != -1)
{
dos.write(biti, 0, bytesRead);
}
(You've got the same problem in both bits of code.)
You might want to look at Guava which has various utility methods to relieve you of a lot of the tedium (and possible error) of writing this kind of code over and over again.
The read method will return the actual number of bytes read from the stream. You should use that as a parameter to your write method, or else you will be writing garbage to it.