File received from socket is missing when run on Android - android

I am building an android app, we build a socket to transfer file from this end to another end.
The file is sent through computer (when we test it on the computer), it works very well.
But when we build app to android, and send file from this android to another android through the socket that we put on a computer (used as server) so the received file is missing (file size is not enough). Sometime it is enough, but sometime is not enough, but almost time it is NOT enough.
It totally works very well on PC when testing.
Hope you guys have some ideas to help me.
This is my code:
1/ Code at Java server application - send file:
int countBufferReceive = 0;
byte[] buffer = new byte[1024 * 1024];
int numByte = 0;
while ((numByte = this.receiveStream.read(buffer, 0, buffer.length)) > 0) {
client.sendStream.write(buffer, 0, numByte);
client.sendStream.flush();
countBufferReceive += numByte;
if (countBufferReceive == fileLength)
break;
}
2/ Code at Android app - receive file:
int countBufferReceive = 0;
byte[] buffer = new byte[1024 * 1024];
int numByte = 0;
while ((numByte = ConnectServer.receiveStream.read(buffer, 0, buffer.length)) > 0) {
fos.write(buffer, 0, numByte);
fos.flush();
countBufferReceive += numByte;
if (countBufferReceive == fileLength)
break;
}
fos.close();
Thank you,

Related

Chunk size sent to client affects the file completeness

Update: The problem must be on the Android side, not Qt.
The problem is simply I can't send more than 1000 bytes (correctly) from Windows (via Qt) to Android. Here I post full information:
Code in Qt Creator (Windows side):
QFile inputFile(fileInfo->absoluteFilePath());
QByteArray read;
inputFile.open(QIODevice::ReadOnly);
int size = 0;
while(1){
read.clear();
read = inputFile.read(1000);
qDebug()<< "Read : " <<read.size();
size += read.size();
if(read.size() == 0){
break;
}
QByteArray toWrite(read);
newSocket->write(toWrite);
newSocket->flush();
newSocket->waitForBytesWritten();
this->sleep(1);
}
inputFile.close();
qDebug()<<"Transfer Done! " << size << " bytes";}
Java code (Android side):
DataOutputStream dos;
DataInputStream dis;
Socket s;
s = new Socket("192.168.137.1",8080);
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream());
while(true){
if(dis.available() > 0 ) {
int chunkSize = 1000;
byte[] b = new byte[chunkSize];
dis.read(b);
writeToExternalStoragePublic("test.png",b);}
The code works pretty good. It even works when I set the chunks size on both sides to 1,000,000, and the data is written to Android, but a lot of the bytes are empty.
Check these photos from hex Workshop data visualizer. Using 1000 as chunkSize in the left and 2000 in right.
Here are the files:
1000ChunkSize
2000ChunkSize
The problem is 1000 is too slow, and it takes a lot of time even for small files though it works. What do you suggest?
A possible problem was the timing on the server side even though it has:
waitForBytesWritten();
I put
this->sleep(1);
But it didn't help.
Update: The problem must be on the Android side, not Qt.

InputStream.read() hangs on reading a file

In my app, i'm sending a file from a client, using sockets. On the other side, another client receive the file using InputStream and then bufferedOutputStream save the file in the system.
I don´t know why, the file isn´t utterly transmited. I think this is because of network overload, anyway, i don´t know how to solve it.
Transmiter is:
Log.d(TAG,"Reading...");
bufferedInputStream.read(byteArrayFile, 0, byteArrayFile.length);
Log.d(TAG, "Sending...");
bufferedOutputStream.write(byteArrayFile,0,byteArrayFile.length);
bufferedOutputStream.flush();
Receiver is:
bufferedOutputStream=new BufferedOutputStream(new FileOutputStream(file));
byteArray=new byte[fileSize];
int currentOffset = 0;
bytesReaded = bufferedInputStream.read(byteArray,0,byteArray.length);
currentOffset=bytesReaded;
do {
bytesReaded = bufferedInputStream.read(byteArray, currentOffset, (byteArray.length-currentOffset));
if(bytesReaded >= 0){ currentOffset += bytesLeidos;
}
} while(bytesReaded > -1 && currentOffset!=fileSize);
bufferedOutputStream.write(byteArray,0,currentOffset);
You don't state where filesize came from, but there are numerous problems with this code. Too many to mention. Throw it all away and use DataInputStream.readFully(). Or use the following copy loop, which doesn't require a buffer the size of the file, a technique which does not scale, assumes that the file size fits into an int, and adds latency:
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
Use this at both ends. If you're sending multiple files via the same connection it gets more complex, but you haven't stated that.

Files go missing after copying - Android

I am moving files(around 100-2000 files each of size 100-200KB) via thread from one folder to another. All goes well but on some Samsung & LG devices with sdcard, suddenly after copying, all or some of them go missing.
This does not happen every time, but approximately around once in every 20 times.
I have tried 3 techniques so far:
public void copyMethodA(File src, File dst){
if(!dst.exists()){
src.renameTo(dst);
}
}
copyMethodA(); resulted in loss of file in most of the times.
public void copyMethodB(File sourceFile, File destFile) throws IOException {
if (!destFile.exists()) {
destFile.createNewFile();
}
try {
FileChannel source = new FileInputStream(sourceFile).getChannel();
FileChannel destination = new FileOutputStream(destFile).getChannel();
destination.transferFrom(source, 0, source.size());
} finally {
source.close();
destination.close();
}
}
copyMethodB(); resulted in loss of file comparatively less number of times than A.
public void copyMethodC(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
byte[] buf = new byte[10240];
int len;
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
out.close();
}
copyMethodC(); very rarely resulted in loss of files. Hence currently using this one.
All 3 methods worked fine without a single loss of file on Xperia C & Nexus 5(both using internal storage)
But loss of files was observed on LG Optimus One(using sdcard) and some Samsung devices(using internal or sdcard)
Info about devices on which I have tested:
Nexus 5 - Android 4.4.2
Xperia C - Android 4.2.2
LG Optimus One - Android 2.3.3
Samsung devices - Android 4.0 and above
(I guess this problem isn't related to version of Android used)
I am avoiding to use huge 3rd party File IO API's as my Android app's size is just 300KB. Using API like Apache commons.io will bloat it to around 2.5MB
Is there any other safe, secure & better way to copy files ?
Thanks.
I think you should something like this :
you should check the return value of renameTo as, as the javadoc states it, there are many reasons for it to fail.
If the renameTo call failed, use the third way, with try / catch blocks to catch IOException when reading / writing the streams and make sure you only delete the source file if the copy was successful. You can then check the exception to understand why the copy failed and possibly retry it later.
I'm doing this (with a 1024 bytes buffer, like in #beni answer) to copy a few hundred files and I've never seen any loss.
I'm using this function and always works. I test this code on Nexus 5. in.read(buf) method returns -1 when is in the end of the file in other case return the number of the bytes readed. So, try this.
public static void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}

Loading and executing a binary file on Android

Is there any way to execute Binary file in an android application. without JNI wrapper approach.
plz give me sample codes.
try this
public void pump(InputStream in, OutputStream out, int size) {
byte[] buffer = new byte[4096]; // Or whatever constant you feel like using
int done = 0;
while (done < size) {
int read = in.read(buffer);
if (read == -1) {
throw new IOException("Something went horribly wrong");
}
out.write(buffer, 0, read);
done += read;
}
// Maybe put cleanup code in here if you like, e.g. in.close, out.flush, out.close
}
from this link Reading and writing binary file in Java (seeing half of the file being corrupted)

Why is data from Arduino to Android using Android host api garbled?

I followed this tutorial to get started using Android host api with an Arduino board. I am using the Arduino Uno. I am able to transmit data and turn on a LED on the Arduino board and I can receive feedback from the Arduino board. I am trying to write to my Android device over the USB connection from the Arduino board like so:
Serial.print("Test");
I am receiving the Arduino data on the Android side like this:
byte[] buffer = new byte[10];
int bytes;
//try-catch statements omitted for simplicity
bytes = mUsbConnection.bulkTransfer(mUsbEndpointIn, buffer, buffer.length, 0);
Every once and awhile the data will be intact but more often than not, what I receive from the Arduino is a garbled mix of those letters from my original message(t,e,s, and t). Many times only 1 or 2 letters are displayed. If anyone could point me in the right direction or share some similar experience I would be appreciative. Thanks.
Edit
When I print out the data into Logcat, there are multiple copies of the data. For example, if I receive "ste" from Arduino, it will be printed out 2-5 times in Logcat.
I think I found something that works at least temporarily:
public void run(){
int i = 0;
byte[] buffer = new byte[4];
byte[] finalBuffer = new byte[8];
byte[] sendBuffer = new byte[8];
int bytes = 0;
while(true){
try{
bytes = mUsbConnection.bulkTransfer(mUsbEndpointIn, buffer, buffer.length, 0);
if (bytes == EXIT_CMD) {
return;
}
if (bytes > 0){
byte[] temporaryBuffer = new byte[bytes];
System.arraycopy(buffer, 0, temporaryBuffer, 0, bytes);
System.arraycopy(temporaryBuffer, 0, finalBuffer, i, bytes);
i += bytes;
java.util.Arrays.fill(buffer, (byte) 0);
}
//Dollar sign terminates string to indicate end of line
if (finalBuffer[7] == 36){
i = 0;
System.arraycopy(finalBuffer, 0, sendBuffer, 0, sendBuffer.length);
messageHandler.obtainMessage(UsbHostTestActivity.ARDUINO_MESSAGE,
sendBuffer.length, -1, sendBuffer).sendToTarget();
java.util.Arrays.fill(finalBuffer, (byte) 0);
}
I had to send strings that were 8 characters exactly from Arduino and they had to end with a dollar sign($) in order to indicate the end of the line, but the data being passed to my message handler always seemed to be correct. It's not the most robust solution but maybe someone can modify it to make it better or take another approach? Please let me know!

Categories

Resources