I wrote the following code for downloading some files from a server but the problem is that this code isn't reading the complete response (inputStream). File size is 7.5 MB while I am getting 5.5 MB each time and of course adobe reader complains that file is damaged. Here is the code
import java.net.URLConnection;
public class Downloader {
URL url;
public Downloader(){
try {
url = new URL("https://d396qusza40orc.cloudfront.net/algs4partI/slides%2F13StacksAndQueues.pdf");
FileOutputStream outStream;
ObjectOutputStream oStream;
try {
URLConnection con = url.openConnection();
InputStream inStream = con.getInputStream();
outStream = new FileOutputStream("data.pdf");
oStream = new ObjectOutputStream(outStream);
int bytesRead;
int totalBytesRead = 0;
byte[] buffer = new byte[100000];
while((bytesRead = inStream.read(buffer)) > 0){
//outStream.write(buffer, 0 , bytesRead);
oStream.write(buffer, 0, bytesRead);
buffer = new byte[100000];
totalBytesRead += bytesRead;
}
System.out.println("Total Bytes read are = " + totalBytesRead);
oStream.close();
outStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args){
Downloader d = new Downloader();
}
}
Any ideas what I am doing wrong here? Thanks in advance.
You don't want to be using ObjectOutputStream when you aren't serializing java objects.
Un-comment the line
//outStream.write(buffer, 0 , bytesRead);
and remove
oStream.write(buffer, 0, bytesRead);
So:
while((bytesRead = inStream.read(buffer)) > 0){
outStream.write(buffer, 0 , bytesRead);
buffer = new byte[100000]; // this line is useless
totalBytesRead += bytesRead;
}
Get rid of the ObjectOutputStream altogether. Your file is 5.25 MB (5,511,685 bytes) long, not 7.5 MB.
InputStream that you get from URL connection does not guarantee that all bytes arrive at once. They are transfered over network, so your reading speed may be higher than your network. Method read() returns number of bytes that have been read at current execution of the method. If it returns 0 the information is probably not available at the moment but will be available later.
Method read() returns -1 to indicate end of stream. Bottom line: change > 0 in your if statement to >= 0.
The problem is that you are using ObjectOutputStream. This encodes the output in the Java Object Serialization format, which is not what the PDF reader expects / requires.
Use a plain FileOutputStream and it should work.
Related
i have a client and a server,
1) client should send choose files and send them to server
2) client should send a command message so that the server knows that the incoming is a file not a message (thats why i have "SF" which stands for send file)
3) server receives files and store them somewhere in the system
Also, i dont want to close the socket after i send/receive files (because this is done when the client clicks on disconnect button)
Below is my code but it does not work for some reason, if someone can help me fix it.
Client
public void sendFiles(String file) {
this.out.print("SF");
this.out.flush();
File myfile = new File(file);
// Get the size of the file
long length = myfile.length();
if (length > Integer.MAX_VALUE) {
System.out.println("File is too large.");
}
byte[] bytes = new byte[(int) length];
FileInputStream fis;
try {
fis = new FileInputStream(myfile);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(sock.getOutputStream());
int count;
while ((count = bis.read(bytes)) > 0) {
out.write(bytes, 0, count);
}
System.out.println("count "+bytes.length);
// this.out.flush();
out.flush();
// out.close();
fis.close();
bis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Server
public void recvFile() {
InputStream is = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
int bufferSize = 0;
try {
is = sock.getInputStream();
bufferSize = sock.getReceiveBufferSize();
System.out.println("Buffer size: " + bufferSize);
fos = new FileOutputStream("/Users/day/Documents/Parallels/server.txt");
bos = new BufferedOutputStream(fos);
byte[] bytes = new byte[bufferSize];
int count;
while ((count = is.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
System.out.println("bytes "+bytes.length);
System.out.println("count "+count);
bos.flush();
bos.close();
// is.close();
// sock.close();
} catch (IOException e) {
System.out.println("ERROR" +e);
}
Also in the server side; this is how i jump to the method recvFile();
if (message.contains("SF")) {
recvFile();
}
MORE explanation about my problem:
It does not work in a sense that i dont know if the file is actually sent properly? or the file received properly because i get 0 bytes in the received file. Also, this is the thing i dont want to close the connection because this is a chat so how can i let the server know that this is the end of file?
Can someone help me making the code works because i dont know whats wrong? thanks
Could you kindly elaborate on the error that you are getting. That may help in answering. Because, prima facie the code structure looks fine.
Additionally, I presume that you are using TCP connection for file transfer.
P.S.: I couldn't add a comment to the question, so asking question here.
I have my client server chat
Client sends files and server receives them. But, the problem is that, i don't think that files are received properly because when i check the size of the files i see the difference is halfed for some reasons!
I am using GUI to browse for files in the client side, and then i'm sending a command to the server to know that the client is sending a file. But it is not working
Here is the client and server
public void sendFiles(String file) {
try {
BufferedOutputStream outToClient = null;
outToClient = new BufferedOutputStream(sock.getOutputStream());
System.out.println("Sending file...");
if (outToClient != null) {
File myFile = new File( file );
byte[] mybytearray = new byte[(int) myFile.length()];
FileInputStream fis = null;
fis = new FileInputStream(myFile);
BufferedInputStream bis = new BufferedInputStream(fis);
this.out.println("SF");
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
this.out.flush();
outToClient.flush();
outToClient.close();
System.out.println("File sent!");
return;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Server
public void recvFile() {
try {
byte[] aByte = new byte[1];
int bytesRead;
InputStream is = null;
is = sock.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
if (is != null) {
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fos = new FileOutputStream("/Users/Documents/Received.png");
bos = new BufferedOutputStream(fos);
bytesRead = is.read(aByte, 0, aByte.length);
do {
baos.write(aByte);
bytesRead = is.read(aByte);
} while (bytesRead != -1);
bos.write(baos.toByteArray());
bos.flush();
bos.close();
// clientSocket.close();
} catch (IOException ex) {
// Do exception handling
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Can someone help me with this issue? As i don't know how to properly send and receive files
Thank you
You are using two copy techniques, and they are both wrong.
First:
byte[] mybytearray = new byte[(int) myFile.length()];
bis.read(mybytearray, 0, mybytearray.length);
outToClient.write(mybytearray, 0, mybytearray.length);
Here you are assuming:
That the file fits into memory.
That the file length fits into an int.
That read() fills the buffer.
None of these assumptions is valid.
Second:
byte[] aByte = new byte[1];
bytesRead = is.read(aByte, 0, aByte.length);
do {
baos.write(aByte);
bytesRead = is.read(aByte);
} while (bytesRead != -1);
Here you are:
Using a ridiculously small buffer of one byte.
Writing an extra byte if the file length is zero.
Using a do/while where the situation naturally calls for a while (as 99.99% of situations do), and therefore:
Using two read() calls, and only correctly checking the result of one of them.
Pointlessly using a ByteArrayOutputStream, which, as above, assumes the file fits into memory and that its size fits into an int. It also pointlessly adds latency.
Throw them both away and use this, at both ends:
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
where:
in is a FileInputStream in the case of sending the file, or the socket input stream in the case of receiving the file.
out is a FileOutputStream in the case of receiving the file, or the socket output stream in the case of sending the file
I am sending files to remote Android client from java server. I write the bytes using outputstream. On reading these bytes read() method keep trying to read bytes after the stream is ended. if I close the outputstream on server-side, read operation work fines. But I have to write file on the same socket again so can't close output stream any solution?
NOTE: MY CODE WORKS FINE FOR SHARING SINGLE FILE
CODE FOR WRITING FILE
public static void writefile(String IP, String filepath, int port, OutputStream out) throws IOException {
ByteFileConversion bfc = new ByteFileConversion();
byte[] file = bfc.FileToByteConversion(filepath);
out.write(file, 0, file.length);
out.close(); // i donot want to close this and how can I tell reading side that stream is ended.
System.out.println("WRITTEN");
}
Here Am I reading the file on Android :
public Bitmap fileReceived(InputStream is) {
Bitmap bitmap = null;
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "a.png";
String imageInSD = baseDir + File.separator + fileName;
// System.out.println(imageInSD);
if (is != null) {
FileOutputStream fos = null;
OutputStream bos = null;
try {
bos = new FileOutputStream(imageInSD);
byte[] aByte = new byte[1024];
int bytesRead;
int index = 0;
DataInputStream dis = new DataInputStream(is);
while ((bytesRead = is.read(aByte)) > 0) {
index = bytesRead + index;
bos.write(aByte, 0, bytesRead);
// index = index+ bytesRead;
System.out.println("Loop" + aByte + " byte read are " + bytesRead + "whree index =" + index);
}
bos.flush();
bos.close();
Log.i("IMSERVICE", "out of loop");
java.io.FileInputStream in = new FileInputStream(imageInSD);
bitmap = BitmapFactory.decodeStream(in);
bitmap = BitmapFactory.decodeFile(imageInSD);
Log.i("IMSERVICE", "saved");
// if (bitmap != null)
// System.out.println("bitmap is "+ bitmap.toString());
} catch (IOException ex) {
// Do exception handling
// Log.i("IMSERVICE", "exception ");
System.out.println("ex");
}
}
return bitmap;
}
Actually, I want to reset socket connection
Thanks in advance
You need to:
Send the length of the file ahead of the file. You can use DataOutputStream.writeLong() for that, and DataInputStream.readLong() at the receiver.
Read exactly that many bytes from the stream at the receiver:
while (total < length && (count = in.read(buffer, 0, length-total > buffer.length ? buffer.length : (int)(length-total))) > 0)
{
out.write(buffer, 0, count);
total += count;
}
E&OE
Actually I want to reset socket connection
Actually you don't want to do any such thing.
If i donot close outputstream the read operation on other side stuck on keep reading
That is because the client socket's InputStream is still waiting for the server to send some packets of data thus blocking your Main Thread.
Solution:
You can put each of your sending(OutputStream) and reading(InputStream) of packets of data from the socket to a Thread to prevent blocking your main thread when reading and sending.
Create a thread that reads the InputStream and another one for the OutputStream
Side note:
Don't try to close your outputStream that it cant be reopened again as the documentation is saying:
Closing the returned OutputStream will close the associated socket.
The general contract of close is that it closes the output stream. A closed stream cannot perform output operations and cannot be reopened.
I'm putting together some code to download files from an HTTP address in Android. I'd like to support download resumption if the download fails mid way.
The output I get when starting the download, then killing the wifi connection and restarting again several times is the following:
Start size 0
Stop size 12333416
Start size 12333416
Stop size 16058200
Start size 3724784
I cannot understand why after the first resumption, subsequent file size readings of the partially downloaded file do not match.
Thanks in advance!
public void download(String source, String target) throws IOException {
BufferedOutputStream outputStream = null;
InputStream inputStream = null;
try {
File targetFile = new File(target);
currentBytes = targetFile.length();
Log.i(TAG, "Start size " + String.valueOf(currentBytes));
outputStream = new BufferedOutputStream(new FileOutputStream(targetFile));
// create the input stream
URLConnection connection = (new URL(source)).openConnection();
connection.setConnectTimeout(mCoTimeout);
connection.setReadTimeout(mSoTimeout);
inputStream = connection.getInputStream();
inputStream.skip(currentBytes);
// calculate the total bytes
totalBytes = connection.getContentLength();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) > 0) {
// write the bytes to file
outputStream.write(buffer, 0, bytesRead);
outputStream.flush();
currentBytes += bytesRead;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
// close the output stream
outputStream.flush();
outputStream.close();
}
if (inputStream != null) {
// close the input stream
inputStream.close();
}
Log.i(TAG, "Stop size " + String.valueOf(currentBytes));
}
}
There are two things you are doing wrong:
To resume download to file you should append, not rewrite the file. Use special constructor for output stream:
FileOutputStream(targetFile, true)
To request part of file from server you should use HTTP 1.1 property "Range". You can do it like this:
HttpURLConnection httpConnection = (HttpURLConnection) connection;
connection.setRequestProperty("Range", "bytes=" + currentBytes + "-");
I am using following code for reading image file from socket. It reads all the bytes from server because size of file on server and android machine are same. When i open this file it does not open the file and generate error that is the file is corrupted or too large.
public Bitmap fileReceived(InputStream is)
throws FileNotFoundException, IOException {
Bitmap bitmap = null;
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String fileName = "a.png";
String imageInSD = baseDir + File.separator + fileName;
System.out.println(imageInSD);
if (is!= null) {
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
fos = new FileOutputStream(imageInSD);
bos = new BufferedOutputStream(fos);
byte[] aByte = new byte[1024];
int bytesRead;
while ( true ) {
bytesRead = is.read(aByte);
bos.write(aByte, 0, bytesRead);
if ( is.available()==0)
break;
}
bos.flush();
bos.close();
// is.reset();
// here it give error i.e --- SkImageDecoder::Factory returned null
bitmap = BitmapFactory.decodeFile(imageInSD);
} catch (IOException ex) {
// Do exception handling
Log.i("IMSERVICE", "exception ");
}
}
return bitmap;
}
Don't use available() for this, it won't work reliably!
The docs state:
[ available() ] Returns an estimate of the number of bytes that can be read [...] It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
Do it like:
while ( (bytesRead = is.read(aByte)) > 0 ) {
bos.write(aByte, 0, bytesRead);
}