I have a java web application, where users can download images
The way i coded the download is using IOUtils.copy to the response stream
But downloading a 4mb image takes around 10 sec and its happening really slow.
It seems like the server is sending chunk at a time.
this is the way I am writing the image to the output stream:
OutputStream out = response.getOutputStream();
FileInputStream stream = new FileInputStream(path);
IOUtils.copy(stream, out);
out.flush();
out.close();
Is there a faster way to do this?
UPDATE
following code using 1MB buffer and copyLarge didn't make any change.
FileInputStream stream = new FileInputStream(path);
byte[] buffer = new byte[1024 * 1024];
IOUtils.copyLarge(stream, out,buffer );
Try copyLarge:
public static long copyLarge(InputStream input,
OutputStream output,
byte[] buffer) throws IOException
Use buffer size about 1Mb
Related
When I try upload the file from server, I use this code. I get the file size of 500kb, when the original file size about 300kb.
What am I doing wrong?
attachmentContent = applicationApi.getApplicationAttachmentContent(applicationame);
InputStream in = new BufferedInputStream(attachmentContent.getAttachmentContent().getInputStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
int n=0;
while (-1 !=(n=in.read(buf)))
{
out.write(buf,0,n);
}
out.close();
in.close();
byte[] response = out.toByteArray();
File transferredFile = new File(attachmentName);
FileOutputStream outStream = new FileOutputStream(transferredFile);
attachmentContent.getAttachmentContent().writeTo(outStream);
outStream.write(response);
outStream.close();
Simplify. The same result:
File transferredFile = new File(attachmentName);
FileOutputStream outStream = new FileOutputStream(transferredFile);
attachmentContent.getAttachmentContent().writeTo(outStream);
outStream.close();
The ByteArrayOutputStream is a complete waste of time and space. You're reading the attachment twice, and writing it twice too. Just read from the attachment and write directly to the file. Simplify, simplify. You don't need 90% of this.
I have a webservice running and ready to consume images produced by my Android tablet camera (Samsumg Galaxy TAB 10.1).
It works perfectly when consuming images taken at 1024x768 resolution (0.8M). However, when using the tablet's highest resolution (2048x1536, or 3.2M), the image saved simply does not work. It saves a broken image file with 0kb size.
This is the code related to the image-saving in the webservice:
public static void saveFile(final InputStream file, final String filePath) throws IOException {
OutputStream out = new FileOutputStream(new File(filePath.trim()));
int read = 0;
byte[] bytes = new byte[2048];
while ((read = file.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
file.close();
out.flush();
out.close();
}
I've already tried increasing the byte array size, but it didn't help.
The file variable is produced like this:
final InputStream image = data.getImage().getDataHandler().getInputStream();
Where data is a object consumed via a multipart request made by the webservice to Android, like this.
Any ideas?
My program takes a picture of the users screen, when they are using my program, to make a screenshot, then sends it to a server. The image will load about 1/4 of the way and freeze.
Sending the screenshot:
BufferedImage buffimg = robot.createScreenCapture(captureSize);
BufferedImage image = buffimg;
byte[] imageInByte;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
baos.flush();
imageInByte = baos.toByteArray();
baos.close();
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.println("!SCREENDATA!");
out.flush();
dos.writeInt(baos.toByteArray().length);
dos.write(baos.toByteArray());
dos.flush();
Getting the image:
if (input.startsWith("!SCREENDATA!")) {
System.out.println("reading");
DataInputStream dis = new DataInputStream(socket.getInputStream());
int len = dis.readInt();
System.out.println(len);
byte[] data = new byte[len];
dis.read(data);
InputStream in = new ByteArrayInputStream(data);
Image image = Toolkit.getDefaultToolkit().createImage(data);
v.repaint(image);
}
Displaying the image:
public void repaint(Image img) {
frame.getContentPane().add(new JLabel(new ImageIcon(img)));
frame.repaint();
frame.pack();
}
If anyone could help me with this, I would appreciate it a lot!
You need to keep calling dis.read(data); as this method on a TCP socket isn't designed to offer the entire buffer in one call (it's a stream socket, it keeps going). But be aware that the method call will block when the socket has no data to give. Also, it's best to send the file size in advance of the file so the other end knows how much to expect - it is less prone to protocol errors that can cause an infinite loop.
Have a look at the answers at how to achieve transfer file between client and server using java socket.
Anyway, an analogy: the socket has a bucket which fills up which is 512kb, let's say. You have a bucket that is 2048kb. You have to keep pouring the socket bucket into your own bucket.
Also, don't do stuff with Swing unless its on the Event Dispatch Thread. See How do you use the Event Dispatch Thread? for more details.
I am using the code provided by this accepted answer to send a list of files over a socket in Java. My goal is to be receiving a list of images. What I would like to do is read these images directly into memory as BufferedImages before writing them to disk. However, my first attempts, which was to use ImageIO.read(bis) (again, see the attached question) failed, as it attempted to continue reading beyond the end of the first image file.
My current idea is to write the data from the socket to a new output stream, then read that stream from an intput stream that is passed to ImageIO.read(). This way, I can write it byte by byte as the program is currently doing, but send it to the BufferedImage rather than the file. however I'm not sure how to link the output stream to an input stream.
Can anyone recommend simple edits to the code above, or provide another method of doing this?
In order to read the image before writing it to disk, you'll need to use a ByteArrayInputStream. http://docs.oracle.com/javase/6/docs/api/java/io/ByteArrayInputStream.html
Basically, it creates a inputstream that reads from a specified byte array. So, you'd read the image length, then it's name, then the length-amount of bytes, create the ByteArrayInputStream, and pass it to ImageIO.read
Example snippet:
long fileLength = dis.readLong();
String fileName = dis.readUTF();
byte[] bytes = new byte[fileLength];
dis.readFully(bytes);
BufferedImage bimage = ImageIO.read(new ByteArrayInputStream(bytes));
Or using the code from the other answer you cited:
String dirPath = ...;
ServerSocket serverSocket = ...;
Socket socket = serverSocket.accept();
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
File[] files = new File[filesCount];
for(int i = 0; i < filesCount; i++)
{
long fileLength = dis.readLong();
String fileName = dis.readUTF();
byte[] bytes = new byte[fileLength];
dis.readFully(bytes);
BufferedImage bimage = ImageIO.read(new ByteArrayInputStream(bytes));
//do some shit with your bufferedimage or whatever
files[i] = new File(dirPath + "/" + fileName);
FileOutputStream fos = new FileOutputStream(files[i]);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write(bytes, 0, fileLength);
bos.close();
}
dis.close();
I have a FileInputStream created using Context.openFileInput(). I now want to convert the file into a byte array.
Unfortunately, I can't determine the size of the byte array required for FileInputStream.read(byte[]). The available() method doesn't work, and I can't create a File to check it's length using the specific pathname, probably because the path is inaccessible to non-root users.
I read about ByteArrayOutputStream, and it seems to dynamically adjust the byte array size to fit, but I can't get how to read from the FileInputStream to write to the ByteArrayOutputStream.
This should work.
InputStream is = Context.openFileInput(someFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
while ((int bytesRead = is.read(b)) != -1) {
bos.write(b, 0, bytesRead);
}
byte[] bytes = bos.toByteArray();
This is the easiest way
FileInputStream fis = openFileInput(fileName);
byte[] buffer = new byte[(int) fis.getChannel().size()];
fis.read(buffer);
You can pre-allocate the byte array using
int size = context.getFileStreamPath(filename).length();
This way, you will avoid allocating memory chunks every time your ByteArrayOutputStream fills up.
For the method to work on any device and aplication you just need to replace:
InputStream is = Context.getContentResolver().openInputStream(yourFileURi);
This way you can encode external files as well.