Java: read from binary file, send bytes over socket - java

This should be easy, but I can't get my head around it right now. I wanna send some bytes over a socket, like
Socket s = new Socket("localhost", TCP_SERVER_PORT);
DataInputStream is = new DataInputStream(new BufferedInputStream(s.getInputStream()));
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(s.getOutputStream()));
for (int j=0; j<40; j++) {
dos.writeByte(0);
}
That works, but now I dont want to writeByte to the Outputstream, but read from a binary file, then write it out. I know(?) I need a FileInputStream to read from, I just can't figure out hot to construct the whole thing.
Can someone help me out?

public void transfer(final File f, final String host, final int port) throws IOException {
final Socket socket = new Socket(host, port);
final BufferedOutputStream outStream = new BufferedOutputStream(socket.getOutputStream());
final BufferedInputStream inStream = new BufferedInputStream(new FileInputStream(f));
final byte[] buffer = new byte[4096];
for (int read = inStream.read(buffer); read >= 0; read = inStream.read(buffer))
outStream.write(buffer, 0, read);
inStream.close();
outStream.close();
}
This would be the naive approach without proper exception handling - in a real-world setting you'd have to make sure to close the streams if an error occurs.
You might want to check out the Channel classes as well as an alternative to streams. FileChannel instances, for example, provide the transferTo(...) method that may be a lot more efficient.

Socket s = new Socket("localhost", TCP_SERVER_PORT);
String fileName = "....";
create a FileInputStream using a fileName
FileInputStream fis = new FileInputStream(fileName);
create a FileInputStream File Object
FileInputStream fis = new FileInputStream(new File(fileName));
to read from the file
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(
s.getOutputStream()));
reading from it byte after byte
int element;
while((element = fis.read()) !=1)
{
dos.write(element);
}
or reading from it buffer wise
byte[] byteBuffer = new byte[1024]; // buffer
while(fis.read(byteBuffer)!= -1)
{
dos.write(byteBuffer);
}
dos.close();
fis.close();

read a byte from the input and write the same byte to the output
or with a byte buffer it like this:
inputStream fis=new fileInputStream(file);
byte[] buff = new byte[1024];
int read;
while((read=fis.read(buff))>=0){
dos.write(buff,0,read);
}
note that you don't need to use the DataStreams for this

Related

Why does InputStream.read() throw "Read timed out" exception when the inputStream object has previously been wrapped in a BufferedReader?

I have an inputStream object that comes from a socket.
This stream could be all plain text, or it could contain binary data. It has a plain text "prefix" that tells me which type of data it has. I use BufferedReader to read that prefix. Then, if the data type is plain text, I continue to use BufferedReader to read the rest which works just fine.
The problem is when I switch back to using InputStream if the prefix indicates non-text data. The stream seems to be lost somewhere, and I get a java.net.SocketTimeoutException: Read timed out instead.
Code goes something like this:
InputStream instream = mysocket.getInputStream();
BufferedReader br = (new InputStreamReader(instream, "UTF-8")));
byte[] prefixArray = new byte[4];
br.read(prefixArray, 0, 4);
String prefix = new String(prefixArray);
if("text".equals(prefix)) {
// continue to use br.read() here, which works fine...
}else{
byte[] barray = new byte[arraysize]
instream.read(barray, 0, arraysize); // THROWS "Read timed out" exception
}
Is this simply not allowed? Once instream is wrapped in a BufferedReader, it can't be used directly any longer?
A BufferedReader reads from a Reader and stores the data in a buffer for subsequent reads to use. It reads as much as it can at one time, and each time the buffer is emptied, it reads more into the buffer.
Your binary reads time out because the BufferedReader has already read the bytes you are trying to read.
It takes only 4 bytes for you to detect the stream type. Using a Reader for those 4 bytes is overkill. Read the bytes directly from the InputStream first, then create a Reader only for the text data, eg:
InputStream instream = mysocket.getInputStream();
byte[] prefixArray = new byte[4];
int offset = 0;
int numread;
do
{
numread = instream.read(prefixArray, offset, 4-offset);
if (numread == -1) return;
offset += numread;
}
while (offset < 4);
String prefix = new String(prefixArray);
if ("text".equals(prefix))
{
BufferedReader br = new BufferedReader(new InputStreamReader(instream, "UTF-8"));
//...
}
else
{
byte[] barray = new byte[arraysize];
// consider using BufferedInputStream here ...
do
{
numread = instream.read(barray, 0, arraysize);
if (numread == -1) break;
//...
}
while (true);
}
Alternatively, consider using BufferedInputStream for the socket reading, and add other classes on top of it as needed, eg:
InputStream instream = mysocket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(instream);
byte[] prefixArray = new byte[4];
DataInputStream dis = new DataInputStream(bis);
dis.readFully(prefixArray);
String prefix = new String(prefixArray);
if ("text".equals(prefix))
{
InputStreamReader isr = new InputStreamReader(bis, "UTF-8"));
//...
}
else
{
byte[] barray = new byte[arraysize];
do
{
numread = bis.read(barray, 0, arraysize);
if (numread == -1) break;
//...
}
while (true);
}

Solving "socket is closed" exception while copying file from server to client and vice versa

I'm doing simple Client-Server applications which copying file from client to server and vice versa. I'm using Sockets of course. Apps shows Client menu with some options to choose: 1. Make Copy on sever 2. Get fileCopy from Server etc.
The issue is when I'm choosing first option, I can't do second one. I read about this exception, but i have no idea how to solve this problem. I'm looking forward for your ideas.
There is part of clientside code:
public Client(String host, int port) {
try {
s = new Socket(host, port);
System.out.println("Witaj w programie");
boolean finished = false;
Scanner sc = new Scanner(System.in);
while(!finished){
System.out.println("\n\n1.Zrob kopie zapasowa pliku");
System.out.println("2. Przywroc kopie");
System.out.println("0.Zakoncz");
char c = sc.nextLine().charAt(0);
switch(c){
case '1':
this.sendMessage(1);
makeCopy(s);
//s.close();
break; ...
sendMessage method code:
public void sendMessage(int message_id) throws IOException{
oos = new ObjectOutputStream(s.getOutputStream());
ois = new ObjectInputStream(s.getInputStream());
oos.writeInt(message_id);
oos.flush();
}
and makeCopy method code:
private void makeCopy(Socket clientSock) throws IOException {
File file = new File("D:\\klient\\doKopii.bmp");
DataOutputStream dos = new DataOutputStream(clientSock.getOutputStream());
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[4096];
while (fis.read(buffer) > 0) {
dos.write(buffer);
}
fis.close();
dos.close();
}
Download copy from Server code:
private void saveFile(Socket clientSock) throws IOException {
//DataInputStream dis = new DataInputStream(clientSock.getInputStream());
FileOutputStream fos = new FileOutputStream("D:\\klient\\przywroconaKopia.bmp");
File zSerwera = new File("D:\\serwer\\kopiaPliku.bmp");
byte[] buffer = new byte[4096];
int filesize = (int)zSerwera.length();
int read = 0;
int totalRead = 0;
int remaining = filesize;
while((read = ois.read(buffer, 0, Math.min(buffer.length, remaining))) > 0) {
totalRead += read;
remaining -= read;
System.out.println("read " + totalRead + " bytes.");
fos.write(buffer, 0, read);
}
//fos.close();
//ois.close();
}
I am aware of that this does not work because of DataOutputStream closing which means socket is also closed. I deleted this line, but after choosing one option then second (when first one has done), application just freezes.
oos = new ObjectOutputStream(s.getOutputStream());
ois = new ObjectInputStream(s.getInputStream());
public void sendMessage(int message_id) throws IOException{
oos.writeInt(message_id);
}
make oos and ois as instance variables and make sure that they are instantiated only for one single time.
why you have to get a dataoutput stream seperately you can send byte array in same objectoutputstream
private void makeCopy(Socket clientSock) throws IOException {
File file = new File("D:\\klient\\doKopii.bmp");
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[4096];
while (fis.read(buffer) > 0) {
oos.write(buffer);
}
}
this is not very good coding practise bt maybe u should try this approach
There are several problems here.
You need to send the file length ahead of the file, and read exactly that many bytes at the receiver, as shown in this answer.
Don't mix stream types, and don't keep creating new streams. Use the same ObjectInputStream/ObjectOutputStream pair for the life of the socket, at both ends.

Can't open received amr/jgp file from socket on android

To send and receive file via socket over Wifi I have used following code...
Client side :
Socket socket = new Socket(dstAddress, dstPort);
int bufferSize=socket.getReceiveBufferSize();
InputStream in=socket.getInputStream();
DataInputStream clientData = new DataInputStream(in);
String fileName = clientData.readUTF();
System.out.println(fileName);
OutputStream output = new FileOutputStream("/sdcard/"+fileName);
byte[] buffer = new byte[bufferSize];
int read;
while((read = clientData.read(buffer)) != -1){
output.write(buffer, 0, read);
}
//close every thing
output.flush();
output.close();
socket.close();
Server side:
File file = new File(Environment.getExternalStorageDirectory(), "/sdcard/test.amr");
byte[] mybytearray = new byte[8092];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
OutputStream os;
try {
os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(file.getName());
dos.writeLong(mybytearray.length);
int read;
while((read = dis.read(mybytearray)) != -1){
dos.write(mybytearray, 0, read);
}
os.flush();
os.close();
socket.close();
At this point I am receiving file 'test.amr' from server without change of its original size.
But when I try to play the file in client device it can't be played.
Note : mp3, avi and txt file received using above code can be opened and played perfectly.
Please suggest how to solve this issue.
Finally I have solved the above problem by just removing
dos.writeLong(mybytearray.length);
line form server code...
as per suggestion of greenapps.
My revised server code is:
File file = new File(Environment.getExternalStorageDirectory(), "/sdcard/test.amr");
byte[] mybytearray = new byte[8092];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
DataInputStream dis = new DataInputStream(bis);
OutputStream os;
try {
os = socket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(file.getName());
int read;
while((read = dis.read(mybytearray)) != -1){
dos.write(mybytearray, 0, read);
}
os.flush();
os.close();
socket.close();
You're writing the buffer size as a long but you're not reading it. So the long is being read as part of the image. As writing your sending buffer size has no conceivable relevance to the receiver, you should remove the writeLong(mybytearray.length) call from the sender.

avoiding garbage data while reading data using a byte buffer

I am trying to write a program to transfer a file between client and server using java tcp sockets I am using buffer size of 64K but The problem I am facing is that when when the tcp sometimes fail to send the whole 64K it sends the remaing part for example 32K in anther go
There for A garbage data of some Spaces or so is being taken by the buffer at reading side to make 64K complete and thus unnecessary data is making the file useless at receiving side.
Is there any solution to overcome this problem ???
I am using TCP protocol this code is using to send data to client
Server-side code
File transferFile = new File ("Document.txt");
byte [] bytearray = new byte [1024];
int byRead=0;
FileInputStream fin = new FileInputStream(transferFile);
BufferedInputStream bin = new BufferedInputStream(fin);
OutputStream os = socket.getOutputStream();
while(byRead>-1) {
byRead=bin.read(bytearray,0,bytearray.length);
os.write(bytearray,0,bytearray.length);
os.flush();
}
Client-side code
byte [] bytearray = new byte [1024];
InputStream is = socket.getInputStream();
FileOutputStream fos = new FileOutputStream("C:\\Users\\NetBeansProjects\\"+filename);
BufferedOutputStream bos = new BufferedOutputStream(fos);
bytesRead = is.read(bytearray,0,bytearray.length);
currentTot = bytesRead; System.out.println("Data is being read ...");
do {
bytesRead = is.read(bytearray, 0, (bytearray.length));
if(bytesRead == 0) continue;
if(bytesRead >= 0) currentTot += bytesRead;
bos.write(bytearray,0,bytearray.length);
} while(bytesRead > -1);
here I tried to skip the loop if the byte is empty by continue; statement but it is not
working.
bos.write(bytearray,0,bytearray.length);
This should be
bos.write(bytearray,0,bytesRead);
The region after 'bytesRead' in the buffer is undisturbed by the read. It isn't 'garbage'. It's just whatever was there before.
use CLIENT Side Code as below to get the total write bytes without garbage
int availableByte = socket.available();
if (availableByte > 0) {
byte[] buffer = new byte[availableByte];
int bytesRead = socketInputStream.read(buffer);
FileOutputStream fileOutputStream = new FileOutputStream(FilePath, true);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write(buffer.toString());
bufferedWriter.close();
}

Socket Programming file upload issues?Complete file not uploading

Hi i am using the following code for uploding my file from android phone to the server bt the file does not upload completely..e.g i uploded a 11kb file and got only 8kb file at the server.What am i doing wrong?
Client side
Socket skt = new Socket"112.***.*.**", 3000);
String FileName=fil.getName();
PrintWriter out2 = new PrintWriter(new BufferedWriter(new OutputStreamWriter(skt.getOutputStream())),true);
out2.println("Upload");
out2.println(FileName);
out2.println(spinindx);
out2.println(singleton.arrylst_setngs.get(0).toString());
out2.println(singleton.arrylst_setngs.get(1).toString());
out2.println(singleton.arrylst_setngs.get(2).toString());
out2.println(singleton.arrylst_setngs.get(3).toString());
out2.println(singleton.arrylst_setngs.get(4).toString());
out2.flush();
//Create a file input stream and a buffered input stream.
FileInputStream fis = new FileInputStream(fil);
BufferedInputStream in = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(skt.getOutputStream());
//Write the file to the server socket
int i;
byte[] buf = new byte[512];
while ((i = in.read(buf)) != -1) {
out.write(buf,0,i);
publishProgress(in.available());
System.out.println(i);
}
//Close the writers,readers and the socket.
in.close();
out.flush();
out.close();
out2.close();
skt.close();
}
catch( Exception e ) {
System.out.println(e);
}
The server side
InputStream inStream = socket.getInputStream();
BufferedReader inm = new BufferedReader(new InputStreamReader(inStream));
String Request=inm.readLine();
if(Request.equals("Upload")){
fileName = inm.readLine();
chosn = inm.readLine();
lt=inm.readLine();
cs = inm.readLine();
om = inm.readLine();
o = inm.readLine();
check=inm.readLine();
//Read, and write the file to the socket
BufferedInputStream in = new BufferedInputStream(inStream);
int i=0;
File f=new File("D:/data/"+filePrefx+fileName);
if(!f.exists()){
f.createNewFile();
}
FileOutputStream fos = new FileOutputStream("D:/data/"+filePrefx+fileName);
BufferedOutputStream out = new BufferedOutputStream(fos);
byte[] buf = new byte[512];
while ((i = in.read(buf)) != -1) {
System.out.println(i);
out.write(buf,0,i);
System.out.println("Receiving data...");
}
in.close();
inStream.close();
out.close();
fos.close();
socket.close();
Looks like you are using both a BufferedReader and a BufferedInputStream on the same underlying socket at the server side, and two kinds of output stream/writer at the client. So your BufferedReader is buffering, which is what it's supposed to do, and thus 'stealing' some of the data you're expecting to read with the BufferedInputStream. Moral: you can't do that. Use DataInputStream & DataOutputStream only, and writeUTF()/readUTF() for the 8 lines you are reading from the client before the file.
You shared the same underlying InputStream between your BufferedReader and bufferedInputStream.
What happened is, when you do the reading through BufferedReader, it reads more than the a few lines you requested from the underlying InputStream into its own internal buffer. And when you create the BufferedInputStream, the data has already been read by the BufferedReader. So Apart from what EJP suggested not to use any buffered class, you can create the BufferedInputStream, and then create the Reader on Top of it. The code is something like this:
BufferedInputStream in = new BufferedInputStream(inStream);
Reader inm = new InputStreamReader(in);
Add it to the beginning of your server code and remove this line:
BufferedInputStream in = new BufferedInputStream(inStream);
See this, i never tried though
void read() throws IOException {
log("Reading from file.");
StringBuilder text = new StringBuilder();
String NL = System.getProperty("line.separator");
Scanner scanner = new Scanner(new FileInputStream(fFileName), fEncoding);
try {
while (scanner.hasNextLine()){
text.append(scanner.nextLine() + NL);
}
}
finally{
scanner.close();
}
log("Text read in: " + text);
}
Shamelessly copied from
http://www.javapractices.com/topic/TopicAction.do?Id=42

Categories

Resources