I am trying to send a file from one computer to another using Java. I have written the code below, it works fine if both sender and receiver are started in the same computer but if they work on different machines received file size is bigger than the original file and it is corrupted.
Note: I am trying to transfer files which are max 10 MBs.
How can I fix this?
Sender:
ServerSocket server_socket = new ServerSocket(8989);
File myFile = new File(myPath);
Socket socket = server_socket.accept();
int count;
byte[] buffer = new byte[1024];
OutputStream out = socket.getOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(myFile));
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
out.flush();
}
socket.close();
Receiver:
Socket socket = new Socket(address, 8989);
FileOutputStream fos = new FileOutputStream(anotherPath);
BufferedOutputStream out = new BufferedOutputStream(fos);
byte[] buffer = new byte[1024];
int count;
InputStream in = socket.getInputStream();
while((count=in.read(buffer)) >0){
fos.write(buffer);
}
fos.close();
socket.close();
On the client side you write up to count bytes and send them:
while ((count = in.read(buffer)) > 0) {
out.write(buffer, 0, count);
on the server side you read up to count bytes - but then you write the whole buffer to file!
while((count=in.read(buffer)) > 0){
fos.write(buffer);
Just change it to:
fos.write(buffer, 0, count);
and you'll be on the safe side. BTW your program has another small bug: read() can return 0 which doesn't mean InputStream ended. Use >= instead:
count = in.read(buffer)) >= 0
Have you considered IOUtils.copy(InputStream, OutputStream) from Apache Commons? It would reduce your whole while loops to:
OutputStream out = socket.getOutputStream();
InputStream in = new FileInputStream(myFile);
IOUtils.copy(in, out);
socket.close();
Less code to write, less code to test. And buffering is done internally.
Remember that in.read(buffer) not necessarily fills up the whole buffer with new data. Therefore you should make sure you don't write the whole buffer. Change
while((count=in.read(buffer)) >0){
fos.write(buffer);
}
to
while((count=in.read(buffer)) >0){
fos.write(buffer, 0, count);
}
sender
Socket sock = new Socket("127.0.0.1", 5991);
System.out.println("Connecting.........");
File myFile = new File("/root/qrcode/");
File[] files = myFile.listFiles();
OutputStream os = sock.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(files.length);
long totalBytesRead = 0;
int percentCompleted = 0;
for(File file : files)
{
long length = file.length();
dos.writeLong(length);
String name = file.getName();
dos.writeUTF(name);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
int theByte = 0;
while((theByte = bis.read()) != -1)
{
totalBytesRead += theByte;
bos.write(theByte);
}
// System.out.println("file read");
bis.close();
}
dos.close();
//Closing socket
sock.close();
receiver
ServerSocket serverSocket = new ServerSocket(5991);
while(true) {
Socket clientSocket = null;
System.out.println("Starting...");
clientSocket = serverSocket.accept();
InputStream in = clientSocket.getInputStream(); //used
BufferedInputStream bis = new BufferedInputStream(in);
String dirPath ;
dirPath = "/root/NewFolder";
try{
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
File[] files = new File[filesCount];
long f_l = 0;
int count =0 ;
long totalBytesRead = 0;
int percentCompleted = 0;
for(int i = 0; i < filesCount; i++)
{
long fileLength = dis.readLong();
String fileName = dis.readUTF();
f_l = f_l +fileLength;
files[i] = new File(dirPath + "/" + fileName);
FileOutputStream fos = new FileOutputStream(files[i]);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int tot = 0;
for(int j = 0; j < fileLength; j++) {
bos.write(bis.read());
}
bos.close();
}
}catch(Exception ex)
{
System.out.println("error in socket programming ");
}
}
Related
i am trying to transfer large file over java socket transfer happen sucessfully but the file recieved miss some data or some bytes in my opinion. (completely new to the sockets)
Server Side Code
try {
File img = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "/abc.mkv");
byte[] mybytearr = new byte[8192];
FileInputStream fis = new FileInputStream(img);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
long len = fis.read();
DataOutputStream dos = new DataOutputStream(outputStream);
int read;
while ((read = dis.read(mybytearr)) != -1) {
dos.write(mybytearr, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
}
Client Side Code
try {
if (inputStream.available() != 0) {
int bytesRead;
int bufferSize = 0;
bufferSize = socket.getReceiveBufferSize();
DataInputStream dis = new DataInputStream(inputStream);
String name = dis.readUTF();
File db = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + "abc.mkv");
FileOutputStream output = new FileOutputStream(db);
byte[] buffer = new byte[bufferSize];
int read;
while((read = dis.read(buffer)) !=-1) {
output.write(buffer,0,read);
}
}
} catch (IOException e) {
e.printStackTrace();
}
The code I have posted below works for single file transfer over a socket. But it doesn't work for multiple file transfers over a socket. When trying multiple file transfers over the socket the code crashes.
I send multiple files by looping over the server sending code x amount of times, and run the receiving code x amount of times. When trying to send multiple files, the first file will send successfully, the second file name and size will be read successfully but the error in my code happens after this.
In my receiving client I tried to use to suggestion posted here: Java multiple file transfer over socket but had no success.
The error is on the client side.
The question I am asking is: Why isn't this code working for multiple files, and how can I fix it?
Server Sending
try{
byte[] bytes = new byte[(int)file.length()];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
out.println(file.getName()); // Send Filename
out.println(file.length()); // Send filesize
int count;
while ((count = fis.read(bytes)) > 0) {
os.write(bytes, 0, count);
}
os.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client Recieving
try{
String file = in.readLine(); // Read filename
int fileSize = Integer.parseInt(in.readLine()); // Read Filesize
//ERROR HAPPENING ON LINE ABOVE IN LOOPS AFTER THE FIRST
byte [] buf = new byte [fileSize];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
int count = 0;
while (fileSize > 0 && (count = is.read(buf, 0, (int)Math.min(buf.length, fileSize))) != -1){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
The error is a NumberFormatException, on loops after the first when the client is receiving part of a file for the input to the fileSize.
Make sure you flush the PrintWriter before you then write raw bytes directly to the OutputStream that the PrintWriter is attached to. Otherwise, you could write any buffer data out of order to the underlying socket.
But more importantly, make sure that if you use buffered reading on the receiving end that you read the file bytes using the same buffer that receives the file name and file size. You should also transfer the File using smaller fixed chunks, don't allocate a single byte[] array for the entire file size, that is a waste of memory for large files, and likely to fail.
Server:
try{
byte[] bytes = new byte[1024];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
PrinterWriter pw = new PrintWriter(bos);
pw.println(file.getName()); // Send Filename
pw.println(file.length()); // Send filesize
pw.flush();
int count;
while ((count = fis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client:
try{
byte [] buf = new byte [1024];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis);
String file = isr.readLine(); // Read filename
long fileSize = Long.parseLong(isr.readLine()); // Read Filesize
int count = 0;
while ((fileSize > 0) && (count = bis.read(buf, 0, (int)Math.min(buf.length, fileSize))) > 0){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
That being said, you might also consider using DataOutputStream.writeLong() and DataInputStream.readLong() to send/receive the file size in its original binary format instead of as a textual string:
Server:
try{
byte[] bytes = new byte[1024];
FileInputStream fis = new FileInputStream(file);
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
PrinterWriter pw = new PrintWriter(bos);
pw.println(file.getName()); // Send Filename
pw.flush();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeLong(file.length()); // Send filesize
dos.flush();
int count;
while ((count = fis.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
Client:
try{
byte [] buf = new byte [1024];
FileOutputStream fos = new FileOutputStream(file);
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
InputStreamReader isr = new InputStreamReader(bis);
String file = isr.readLine(); // Read filename
DataInputStream dis = new DataInputStream(bos);
long fileSize = dis.readLong(); // Read Filesize
int count = 0;
while ((fileSize > 0) && (count = bis.read(buf, 0, (int)Math.min(buf.length, fileSize))) > 0){
fos.write(buf, 0, count);
fileSize -= count;
}
fos.close();
}catch(IOException e){
e.printStackTrace();
}
I'm trying to send my image from android client to Java server. Size of image that i'm sending is about 99kb, but server always reads a few kb less, sometimes 98, sometimes 96 and so on. I'd like to know why that data is lost and how can I send image in a proper way. Please help :)
Code:
Client(sending image):
public void sendImage(File file){
try {
out = new PrintWriter(socket.getOutputStream(),true);
out.println("Image");
out.println(file.length());
byte[] byteArray = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(byteArray,0,byteArray.length);
OutputStream os = socket.getOutputStream();
FilterOutputStream bos = new FilterOutputStream(os);
bos.write(byteArray,0,byteArray.length);
bos.flush();
os.close();
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server(receiving image):
if(input.equals("Image")){
input = in.readLine();
int fileSize = Integer.parseInt(input);
System.out.println("FILESIZE:" +fileSize);
byte[] byteArray = new byte[fileSize];
FileOutputStream fileOutputStream =
new FileOutputStream("filename.jpg");
BufferedOutputStream bos =
new BufferedOutputStream(fileOutputStream);
BufferedInputStream bis = new BufferedInputStream(in_);
int bytesRead = bis.read(byteArray, 0, byteArray.length);
int current = bytesRead;
do {
bytesRead = bis.read(byteArray, current,
(byteArray.length - current));
if (bytesRead >= 0) {
current += bytesRead;
System.out.println(current);
}
} while (bytesRead != -1);
bos.write(byteArray, 0, current);
bos.flush();
bos.close();
}
EDIT
Problem solved, working code is as follows:
Client side:
public void sendImage(File file){
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeChar('I');
DataInputStream dis = new DataInputStream(new FileInputStream(file));
ByteArrayOutputStream ao = new ByteArrayOutputStream();
int read = 0;
byte[] buf = new byte[1024];
while ((read = dis.read(buf)) > -1) {
ao.write(buf, 0, read);
}
out.writeLong(ao.size());
out.write(ao.toByteArray());
out.flush();
out.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server side:
if(input =='I'){
DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
long length = dis.readLong();
File to = new File("filename.jpg");
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(to));
byte[] buffer = new byte[1024];
int len, current = 0;
System.out.println(length);
while ( current != length) {
len = dis.read(buffer);
dos.write(buffer, 0, len);
current += len;
System.out.println(current);
}
dis.close();
dos.close();
}
From my personal experience PrintWriter and Buffers dont work well together..
As buffers trying to read data before you tell it to it can "steal" data that it should not do. For example if you use any kind of buffered reader to read the input on the server side that buffer will steal some parts at the "start" of the incomming image becuase it think's it's just another line. You could always try using DataInputStream and DataOutputStream instead..
Client:
public void sendImage(File file) {
try {
DataOutputStream out = new DataOutputStream(
socket.getOutputStream());
out.writeChar('I'); // as image,
DataInputStream dis = new DataInputStream(new FileInputStream(file));
ByteArrayOutputStream ao = new ByteArrayOutputStream();
int read = 0;
byte[] buf = new byte[1024];
while ((read = dis.read(buf)) > -1) {
ao.write(buf, 0, read);
}
out.writeLong(ao.size());
out.write(ao.toByteArray());
out.flush();
out.close();
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Server:
// assuming folder structure exists.
public void readImage(Socket s, File to) throws IOException {
DataInputStream dis = new DataInputStream(s.getInputStream());
char c = dis.readChar();
if (c == 'I') {
long length = dis.readLong();
DataOutputStream dos = new DataOutputStream(
new FileOutputStream(to));
byte[] buffer = new byte[1024];
int len;
while ((len = dis.read(buffer)) != -1) {
dos.write(buffer, 0, len);
}
dis.close();
dos.close();
}
}
As a starting point, in the client side, you will also need a loop for reading the local image, because are you sure that...
bis.read(byteArray,0,byteArray.length);
... is really reading the whole image? So you will also need a loop as in the server side.
I am trying to transfer a large file from a server to a client. My code so far works but only if I set the buffer size in the client code to the exact size of the file. I won't always know what the file size is going to be. I keep finding examples that claim it doesn't matter what the size of the file or buffer is because it will just keep reading from the input stream...? However, when I implement the code that supposedly does this, it transfers 0 bytes.
Client:
public static void main (String [] args ) throws IOException {
int bytesRead;
int current = 0;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
Socket sock = null;
try {
sock = new Socket(hostname, 20000);
System.out.println("Connecting...");
// receive file
InputStream is = sock.getInputStream();
fos = new FileOutputStream(FILE_TO_RECEIVE);
bos = new BufferedOutputStream(fos);
//////////// replaced this ////////////////////////////
byte[] buffer = new byte[BUFFER_SIZE];
bytesRead = is.read(buffer,0,buffer.length);
current = bytesRead;
do {
bytesRead = is.read(buffer, current, (buffer.length-current));
if(bytesRead >= 0){ current += bytesRead;}
} while(bytesRead > 0);
bos.write(buffer, 0 , current);
///////////////////////////////////////
// with this:
// int count;
// byte[] buffer = new byte[8192];
// while ((count = is.read(buffer)) > 0)
// {
// bos.write(buffer, 0, count);
// }
//////////// transfers 0 bytes ///////////
bos.flush();
System.out.println("File " + FILE_TO_RECEIVE
+ " downloaded (" + current + " bytes read)");
}
finally {
if (fos != null){ fos.close();}
if (bos != null){ bos.close();}
if (sock != null){ sock.close();}
}
}
Server:
public static void main(String[] args) throws IOException{
FileInputStream fis = null;
BufferedInputStream bis = null;
OutputStream os = null;
ServerSocket servsock = null;
Socket sock = null;
try {
servsock = new ServerSocket(20000);
while (true) {
System.out.println("Waiting...");
try {
sock = servsock.accept();
System.out.println("Accepted connection : " + sock);
// send file
File myFile = new File (FILE_TO_SEND);
byte [] mybytearray = new byte [(int)myFile.length()];
fis = new FileInputStream(myFile);
bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
os = sock.getOutputStream();
System.out.println("Sending " + FILE_TO_SEND + "(" + mybytearray.length + " bytes)");
os.write(mybytearray,0,mybytearray.length);
os.flush();
System.out.println("Done.");
}
finally {
if (bis != null){ bis.close();}
if (os != null){ os.close();}
if (sock!=null){ sock.close();}
}
}
}
finally {
if (servsock != null){
servsock.close();
}
}
}
Thank you for your help
Your copy loops are both different, and both nonsense. One of them isn't even a loop. Try this:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
This works for any buffer of size >= one byte.
Use this at both ends.
*i have have a folder in my pc in c:/ name share and in that i have 4 pictures after running my client and server code i got all 4 picture downloaded in my android emulator but only first image is correctly download other 3 are garbage
here is my code
SERVER SIDE
public class Multiplefilessending
{
public static void main(String[] args) throws IOException,EOFException
{
FileOutputStream fos;
BufferedOutputStream bos;
OutputStream output;
int len;
int smblen;
InputStream in;
boolean flag=true;
DataInputStream clientData;
BufferedInputStream clientBuff;
System.out.println("Waiting for Connection");
ServerSocket serverSocket = new ServerSocket(5991);
Socket clientSocket = null;
clientSocket = serverSocket.accept();
////////////////////////
File myFile = new File("C:/share");
File[] Files = myFile.listFiles();
OutputStream os = clientSocket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeInt(Files.length);
for (int count=0;count<Files.length;count ++)
{
dos.writeUTF(Files[count].getName());
}
for (int count=0;count<Files.length;count ++)
{
int filesize = (int) Files[count].length();
dos.writeInt(filesize);
}
for (int count=0;count<Files.length;count ++)
{
int filesize = (int) Files[count].length();
byte [] buffer = new byte [filesize];
//FileInputStream fis = new FileInputStream(myFile);
FileInputStream fis = new FileInputStream(Files[count].toString());
BufferedInputStream bis = new BufferedInputStream(fis);
//Sending file name and file size to the server
bis.read(buffer, 0, buffer.length); //This line is important
dos.write(buffer, 0, buffer.length);
dos.flush();
//dos.close();
}
if (flag==false){
clientSocket = serverSocket.accept();
flag = true;
}
//Closing socket
//dos.close();
clientSocket.close();
}
}
And
CLIENT SIDE
Socket sock = new Socket("10.0.2.2", 5991);
System.out.println("Connecting.........");
FileOutputStream fos;
BufferedOutputStream bos;
OutputStream output;
DataOutputStream dos;
int len;
int smblen;
InputStream in;
boolean flag=true;
DataInputStream clientData;
BufferedInputStream clientBuff;
while (true)
{
//while(true && flag==true){
while(flag==true)
{
in = sock.getInputStream(); //used
clientData = new DataInputStream(in); //use
clientBuff = new BufferedInputStream(in); //use
int fileSize = clientData.read();
ArrayList<File>files=new ArrayList<File>(fileSize); ArrayList<Integer>sizes = new ArrayList<Integer>(fileSize); //store file size from client
//Start to accept those filename from server
for (int count=0;count < fileSize;count ++){
File ff=new File(clientData.readUTF());
files.add(ff);
}
for (int count=0;count < fileSize;count ++){
sizes.add(clientData.readInt());
}
for (int count =0;count < fileSize ;count ++)
{
if (fileSize - count == 1)
{
flag =false;
}
len=sizes.get(count);
//System.out.println("File Size ="+len);
output = new FileOutputStream("/mnt/sdcard/" + files.get(count));
dos=new DataOutputStream(output);
bos=new BufferedOutputStream(output);
byte[] buffer = new byte[1024];
bos.write(buffer, 0, buffer.length); //This line is important
while (len > 0 && (smblen = clientData.read(buffer)) > 0)
{
dos.write(buffer, 0, smblen);
len = len - smblen;
dos.flush();
}
dos.close(); //It should close to avoid continue deploy by resource under view
}
}
if (flag==false)
{
sock = new Socket("10.0.2.2", 5991);
flag = true;
}
} }
catch (UnknownHostException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
Your read loop is incorrect. You need to constrain the read length so you don't over-run into the next file:
while (len > 0 && (smblen = clientData,read(buffer, 0, len > buffer.length ? buffer.length : (int)len)) > 0)
{
bos.write(buffer, 0, smblen);
len -= smblen;
}
Other comments:
File lengths are longs, not ints.
Use a bigger buffer, at least 8192, and declare it once at the top of the method. You don't need a new one per file.
Don't flush inside the loop.
Don't keep recreating the streams. Use the same ones for the life of the socket, at both ends.
You should be writing to 'bos', not 'dos'. In fact you don't need the DataOutputStream to write to the file at all. Just the BufferedOutputStream and the FileOutputStream.
You should send one filename, one length, then one file, then the next filename, ... That way the sender can stop any time. That gets rid of the initial count, and it also gets rid of all that 'flag' nonsense. If you get EOFException reading the next name, the peer has closed the connection.