So, I have a simple Android app that connects to a Java Server application using Sockets.
Specifically, I want to be able to send a file from the Server application to the Android app and then store that file in internal memory on the device.
The basis of the server code for transferring the file is:
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File(System.getProperty("user.home"), "text.txt")));
BufferedOutputStream bos = new BufferedOutputStream(clientSocket.getOutputStream());
byte buffer[] = new byte[1024];
int read;
while ((read = bis.read(buffer)) != -1) {
bos.write(buffer, 0, read);
}
bos.flush();
bos.close();
and the Client code to receive the file is as follows:
BufferedInputStream bis = new BufferedInputStream(clientSocket.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(openFileOutput("text.txt", Context.MODE_PRIVATE));
byte buffer[] = new byte[1024];
int read;
while ((read = bis.read(buffer)) != -1) {
bos.write(buffer, 0, read);
}
bos.flush();
bos.close();
The code appears to work fine when the client code is in a standard Java application, that is, the file sends successfully from server to client.
The problem arises when I use this code in an Android app. (Note: I use a standard FileOutputStream in the standard Java app instead of the
openFileOutput("text.txt", Context.MODE_PRIVATE))
line above).
For example purposes, the file I am transferring is a simple UTF-8 text file, which contains a single string
This is a text file.
However, when I pull this file I have copied to the emulator, from the "/data/data//files" folder on the emulator, there are an extra couple of bytes at the top of the file so the content is now
¨ÌThis is a text file.
I have no idea why this is happening and it has me stumped. I think the problem might be related to the line:
BufferedOutputStream bos = new BufferedOutputStream(openFileOutput("text.txt", Context.MODE_PRIVATE));
but I can't quite figure it out.
Any suggestions as to what I am doing wrong would be most helpful.
Thank you in advance
Related
I was implement download apk from my own server, and install that, when i download with wifi its working fine, but when the movile is conected to internet with movile data the transfer is very low, and the apk not donwload, dont give me an error.
The code that i implemented is:
//Download the actual apk
InputStream inputStream = consumirWebService.ventaMovilUpdate("1", direccionUrlBase);
String pathApk = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+Dictionary.APK_NAME;
OutputStream os = new FileOutputStream(pathApk);
byte[] buffer = new byte[1024];
int bytesRead;
while((bytesRead = inputStream.read(buffer)) !=-1){
os.write(buffer, 0, bytesRead);
}
inputStream.close();
os.flush();
os.close();
//Install the new apk
PackageInfo info = IMAdministrador.this.getPackageManager().getPackageArchiveInfo(pathApk, PackageManager.GET_META_DATA);
File file = new File(pathApk);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(Intent.ACTION_PACKAGE_REPLACED, info.packageName);
intent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
if(info.packageName != null){
IMAdministrador.INSTALL_APK_INFO.put(info.packageName, file);
}
I am thinking on download the apk by parts compressed with rest webservices. The weight of apk is 5MB, download each of a parts some thing like 1Mb by part, and when i have the five parts, uncompress and install. But really i dont have idea how can I do that.
Or if you have any best idea, I am very appreciate for your help.
Thanks in advance.
I'm writing a process that downloads/ copies a file attached to Gmail on to the SD card that my application can then read.
When a user clicks on the attachment my activity is fired and I use the following code to save to local storage;
InputStream in = getContentResolver().openInputStream( intent.getData() );
String ext = intent.getType().equals("text/xml") ? ".xml" : ".gpkg";
localFile = new File( TILE_DIRECTORY, "tmp/"+intent.getDataString().hashCode()+ext);
// If we haven't already cached the file, go get it..
if (!localFile.exists()) {
localFile.getParentFile().mkdirs();
FileIO.streamCopy(in, new BufferedOutputStream(new FileOutputStream(localFile)) );
}
The FileIO.streamCopy is simply;
public static void streamCopy(InputStream in, OutputStream out) throws IOException{
byte[] b = new byte[BUFFER];
int read;
while ((read = in.read(b)) != -1) {
out.write(b, 0, read);
}
out.close();
in.close();
}
This all works fine on a small file, but with a 6Mb attachment only 12Kb is ever getting written. I'm not even getting an error, the process just runs through very quickly and i'm left with a corrupt file.
This process is run in its own thread and is part of a larger app with a lot of fileIO, so there is no issue with permissions/ directories etc.
Is there something different I should be doing with the stream?
Incidentally, intent.getData() is
content://gmail-ls/mexxx#gmail.com/messages/6847/attachments/0.1/BEST/false
and intent.getType() is
application/octet-stream
Thanks
All work's fine with this code
InputStream in = new BufferedInputStream(
getContentResolver().openInputStream(intent.getData()) );
File dir = getExternalCacheDir();
File file = new File(dir, Utils.md5(uri.getPath()));
OutputStream out = new BufferedOutputStream( new FileOutputStream(file) );
streamCopy(in, out);
I'm trying to send bmp image using socket. I have such code on android:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
MainActivity.bmp.compress(Bitmap.CompressFormat.JPEG, 20,
stream);
byte[] byteArray = stream.toByteArray();
OutputStream os = echoSocket.getOutputStream();
os.write(byteArray,0,byteArray.length);
os.flush();
and on PC:
String q = SockIn.readLine();
File file = new File("filename.bmp");
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(q);
in bmp file I only get up to 401 bytes, which of course is corrupt bmp image. what am I doing wrong?
MODIFIED
modified PC side, now the code is:
InputStream in_ = clientSocket.getInputStream();
OutputStream out_ = new FileOutputStream("filename.bmp");
final byte[] buffer = new byte[1024];
int read = -1;
int i = 0;
while ((read = in_.read(buffer)) != -1) {
out_.write(buffer, 0, read);
System.out.println(i);
i++;
}
in_.close();
out_.close();
System.out.println("Done");
It never gets to last line( println("Done") ). when I close android program, it gets to last line and bmp opens succesfully
Your reading logic is completely off. You only use a readLine() once and then write that to file. The data that was written to the socket on the device side was binary. That means that trying to read it as if it were textual (as readLine() does) will return meaningless junk. The reason it's usually 401 bytes long is that readLine() will look for the first newline character combination and return everything up to that as a String. This is not what you want.
What you need is a loop that will read from the socket and write into the file as long as there is data in the socket. A standard copy loop should suffice here.
InputStream in = socket.getInputStream();
OutputStream out = new FileOutputStream(...);
final byte[] buffer = new byte[BUFFER_SIZE];
int read = -1;
while ((read = in.read(buffer)) != -1)
out.write(buffer, 0, read);
in.close();
out.close();
Note that the above code isn't tested but something to that effect should do the trick.
Why are you reading a String if you are sending a byte ?
Try those setp one by one only if the previous did not worked.
1. Read() and don't Readline() what you are writing
If you write a byte, read a byte
Byte obj = SockIn.read();
2. Encode your array before sending
Base64.encodeBase64String(byteArray);
I'm trying to send bmp image using socket. I have such code on android:
ByteArrayOutputStream stream = new ByteArrayOutputStream();
MainActivity.bmp.compress(Bitmap.CompressFormat.JPEG, 20,
stream);
byte[] byteArray = stream.toByteArray();
OutputStream os = echoSocket.getOutputStream();
os.write(byteArray,0,byteArray.length);
os.flush();
and on PC:
InputStream in_ = clientSocket.getInputStream();
OutputStream out_ = new FileOutputStream("filename.bmp");
final byte[] buffer = new byte[1024];
int read = -1;
int i = 0;
while ((read = in_.read(buffer)) != -1) {
out_.write(buffer, 0, read);
System.out.println(i);
i++;
}
in_.close();
out_.close();
System.out.println("Done");
It never gets to last line( println("Done") ). It only does when I close android program, it gets to last line and bmp opens succesfully. problem is in_.read waits after android has finished transmitting, and i can't make it work.
You never close the socket/OutputStream on the device side so the PC side doesn't know that there is no more data and so it just spins in the while loop reading 0 bytes at a time.
Also, if you're going to use my solution, please mark me as the accepted answer in your previous thread.
Edit*
I have successful on the client server. Now I am doing a file transferring between 2 emulators. The file did transfer between the emulators, but I notice that the file size received is not the same as the original file. For example, A.jpg size is 900KB, but the received file is less than 900KB. I checked the file transfer size, found that there were some data(byte) lost when transferring. How is this happening?
Here's the code:
Client (Send File)
File myFile = new File ("/mnt/sdcard/Pictures/A.jpg");
FileInputStream fis = new FileInputStream(myFile);
OutputStream os = socket.getOutputStream();
int filesize = (int) myFile.length();
byte [] buffer = new byte [filesize];
int bytesRead =0;
while ((bytesRead = fis.read(buffer)) > 0) {
os.write(buffer, 0, bytesRead);
//Log display exact the file size
System.out.println("SO sendFile" + bytesRead);
}
os.flush();
os.close();
fis.close();
Log.d("Client", "Client sent message");
socket.close();
Server (Receive File)
FileOutputStream fos = new FileOutputStream("/mnt/sdcard/Pictures/B.jpg");
#SuppressWarnings("resource")
BufferedOutputStream bos = new BufferedOutputStream(fos);
InputStream is = clientSocket.getInputStream();
byte[] aByte = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(aByte)) != -1)
{
bos.write(aByte, 0, bytesRead);
//Log display few parts the file size is less than 1024. I total up, the lost size caused the file received is incomplete
System.out.println("SO sendFile" + bytesRead);
}
clientSocket.close();
*Edit 2
While I surfed around google, I found that .read(buffer) does not guarantee read the full size(byte) of the file. Hence, the received file always lost some bytes (like space, empty character). To solve this, send the file size first to inform the receiver, then only start transfer the file.
NetworkOnMainThreadException occurs because you have to use AsyncTask
NullPointerException occurs because you are trying to use PrintWriter with the result of Sockets. As you have got nothing with Sockets you get this error.
The NetworkOnMainThreadException tells you what you are doing wrong.
You need to put the network stuff into a separate Thread (or AsyncTask or similar).
You can not call any server operation on Main Thread in Android.
In Android O.S 4.0 and above this will directly cause to NetworkOnMainThreadException. You have 2 choices :
1) Either to use AsyncTask to call your every server operation.
2) Or Use User defined Thread for any type of server operation.
I was also struggling with this Exception, only in OS version above 4.0 devices, So you can not ignore these small needs of Android.