Error Sending ONLY Image/Video file - java

I'm trying to share files between my pc & android device over wifi. Strange thing is text and audio files are being perfectly transferred, while the images and video files fail to render.
Here's the main piece of code:
Sender:
BufferedOutputStream writer = new BufferedOutputStream(client.getOutputStream());
InputStream stream = new FileInputStream(file);
while ((read = stream.read(buffer)) != -1)
writer.write(buffer, 0, read);
Receiver:
BufferedInputStream input = new BufferedInputStream(client.getInputStream());
OutputStream outputStream = new FileOutputStream(file, true);
while (!store.complete) {
read = input.read(buffer, 0 , MAX_SIZE_OF_BUFFER);
String data = new String(buffer);
// Need to do some data manipulation (like removing a string which i appended
// while sending )
outputStream.write(data.getBytes());
}
Note: Even the size of the image/video file at the receiver is equal to the file being sent, still it fails to render.
Thanks in Advance!! :)

You can't assume that converting a byte[] to String and then converting it back to byte[] will give you the original byte[].
For example, the following does not output the original byte array:
byte[] buffer = {-127};
for (byte b : new String(buffer).getBytes()) { System.out.print(" " + b); }
To solve your problem, do your data manipulation (appending and removing your data) as bytes and don't convert to and from String.

Related

How send the http post request with DataOutPutStream properly so server can handle it

I wish somebody tell me what is the different of just write a file and a file with another kind of bytes.
server using, python3 flask
I think maybe the android retrofit etc useful, but I would like to try with the classic method, HTTPUrlConnection
So i successfully sending just one or multi-parameter of string to the server.
I also successfully just by sending a file to the server.
- my file will just 5-second audio or video mp4 that creates from real android.
When i tried just two, param and a list of byte, len(list) = 2, i can get back my sent file, but the concat style of the bytes just could not acheive it.
but when I combine both of it, i found out that when the file is chopped as multi-part, the file just could not recover.
I know delimeter is useful, I tried with a string of "--------------" to split it in server-side.
list= request.data.split(b"------------------------------")
newList= list[1:]
data = b""
for part in newList:
data += part
how i recover the file (python)
def createAudioFromDataReceived(fileName, data):
with open(fileName, 'wb') as wfile:
wfile.write(data)
the basic code write to dataOutPutStream
public void writeFilesParamToDataOutputStream(HttpURLConnection conn, File file, String action) throws IOException {
byte[] buffer;
FileInputStream fileInputStream = new FileInputStream(file);
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
buffer = new byte[1024 * 1024];
int length = 0;
while ( ( length = fileInputStream.read( buffer ) ) > 0 ) {
dos.write(buffer, 0, length);
}
dos.flush();
fileInputStream.close();
dos.close();
}
to add extra line to the dataOutputStream
//Bytes
byte[] bytes = "toSend".getBytes();
dos.write(bytes);
dos.write("------------------------------");
ops, reference are seen before
roughly this kind How to send data from server to Android?
i could not imagine the byte got alot of "-" and need "/r/n" ...
delimiter should be some thing like
String delimiter = "--aaWEdFXvDF--" + "\r\n";

Java reading a file and sending it via DatagramSocket

Using Java, I am trying to send some file data over a DatagramSocket. I need to read a file in 1000-byte chunks and send them over as packets. My code:
reads a file into a byte array wrapped in a byte buffer
places the data in a packet and sends it
has the receiver open the packet and re-write the contents to a new file.
I am having a problem with writing the byte array back to a file. Please see my code below.
Client/Sender:
byte[] data = new byte[1000];
ByteBuffer b = ByteBuffer.wrap(data);
DatagramPacket pkt;
File file = new File(sourceFile);
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
CRC32 crc = new CRC32();
while(true){
b.clear();
b.putLong(0); // I need to put the checksum at the beginning for easy retrieval
bytesRead = bis.read(data);
if(bytesRead==-1) { break; }
crc.reset();
crc.update(data, 8, data.length-8);
long chksum = crc.getValue();
b.rewind();
b.putLong(chksum);
pkt = new DatagramPacket(data, 1000, addr); // addr is valid, works fine
sk.send(pkt);
}
bis.close();
fis.close();
Server/Receiver:
DatagramSocket sk = new DatagramSocket(port);
File destfile = new File("hello.txt");
FileOutputStream fos = new FileOutputStream(destfile);
BufferedOutputStream bos = new BufferedOutputStream(fos);
PrintStream ps = new PrintStream(fos);
byte[] data = new byte[1000];
DatagramPacket pkt = new DatagramPacket(data, data.length);
ByteBuffer b = ByteBuffer.wrap(data);
CRC32 crc = new CRC32();
while(true) {
pkt.setLength(data.length);
sk.receive(pkt);
b.rewind();
// compare checksum, print error if checksum is different
// if checksum is the same:
bos.write(data); // Where the problem seems to be occurring.
// send acknowledgement packet.
}
bos.close();
fos.close();
Here, I am mainly having issues with writing the file back. With a small text file that says Hello World!, I get a strange output that says vˇ]rld!. Also, the input file is only 12 bytes but the file that the receiver creates is 1KB.
I think my issue is dealing with a byte buffer - I've written a program that copies files using file streams and buffered streams, which worked well. But I'm confused with how streams work in this sort of situation, and I would really appreciate any help. Thanks!
In the sender's data[] you overwrite the text, which was read from the file by the crc! You have to read the text in a position after the long. When correcting this in the Sender, it works:
//int bytesRead = bis.read(data); --old code
int bytesRead=bis.read(data,8,data.length-8);
Furthermore you send 1000 bytes, so will receive 1000 bytes, which will go into the destfile.
BTW: you do not check the crc in the server.... so why send it ?

Client-Server not sending the entire file

When I run my client server - which is connecting and I try to send a file it doesn't won't send the whole file which is pulling errors else where, it gets about halfway through and constantly stops at the same part. This set up works when running the server-client on the same machine so I am completely confused
Server --->
// output (a DataOutputstream) is set up elsewhere and messages are sent and received properly
output.writeInt((int)file.length());
// send file
byte [] mybytearray = new byte [(int)file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(mybytearray,0,mybytearray.length);
System.out.println("Sending " + file + "(" + mybytearray.length + " bytes)");
output.write(mybytearray,0,mybytearray.length);
output.flush();
System.out.println("Done.");
Client --->
// input (a DataInputstream) is set up elsewhere and messages are sent and received properly
String FILE_TO_RECEIVED = "Load_From.xml";
File file = new File(FILE_TO_RECEIVED);
int FILE_SIZE = input.readInt();
if(FILE_SIZE!=0){
// receive file
System.out.println("received file size : " + FILE_SIZE);
byte [] mybytearray = new byte [FILE_SIZE];
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = input.read(mybytearray, 0, mybytearray.length);
bos.write(mybytearray, 0, bytesRead);
You are only reading part of the data, both when reading the file and when reading the socket. The read method returns the number of bytes read, and you need a loop to read everything. For example,
int read = 0, offset = 0;
while ((read = bis.read(mybytearray, offset, mybytearray.length - offset) != -1) {
offset += read;
}
Or you can use classes from the standard library, for example DataInputStream has a readFully method.
DataInputStream dis = new DataInputStream(fis);
dis.readFully(mybytearray);
Please see the documentation of read() at: http://docs.oracle.com/javase/7/docs/api/java/io/InputStream.html#read(byte[],%20int,%20int).
In particular:
An attempt is made to read as many as len bytes, but a smaller number may be read. The number of bytes actually read is returned as an integer.
This means that if the length returned is not what you expect and you haven't encountered the end of file yet, you should call read() again (in a loop).

How do I send file name with file using sockets in Java? [duplicate]

This question already has answers here:
Java multiple file transfer over socket
(3 answers)
Closed 5 years ago.
I have the following code which transfers file via Sockets. How do I send the file name?
Socket socket = new Socket("localhost", port);//machine name, port number
File file = new File(fileName);
// Get the size of the file
long length = file.length();
if (length > Integer.MAX_VALUE)
{
System.out.println("File is too large.");
}
byte[] bytes = new byte[(int) length];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
int count;
while ((count = bis.read(bytes)) > 0)
{
out.write(bytes, 0, count);
}
out.flush();
out.close();
fis.close();
bis.close();
socket.close();
You can invent your own protocol for your socket. If all you need is a filename and data, DataOutputStream.writeUTF is easiest:
BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
try (DataOutputStream d = new DataOutputStream(out)) {
d.writeUTF(fileName);
Files.copy(file.toPath(), d);
}
The peer must use the same protocol, of course:
BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
try (DataInputStream d = new DataInputStream(in)) {
String fileName = d.readUTF();
Files.copy(d, Paths.get(fileName));
}
Use a character that can never be in a file name - such as a null (0x00, \0, whatever you want to call it). Then send a 64 bit integer that indicates how long, in bytes, the file is (make sure you don't run into buffer overflows, little endian/big endian issues, etc... just test all edge cases). Then send the file data. Then the ending socket will know which part is the file name, the file length and the file data, and will even be ready for the next file name if you want to send another.
(if file names can be arbitrary characters including control characters, ouch! Maybe send a 64 bit integer length of file name, the file name, a 64 bit integer length of file data, the file data, repeat ad infinitum?)
EDIT: To send a 64 bit integer over a socket, send its constituent bytes in a specific order, and make sure sender and receiver agree on the order. One example of how to do this is How to convert a Java Long to byte[] for Cassandra?
I tried to wrap a buffer which cause MalfuctionUTF and putting it on try-with resource closes the underlining socket stream and cause connection reset exceptionFollowing code worked for me
Client
DataOutputStream d = new DataOutputStream(out);
d.writeUTF(filename);
d.writeLong(length);
Server
DataInputStream d = new DataInputStream(in);
filename = d.readUTF();
fileLength = d.readLong();

How to write file data correctly?

My application is unable to transfer data properly over a socket connection and write it to a file properly. Files over about 65,535 bytes get corrupted and are no longer recognized by the programs designed to run them.
I have been able to send small .doc and .txt files successfully, but .mp3 .wmv .m4a .avi and just about anything else does not work. Neither do larger docs.
I have looked all over the internet for a solution to this problem. I have repeatedly tweaked the I/O code to fix the problem but it still doesn't work! Here is the I/O code in the super class that handles sending and receiving files. If you need anymore information/other parts of code, let me know.
protected void sendFile() throws IOException {
byte[] bytes = new byte[(int) file.length()];
buffin = new BufferedInputStream(new FileInputStream(file));
int bytesRead = buffin.read(bytes,0,bytes.length);
System.out.println(bytesRead);
out = sock.getOutputStream();
out.write(bytes,0,fileBytes);
out.flush();
out.close();
}
protected void receiveFile() throws IOException {
byte[] bytes = new byte[fileBytes];
in = sock.getInputStream();
for(int i=0;i<fileBytes;i++) {
in.read(bytes);
}
fos = new FileOutputStream("/Datawire/"+fileName);
buffout = new BufferedOutputStream(fos);
buffout.write(bytes,0,fileBytes);
buffout.flush();
buffout.close();
}
UPDATED CODE (that works):
protected void sendFile() throws IOException {
if((file.length())<63000) {
byte[] bytes = new byte[(int)file.length()];
buffin = new BufferedInputStream(new FileInputStream(file));
buffin.read(bytes,0,bytes.length);
out = sock.getOutputStream();
out.write(bytes,0,bytes.length);
out.close();
} else {
byte[] bytes = new byte[32000];
buffin = new BufferedInputStream(new FileInputStream(file));
out = sock.getOutputStream();
int bytesRead;
while((bytesRead = buffin.read(bytes))>0) {
out.write(bytes,0,bytesRead);
}
out.close();
}
}
protected void receiveFile() throws IOException {
if(fileBytes<63000) {
byte[] bytes = new byte[32000];
in = sock.getInputStream();
System.out.println(in.available());
in.read(bytes,0,fileBytes);
fos = new FileOutputStream("/Datawire/"+fileName);
buffout = new BufferedOutputStream(fos);
buffout.write(bytes,0,bytes.length);
buffout.close();
} else {
byte[] bytes = new byte[16000];
in = sock.getInputStream();
fos = new FileOutputStream("/Datawire/"+fileName);
buffout = new BufferedOutputStream(fos);
int bytesRead;
while((bytesRead = in.read(bytes))>0) {
buffout.write(bytes,0,bytesRead);
}
buffout.close();
}
}
The issue is that you are sending only chunks of it. That is, you are only sending 64k of the file ever. If the file is ever larger then 64k the other end will never see it.
You want to continously read from the BufferedInputStream until the read() returns either less then the length or -1.
Your code is completely wrong. This is how to copy a stream in Java:
int count;
byte[] buffer = new byte[8192]; // more if you like but no need for it to be the entire file size
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
You should use this both when sending the file and when receiving the file. At present your sending method hopes that the entire file fits into memory; fits into INTEGER_MAX bytes; and is read in one chunk by the read method, without even checking the result. You can't assume any of those things. Your receive method is complete rubbish: it just keeps overwriting the same array, again without checking any read() results.
EDIT: Your revised code is just as bad, or worse. You are calling read() to check for EOS and then throwing that byte away, and then calling read() again and throwing away the read count it returns. You pointlessly have a different path for files < 64000, or 63000, or whatever it is, that has zero benefit except to give you two code paths to test, or possibly four, instead of one. The network only gives you 1460 bytes at a time at best anyway so what is the point? You already have (a) a BufferedInputStream with a default buffersize of 8192, and (b) my code that uses a byte[] buffer of any size you like. My code above works for any amount of data in two lines of executable code. Yours is 20. QED.
I suggest that you use some good library to read and write file contents as well as socket read/write. For example Apache Commons IO. If you insist on writig code yourself, do it smaller chunks rather than the whole file at once.
You have to consider that InputStream.read returns the number of bytes read which may be less than the total number of bytes in the file.
You would probably be better off just letting something like CopyUtils.copy take care of this for you.
You need to loop until bytesRead < 0. You need to make sure that fileBytes is => than the transferred file.
protected void receiveFile() throws IOException {
byte [] bytes = new byte [fileBytes];
InputStream is = sock.getInputStream();
FileOutputStream fos = new FileOutputStream("/Datawire/"+fileName);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = is.read(bytes,0,bytes.length);
int current = bytesRead;
do {
bytesRead =
is.read(bytes, current, (bytes.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
bos.write(bytes, 0 , current);
bos.flush();
bos.close();
}

Categories

Resources