my below code for downloading file work fine when don't implementing resume for that, after read more solution to implementing that and resolve problem i know i must check Last-Modified header and set it for connection,
but i can't do that because of i get error such as android Cannot set request property after connection is made or i get null for httpURLConnection,
i'm using this reference
getHeaderField heaser return:
{
null=[HTTP/1.1 200 OK],
Cache-Control=[public],
Connection=[keep-alive],
Content-Length=[8037404],
Content-Md5=[VEqXHCc/Off7a6D0gRFpiQ==],
Content-Type=[image/jpeg],
Date=[Tue, 19 Jan 2016 07:24:36 GMT],
Etag=["544a971c273f39f7fb6ba0f481116989"],
Expires=[Sat, 29 Jul 2017 10:07:00 GMT],
Last-Modified=[Thu, 18 Dec 2014 08:44:34 GMT],
Server=[bws],
X-Android-Received-Millis=[1501063623576],
X-Android-Response-Source=[NETWORK 200],
X-Android-Selected-Protocol=[http/1.1],
X-Android-Sent-Millis=[1501063623532]
}
now how can i set that to have resume for download files?
GitHub Link
public void run() {
final URL url;
HttpURLConnection httpURLConnection = null;
try {
try {
url = new URL(mUrl);
String lastModified = httpURLConnection.getHeaderField("Last-Modified");
if (!lastModified.isEmpty()) {
httpURLConnection.setRequestProperty("If-Range", lastModified);
}
httpURLConnection = (HttpURLConnection) url.openConnection();
if (mFile.exists()) {
downloadedLength = mFile.length();
Log.e("downloadedLength ", downloadedLength + "");
httpURLConnection.setRequestProperty("Range", "bytes=" + downloadedLength + "-");
fileOutputStream = new FileOutputStream(mFile, true);
} else {
fileOutputStream = new FileOutputStream(mFile);
}
httpURLConnection.setConnectTimeout(30000);
httpURLConnection.setReadTimeout(30000);
httpURLConnection.setRequestMethod("GET");
} catch (IOException e) {
}
final int responseCode;
final int total;
try {
responseCode = httpURLConnection.getResponseCode();
total = httpURLConnection.getContentLength();
} catch (IOException e) {
e.printStackTrace();
Log.e("ER UPDATE ", e.getMessage());
}
if (responseCode == 200) {
try {
inputStream = httpURLConnection.getInputStream();
} catch (IOException e) {
e.printStackTrace();
Log.e("IOException ", e.getMessage());
}
final byte[] buffer = new byte[4 * 1024];
int length = -1;
int finished = 0;
long start = System.currentTimeMillis();
try {
while ((length = inputStream.read(buffer)) != -1) {
if (!isDownloading()) {
throw new CanceledException("canceled");
}
fileOutputStream.write(buffer, 0, length);
finished += length;
if (System.currentTimeMillis() - start > 1000) {
onDownloadProgressing(finished, total);
start = System.currentTimeMillis();
}
}
onDownloadCompleted();
} catch (IOException e) {
e.printStackTrace();
Log.e("ER UPDATE ", e.getMessage());
}
} else {
Log.e("responseCode ", responseCode + "");
}
} catch (DownloadException e) {
e.printStackTrace();
Log.e("ER UPDATE ", e.getMessage());
} catch (CanceledException e) {
e.printStackTrace();
Log.e("ER UPDATE ", e.getMessage());
}
}
and also i get 206 response code instead of 200
1- You are getting null for httpURLConnection because you try to invoke it before being initialized,
i.e, this line
httpURLConnection = (HttpURLConnection) url.openConnection();
should come before this line:
String lastModified = httpURLConnection.getHeaderField("Last-Modified");
2- you can set the header before calling connect() on httpURLConnection
so you need to set whatever you want, then connect(). this way you should not get the error (android Cannot set request property after connection is made)
3- The 206 is perfectly right, it's what you should expect when using Range and it means Partial Content Success and that's what you are doing, you are getting part of the content, if you are getting full content you would get 200.
so to sum this up, your code can look like this:
Note: follow the //*** to see changes required.
EDIT: it all came to this line
httpURLConnection.setRequestProperty("If-Range", lastModified);
the error get thrown when you set that Property,
Anyways, when you look at this, it's meaningless, you are asking if last-modified is equal to the value that you just got from the connection!,
if you want to do this you need to store lastModified in your system,
then compare it with the one you got from the URLConn, and compare it to your file length (already downloaded)
then proceed with full download or resume download.
find new code below:
public void run() {
myLastModified = getLastModified(mFile.getName()); // get last stored value for this file (use file name or other key)
int total =0;
final URL url;
HttpURLConnection httpURLConnection = null;
try {
try {
url = new URL(mUrl);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setDoInput(true);
httpURLConnection.setConnectTimeout(30000);
httpURLConnection.setReadTimeout(30000);
httpURLConnection.setRequestMethod("GET");
//*** new way to handle download process
total = httpURLConnection.getContentLength();
if(mFile.exists()){
if(mFile.length() == total){
//we are done, return.
return;
}else{
//file was not completly donwloaded, now check lastModified:
long lastModified = httpURLConnection.getLastModified();//this gets the header "Last-Modified" and convert to long
if (lastModified == myLastModified) { //myLastModified should be retrived on each download and stored locally on ur system
downloadedLength = mFile.length();
Log.e("downloadedLength ", downloadedLength + "");
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setDoInput(true);
httpURLConnection.setConnectTimeout(30000);
httpURLConnection.setReadTimeout(30000);
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setRequestProperty("Range", "bytes=" + downloadedLength + "-"+ total); //add + total (TO)
//append mode
fileOutputStream = new FileOutputStream(mFile, true);
}else{
//file was modified after 1st uncompleted-download:
storeLastModified(lastModified, mFile.getName()); // use file name as key. can store in db or file ...
//don't set ant Range ... we want full download, with a fresh file
fileOutputStream = new FileOutputStream(mFile);
}//last mod IF
}//Length check
}else{
//file not exist at all, create new file, set no Range we want full download...
mFile.createNewFile();
fileOutputStream = new FileOutputStream(mFile);
}//file exists.
} catch (IOException e) {
e.printStackTrace();
}
final int responseCode;
try {
responseCode = httpURLConnection.getResponseCode();
} catch (IOException e) {
e.printStackTrace();
Log.e("ER UPDATE ", e.getMessage());
}
//*****
if (responseCode == 200 || responseCode == 206) {
try {
inputStream = httpURLConnection.getInputStream();
} catch (IOException e) {
e.printStackTrace();
Log.e("IOException ", e.getMessage());
}
final byte[] buffer = new byte[4 * 1024];
int length = -1;
int finished = 0;
long start = System.currentTimeMillis();
try {
while ((length = inputStream.read(buffer)) != -1) {
if (!isDownloading()) {
throw new CanceledException("canceled");
}
fileOutputStream.write(buffer, 0, length);
finished += length;
if (System.currentTimeMillis() - start > 1000) {
onDownloadProgressing(finished, total);
start = System.currentTimeMillis();
}
}
onDownloadCompleted();
} catch (IOException e) {
e.printStackTrace();
Log.e("ER UPDATE ", e.getMessage());
}
} else {
Log.e("responseCode ", responseCode + "");
}
} catch (DownloadException e) {
e.printStackTrace();
Log.e("ER UPDATE ", e.getMessage());
} catch (CanceledException e) {
e.printStackTrace();
Log.e("ER UPDATE ", e.getMessage());
}
}
Take a look at this answer of POMATu.
But anyway, if You downloading files over the HTTP protocol, You can use DownloadManager - a system service (since API level 9) for long-running downloads in the background. It handles HTTP connections, connectivity changes, reboots, and ensures each download completes successfully. And it already supports resuming and also progress notifications.
You can find many tutorials like this or examples like that, and many solutions on stackoverflow by android-download-manager tag.
Good day.
I am sending a string of user name (so I know the following file belongs to which user) then followed by stream of array of bytes(for audio) from android client to server running in java.
I think of opening different ports but because the server is running in a private network so if I want to open more ports then I need to add more port forwarding function which is quite silly.
I able to send string of username and arrays of bytes separately but when audio file after user name, the audio file will be sped up.
server.java
while (true) {
Socket socket = listener.accept();
try {
InputStream in = socket.getInputStream();
BufferedReader inFileN = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (fileName==null) {
fileName=inFileN.readLine();
File dir = new File("/home/xxx/Documents/" + fileName);
dir.mkdirs();
}
String filePath = "/home/xxx/Documents/"+fileName+"/voice8K16bitmono.pcm";
FileOutputStream os = null;
byte[] buffer = new byte[1024];
int count;
try {
os = new FileOutputStream(filePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
while ((count = in.read(buffer)) > 0)
{
os.write(buffer, 0, count);
}
} finally {
socket.close();
}
client side for writing string of user name
try {
s = new Socket("localhost", 9090);
PrintWriter out = new PrintWriter(s.getOutputStream(), true);
out.print(userID);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
client side for writing audio file under some condition
try {
s = new Socket("localhost", 9090);
outToServer = s.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
while (isRecording) {
recorder.read(sData, 0, BufferElements2Rec);
detectSilence(sData, threshold);
try {
byte bData[] = short2byte(sData);
//os.write(bData, 0, BufferElements2Rec * BytesPerElement);
outToServer.write(bData, 0, BufferElements2Rec * BytesPerElement);
} catch (IOException e) {
e.printStackTrace();
}
}
Or is there any other better way to use if I want to sending multiple data types from a single client?
ps: I have not implemented multi-threaded server at this point because I want to make sure it works with a single user first
Thank you.
I'm struggling against the uncompleted download of a file.
For example, I upload some data on github :https://gist.githubusercontent.com/rdanniau/3b7f26bb1101b28400bf24f2f9664828/raw/980d6ff511404bf14d3efc56be3dfb081541991f/LEDirium.hex
and on pasteBin : http://pastebin.com/raw/FcVfLf5b
I want to retrieve them and save them into a file "filename".
I've watch a lot of example on internet and it must be working.
Here is the code :
private void download(final URL myUrl){
new Thread(new Runnable() {
//InputStream is = null;
//FileOutputStream fos = null;
public void run() {
try {
URLConnection connection = myURLL.openConnection();
//HttpURLConnection connection = (HttpURLConnection) myUrl.openConnection();
//connection.setRequestMethod("GET");
connection.setReadTimeout(5000);
connection.setConnectTimeout(10000);
connection.connect();
//is = myUrl.openStream();
is = connection.getInputStream();
File file = new File(context.getFilesDir(),fileName);
file.delete();
file = new File(context.getFilesDir(),fileName);
fos = new FileOutputStream(file);
byte data[] = new byte[1024];
String str ="";
int count = 0;
while ((count = is.read(data)) != -1) {
fos.write(data, 0, count);
}
is.close();
fos.close();
}
catch (Exception e) {
downloadedFileCallback.onError(e);
Log.e("DownloadedFile", "Unable to download : " + e.getMessage() + " cause :" + e.getCause());
return;
}
downloadedFileCallback.onDownloadedFinished();
readFile(context);
}
}).start();
}
public void readFile(Context context){
// read
try {
BufferedReader br = new BufferedReader(new FileReader(new File(context.getFilesDir(),fileName)));
String line;
while ((line = br.readLine()) != null) {
Log.v("DL", line);
}
br.close();
}
catch (Exception e) {
Log.e("DownloadedFile", "Unable to read : " + e.getMessage() + " cause :" + e.getCause());
}
//Log.v("DownloadedFile", text.toString());
}
where myURL are called like
URL myURL = new URL("http://pastebin.com/raw/FcVfLf5b");
In the Log.v, I can see that I downloaded only a part of the file which is never the same (it could be the entire file, the half, the quarter, we don' know...)
It's probably the inputStream connection which is closed too fast. But why ?
Last question, instead of using Log.v to check if the file is correctly downloaded. Where can I found it on my phone ? I searched in many folders but I never seen my File.
Thanks a lot for any advice
EDIT : It seems to be the same here InputStream returns -1 before end of file but no one answered.
When debugging I can confirm 6 out of 9 url connections work. One is dead, and others are sending a exceptions. Question 1:I want it to show either alive or dead, nothing else. Question 2 : when running the test, it tests too fast and it shows all are "dead" links when running (even though I know 6 work). Any suggestions?
try{
//Read File
FileReader file = new FileReader("c:\\blocked\\domains1.txt");
BufferedReader buff = new BufferedReader(file);
BufferedReader rd;
OutputStreamWriter wr;
while (true)
{
String line = buff.readLine();
if (line == null)
break;
else
try
{// Test URL Connection
URL url = new URL("http://www."+line);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
wr = new OutputStreamWriter(conn.getOutputStream());
wr.flush();
rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
if( rd.ready())
{
//write to output file
System.out.println("Good URL: " + line);
urlAlive ++;
//Write to file
Path filePath = Paths.get("c:\\RevisedUrls\\revised.txt");
try
{
BufferedWriter myWriter = new BufferedWriter(new FileWriter(filePath.toFile()));
// write the user supplied data to the file plus a line separator.
myWriter.write(line + System.getProperty("line.separator"));
myWriter.close(); // immediately close the file when finished with it.
}
catch(Exception e)
{
System.out.println(e);
}
}
else// increment dead url
urlDead++;
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
buff.close();
}
finally
{
int totalSites = urlAlive + urlDead;
JOptionPane.showMessageDialog(null,"Total Number of Alive Sites: " + urlAlive);
JOptionPane.showMessageDialog(null,"Total Number of Dead Sites: " + urlDead);
JOptionPane.showMessageDialog(null,"Total Number of Sites: " + totalSites);
}
}
}
This is the method I have in my java application. It is reading the bytes correctly, I have logged to see if it was. The problem is that the php is not realizing the data is there. I have tested and the .php reads that $_POST is set, but is empty.
public void screenshot(BufferedImage screenshot) {
try {
ImageIO.write(screenshot, "png",
new File(Environment.getStorageDirectory().toString()
.concat(File.separator + SCRIPT_NAME + ".png")));
HttpURLConnection httpUrlConnection;
OutputStream outputStream;
BufferedInputStream fileInputStream;
BufferedReader serverReader;
int totalBytes;
String response = "";
String serverResponse = "";
String localFileName = Environment.getStorageDirectory().toString()
.concat(File.separator + SCRIPT_NAME + ".png");
// Establish a connection
httpUrlConnection = (HttpURLConnection) new URL(
"http://www.scripted.it/scriptoptions/utils/saveScreenshot.php?user="
+ SupraCrafter.statHandler.getUser())
.openConnection();
httpUrlConnection.setDoOutput(true);
httpUrlConnection.setDoInput(true);
httpUrlConnection.setRequestMethod("POST");
httpUrlConnection.setRequestProperty("Content-type",
"application/x-www-form-urlencoded");
outputStream = httpUrlConnection.getOutputStream();
// Buffered input stream
fileInputStream = new BufferedInputStream(new FileInputStream(
localFileName));
// Get the size of the image
totalBytes = fileInputStream.available();
// Loop through the files data
for (int i = 0; i < totalBytes; i++) {
// Write the data to the output stream
outputStream.write(fileInputStream.read());
}
// Close the output stream
outputStream.close();
// New reader to get server response
serverReader = new BufferedReader(new InputStreamReader(
httpUrlConnection.getInputStream()));
// Read the servers response
serverResponse = "";
while ((response = serverReader.readLine()) != null) {
serverResponse = serverResponse + response;
}
System.out.println(serverResponse);
// Close the buffered reader
serverReader.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
URL url = new URL(
"http://scripted.it/scriptoptions/utils/setScreenshotStatus.php?user="
+ SupraCrafter.statHandler.getUser() + "&pass="
+ SupraCrafter.statHandler.getPass() + "&script="
+ SCRIPT_NAME + "&status=1");
BufferedReader in = new BufferedReader(new InputStreamReader(
url.openStream()));
in.close();
} catch (MalformedURLException e) {
} catch (IOException e) {
}
}
Here is the .php file:
<?
// Config
$uploadBase = "../screenshots/";
$uploadFilename = $_GET['user'] . ".png";
$uploadPath = $uploadBase . $uploadFilename;
// Upload directory
if(!is_dir($uploadBase))
mkdir($uploadBase);
// Grab the data
$incomingData = file_get_contents('php://input');
// Valid data?
if(!$incomingData)
die("No input data");
// Write to disk
$fh = fopen($uploadPath, 'w') or die("Error opening file");
fwrite($fh, $incomingData) or die("Error writing to file");
fclose($fh) or die("Error closing file");
echo "Success";
?>
It always echos 'no input data.'
You are not encoding the content with application/x-www-form-urlencoded. You should not simply copy the bytes into the HTTP payload, but instead encode it correctly.
application/x-www-form-urlencoded is not the only possible way of encoding it, multipart/form-data is another common choice. Both are supported by almost all webservers, and as a consequence by PHP.
A tutorial on how to encode using Java is here : http://www.devx.com/Java/Article/17679
Why don't you use Apache's HttpClient or similar library that already do that tedious work for you?
Apache HttpClient : http://hc.apache.org/httpcomponents-client-ga/