Housefly
Housefly

Reputation: 4422

Dowloading a text file from web

I want to download a text file from a web url and save it locally on the device and use it in my app.

Code:

try {
    File file = new File(getFilesDir(), "file.txt");
    if (file.length() > 0) {
        //File already exists and it is not empty
        return;
    }
    URL url = new URL("https://www.abc.com/file.txt");
    FileOutputStream fos = new FileOutputStream(file);
    InputStream in = url.openStream();
    byte[] buffer = new byte[1024];
    int length = 0;
    while ((length = in.read(buffer)) > 0) {
        fos.write(buffer, 0, length);
    }
    fos.flush();
    fos.close();
} catch (Exception e) {
    // TODO: 
}

As you can see, the code goes with getFilesDir() assuming that always exists. However there are few questions, with proper network connection and permissions:

  1. Does my assumption of getFilesDir() fail in any case?
  2. Are there any cases of either file not downloaded/wrong content etc.., with this code?
  3. Once I faced an issue where the file is downloaded but has all encoded characters, no matter how may times I downloaded it, it still had the same encoded text. Only when I re-installer my app, then the proper text was downloaded. And never got that issue ever since. Any reason for that weird behavior?

EDIT: Here is what I get as the content when I try to read the file which I downloaded(happens sometimes, 1 in 10) shown in the logcat:

enter image description here

Code to read the file:

BufferedReader inputReader= = new BufferedReader(
        new InputStreamReader(new FileInputStream(file)));
String inputString;
StringBuffer stringBuffer = new StringBuffer();
while ((inputString = inputReader.readLine()) != null) {
    Log.e("inputString: ", inputString);
}
inputReader.close();

Thank You

Upvotes: 6

Views: 846

Answers (5)

Chris
Chris

Reputation: 126

I cannot really comment on what goes wrong in your case, I will post a snippet of a code I'm using to detect what type of file I'm targeting and then get it. This has always worked as expected for me. I've modified my "onPostExecute" method to suit my answer here and I've tried to keep the names of my variables similar to yours. I've omitted the download progress indication bar to simplify the snippet. The download has to be done in the background, therefore "AsyncTask" is used. For the snippet I use random text file from google.

final String file_url = "https://www.kernel.org/doc/Documentation/power/drivers-testing.txt";
String fileExtension = MimeTypeMap.getFileExtensionFromUrl(file_url);
final String fileName = URLUtil.guessFileName(file_url, null, fileExtension);
final String path = Environment.getExternalStorageDirectory().toString() + "/" + fileName;

new AsyncTask<Void, Void, Void>() {
        @Override
        protected Void doInBackground(Void... params) {
            try {
                URL url = new URL(file_url);
                URLConnection connection = url.openConnection();
                connection.connect();

                // download the file
                InputStream in = new BufferedInputStream(url.openStream());
                OutputStream output = new FileOutputStream(path);
                byte buffer[] = new byte[1024];
                int length;
                while ((length = in.read(buffer)) != -1) {
                    output.write(buffer, 0, length);
                }
                output.flush();
                output.close();
                in.close();
            } catch (IOException e) {
                Log.e("Downloading file", "Download Error", e);
            }
            return null;
        }

        @Override
        public void onPostExecute(Void result) {
            try {
                File file = new File(path);

                BufferedReader inputReader = new BufferedReader(new FileReader(file));
                String inputString;

                while ((inputString = inputReader.readLine()) != null) {
                    Log.e("inputString: ", inputString);
                }
                inputReader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }.execute();

Upvotes: 0

Mostafa Gazar
Mostafa Gazar

Reputation: 2527

Does my assumption of getFilesDir() fail in any case?

According to the documentation it should always work with no permissions required.

Are there any cases of either file not downloaded/wrong content etc.., with this code?

Sure, I mean just a simple connection drop will cause download failure and so many other things can go wrong like missing required permission (android.permission.INTERNET), wrong encoding, disk full, ...

Once I faced an issue where the file is downloaded but has all encoded characters, no matter how may times I downloaded it, it still had the same encoded text. Only when I re-installer my app, then the proper text was downloaded. And never got that issue ever since. Any reason for that weird behavior?

It might have been an encoding issue, wrap your FileOutputStream in an OutputStreamWriter, which allows you to pass encoding parameter in the constructor.

Writer writer = new OutputStreamWriter(fos);
.
.
.
writer.write(buffer, 0, length);

Upvotes: 2

Pratik Dasa
Pratik Dasa

Reputation: 7439

Try with below code:

public void downloadFile(){
    String DownloadUrl = "Paste Url to download a text file here…";
    DownloadManager.Request request = new DownloadManager.Request(Uri.parse(DownloadUrl));
    request.setDescription("sample text file for testing");   //appears the same in Notification bar while downloading
    request.setTitle("Sample.txt");                
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        request.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
    }
    request.setDestinationInExternalFilesDir(getApplicationContext(),null, "sample.pdf");

    // get download service and enqueue file
    DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
    manager.enqueue(request);
}

public static boolean isDownloadManagerAvailable(Context context) {
    try {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) {
            return false;
        }
        Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_LAUNCHER);
        intent.setClassName("com.android.providers.downloads.ui","com.android.providers.downloads.ui.DownloadList");
        List <resolveinfo> list = context.getPackageManager().queryIntentActivities(intent,
                PackageManager.MATCH_DEFAULT_ONLY);
        return list.size() > 0;
    } catch (Exception e) {
        return false;
    }
}

Upvotes: 0

user4213851
user4213851

Reputation:

The following example may be helpful:

try {
    // Create a URL for the desired page
    URL url = new URL("mysite.com/thefile.txt");

    // Read all the text returned by the server
    BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
    String str;
    while ((str = in.readLine()) != null) {
        // str is one line of text; readLine() strips the newline character(s)
    }
    in.close();
    } catch (MalformedURLException e) {
    } catch (IOException e) {
}

Upvotes: 1

Daniele Campogiani
Daniele Campogiani

Reputation: 129

That's not really an answer but an advice, use ion a networking library for Android.

From examples:

Ion.with(context)
.load("http://example.com/really-big-file.zip")
// have a ProgressBar get updated automatically with the percent
.progressBar(progressBar)
// and a ProgressDialog
.progressDialog(progressDialog)
// can also use a custom callback
.progress(new ProgressCallback() {@Override
   public void onProgress(int downloaded, int total) {
       System.out.println("" + downloaded + " / " + total);
   }
})
.write(new File("/sdcard/really-big-file.zip"))
.setCallback(new FutureCallback<File>() {
   @Override
    public void onCompleted(Exception e, File file) {
        // download done...
        // do stuff with the File or error
    }
}); 

All operations are done not in the UI thread, so the user always see a responsive app.

Upvotes: 0

Related Questions