I am using following code to download and read a PDF file from internal storage on device.
I am able to download the files successfully to the directory:
data/data/packagename/app_books/file.pdf
But I am unable to read the file using a PDF reader application like Adobe Reader.
Code to download file
//Creating an internal dir;
File mydir = getApplicationContext().getDir("books", Context.MODE_WORLD_READABLE);
try {
File file = new File(mydir, outputFileName);
URL downloadUrl = new URL(url);
URLConnection ucon = downloadUrl.openConnection();
ucon.connect();
InputStream is = ucon.getInputStream();
FileOutputStream fos = new FileOutputStream(file);
byte data[] = new byte[1024];
int current = 0;
while ((current = is.read(data)) != -1) {
fos.write(data, 0, current);
}
is.close();
fos.flush();
fos.close();
isFileDownloaded=true;
} catch (IOException e) {
e.printStackTrace();
isFileDownloaded = false;
System.out.println(outputFileName + " not downloaded");
}
if (isFileDownloaded)
System.out.println(outputFileName + " downloaded");
return isFileDownloaded;
Code to read the file
PackageManager packageManager = getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType("application/pdf");
List list = packageManager.queryIntentActivities(testIntent,
PackageManager.MATCH_DEFAULT_ONLY);
try {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
File fileToRead = new File(
"/data/data/com.example.filedownloader/app_books/Book.pdf");
Uri uri = Uri.fromFile(fileToRead.getAbsoluteFile());
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
} catch (Exception ex) {
Log.i(getClass().toString(), ex.toString());
Toast.makeText(MainActivity.this,
"Cannot open your selected file, try again later",
Toast.LENGTH_SHORT).show();
}
All works fine but the reader app says "File Path is not valid".
Your path is only valid for your app. Place the file in a place where other apps can 'see' it. Use GetExternalFilesDir() or getExternalStorageDirectory().
Note about files which are created inside the directory created by Context.getDir(String name, int mode) that they will only be accessible by your own application; you can only set the mode of the entire directory, not of individual files.
So you can use Context.openFileOutput(String name, int mode). I'm re-using your code for an example:
try {
// Now we use Context.MODE_WORLD_READABLE for this file
FileOutputStream fos = openFileOutput(outputFileName,
Context.MODE_WORLD_READABLE);
// Download data and store it to `fos`
// ...
You might want to take a look at this guide: Using the Internal Storage.
If you would like to keep the file app specific, you can use PdfRenderer available for Lollipop and above builds. There are great tutorials on google and youtube that work well. The method you are using is a secure way to store a PDF file that is only readable from inside the app ONLY. No outside application like Adobe PDF Reader will be able to even see the file.It took me a lot of seaching but I found a solution to my specific usage by using this site and especially youtube.
How to download PDF file from asset folder to storage by making folder
make sure you have storage permission are given like marshmallow device support etc then follow these steps
private void CopyReadAssets()
{
AssetManager assetManager = getContext().getAssets();
FileInputStream in = null;
FileOutputStream out = null;
File sdcard = Environment.getExternalStorageDirectory();
File dir = new File(Environment.getExternalStorageDirectory()+File.separator+ "A_level");
File dir2;
if (dir.exists() && dir.isDirectory()){
Log.e("tag out", ""+ dir);
}else {
dir.mkdir();
Log.e("tag out", "not exist");
}
File file = new File(dir, mTitle+".pdf");
try
{
Log.e("tag out", ""+ file);
out = new FileOutputStream(file);
in = new FileInputStream (new File(mPath));
Log.e("tag In", ""+ in);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag out", ""+ out);
Log.e("tag In", ""+ in);
Log.e("tag", e.getMessage());
Log.e("tag", ""+file);
Log.i("tag",""+sdcard.getAbsolutePath() + "A_level");
}
}
private 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);
}
}
Related
I've got a question that probably borders on opinion, but I've not any related questions or documentation that answers, so I feel like it's a fair one to ask.
I'm trying to build an android app which modifies music files, and what I'd like to do is have a shared folder so that the files and the results can be accessible and shared. I'd like it if it was among the other folders like Music, Downloads, Movies, etc, or even under Music since it's music related. However this seems like it's a security no no in Android, as after I've made something and put it in there I have to use an intent to access it again, where as I'd rather just be able to open the files and not have a permissions based fiasco. Maybe some type of symbolic link like in Linux that pointed to my apps internal folder could be used, but of this I'm still uncertain.
In any case, is there a way I should go about this? If so, are there some resources I could be pointed to?
Thank you in advance to anyone who takes this up!
Edit for CommonsWare:
I used the following to create the folder:
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), APP_NAME);
And this to copy files from elsewhere to there:
public void copyFileToHomeDirectory(Uri uri)
{
try
{
ContentResolver contentResolver = getApplicationContext().getContentResolver();
String fileName = queryName(contentResolver, uri);
//Get file extension
String fileType = fileName.substring(fileName.length() - 4, fileName.length());
if(fileType.equalsIgnoreCase(MP3_EXTENSION))
{
String path = Environment.getExternalStorageDirectory() + APP_FOLDER;
InputStream in = contentResolver.openInputStream(uri);
File outputFile = new File(path + File.separator + fileName);
outputFile.createNewFile();
OutputStream out = new FileOutputStream(outputFile);
//First we crack open the file to copy it's contents:
byte[] buffer = new byte[KB_SIZE];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
in.close();
in = null;
// write the output file (You have now copied the file)
out.flush();
out.close();
out = null;
}
}
catch(FileNotFoundException fnfe)
{
Log.e(TAG, "FileNotFoundException");
Log.e(TAG, Log.getStackTraceString(fnfe));
}
catch(IOException ioe)
{
Log.e(TAG, "IOException");
Log.e(TAG, Log.getStackTraceString(ioe));
}
catch(Exception e)
{
Log.e(TAG, "General Exception");
Log.e(TAG, Log.getStackTraceString(e));
}
}
I've tried other methods that I've overwritten in the process, but accessing the files to be used again I need something like this:
public void openDirectory(View view)
{
// Choose a directory using the system's file picker.
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
// Provide read access to files and sub-directories in the user-selected
// directory.
//intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
//intent.addCategory(Intent.CATEGORY_OPENABLE);
// Optionally, specify a URI for the directory that should be opened in
// the system file picker when it loads.
//intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, uriToLoad);
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*"); //use image/* for photos, etc.
//The result of this code will be calling the onActivityResult function below
startActivityForResult(intent, REQUEST_MUSIC_DIR);
}
Edit2:
I've reorganized the folders to what I think I should be doing so that I can work with the files freely, however, even in my internal cache storage (getCacheDir() + folder_name) either isn't letting me create the files (outputFile.createNewFile doesn't throw an error) or it isn't letting me open them when I go to get a directory listing.
Here's my code for creating the file:
String path = getCacheDir() + MY_SUB_FOLDER;
//uri is obtained through ACTION_OPEN_DOCUMENT intent
InputStream in = contentResolver.openInputStream(uri);
File outputFile = new File(path + "/" + fileName);
outputFile.createNewFile();
Log.i(TAG, "The new file's directory/path is: " + outputFile.getAbsolutePath());
//NOTE: This is returning /data/user/0/com.example.myapplication/cache/MY_SUB_FOLDER/file_name.mp3
OutputStream out = new FileOutputStream(outputFile);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
This is my code for attempting to open and read these newly created files
File directory = new File(getCacheDir(), MY_SUB_FOLDER);
Log.i(TAG, "This is the directory we're trying to get the files from: " + directory.getAbsolutePath());
//NOTE: This returns /data/user/0/com.example.myapplication/cache/MY_SUB_FOLDER
File[] files = directory.listFiles();
if(files != null)
{
for(int i = 0; i < files.length; i++)
{
Log.d(TAG, "Files found: " + files[i].getAbsolutePath());
}
}
The files variable isn't null but it's length is 0 and no files are found.
Edit3:
I am catching the exceptions and logging any stack traces, which currently returns nothing.
catch(FileNotFoundException fnfe)
{
Log.i(TAG, "FileNotFoundException");
Log.i(TAG, Log.getStackTraceString(fnfe));
}
catch(IOException ioe)
{
Log.i(TAG, "IOException");
Log.i(TAG, Log.getStackTraceString(ioe));
}
catch(Exception e)
{
Log.i(TAG, "General Exception");
Log.i(TAG, Log.getStackTraceString(e));
}
I try to read a pdf file store in the assets folder. I see this solution :
Read a pdf file from assets folder
But like comments say this it's not working anymore, the file cannot be found, is there another solution for read a pdf file directly, without copy pdf in external storage ?
And I don't want to use PdfRenderer my minimal API is 17
Maybe this can be helpful for somebody so I post my answer :
private void openPdf(String pdfName){
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
File file = new File(getFilesDir(), pdfName);
try
{
in = assetManager.open(pdfName);
out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag", e.getMessage());
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file://" + getFilesDir() + "/"+pdfName),
"application/pdf");
startActivity(intent);
}
The pdf file is store inside the assets folder
I want to open a pdf file when inside the application(internal storage).I have the following code.But once adobe pdf is opened it shows a pop up error as " The document path is not valid".Is it not possible to only read a pdf file from inside the app? If not please let me know how can I copy it to the external storage.Thanks in advance
File file_source = new File(getApplicationContext().getFilesDir()+"/"+"sample.pdf");
String string = "Hello world!";
try
{
file_source.createNewFile();
FileOutputStream outputStream;
outputStream = openFileOutput("sample.pdf", Context.MODE_PRIVATE);
outputStream.write(string.getBytes());
outputStream.close();
if(file_source.exists())
{
Uri path = Uri.fromFile(file_source);
Intent intent1 = new Intent(Intent.ACTION_VIEW);
intent1.setDataAndType(path, "application/pdf");
intent1.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
startActivity(intent1);
}
catch (ActivityNotFoundException e) {
Toast.makeText(this,
"No Application Available to View PDF",
Toast.LENGTH_SHORT).show();
Intent intent2 = new Intent(Intent.ACTION_VIEW);
startActivity(intent2);
}
}
else
{
Log.d("TAG","no file exists");
}
}
catch (FileNotFoundException e) {
Log.d("TAG","File not found");
}
catch (IOException ioe) {
Log.d("TAG","Exception while reading file" + ioe);
}
Files in the internal storage directory of your app are by default private to your application. Which means that no PDF-Reader app can read that file (since it doesn't run with your apps pid - no read permission is given).
You have to save that PDF with explicit reading permissions for other apps by using the Context.MODE_WORLD_READABLE flag.
Also use Context.openFileOutput() and Context.openFileInput() to read and write files in your internal directory . Don't hardcode paths like this, they might change.
You can copy the file from internal storage to external storage by below code.
try {
String file_name="inputpdf.pdf";
File tempfile = new File(directory, file_name);
FileInputStream inStream = new FileInputStream(tempfile);
//where ctx is your context (this)
FileOutputStream fos = ctx.openFileOutput("Outputpdf", ctx.MODE_WORLD_WRITEABLE|ctx.MODE_WORLD_READABLE);
byte[] buffer = new byte[1024];
int length;
//copy the file content in bytes
while ((length = inStream.read(buffer)) > 0){
fos.write(buffer, 0, length);
}
inStream.close();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
I have a PDF file stored in my assets. I want to load the PDF from my assets and read it in the app itself without using any 3rd party app to view.
I got the solution in this link. It works fine when selecting files from sdcard.
Following snippet might help you accessing files from asset folder and then open it:
private void ReadFromAssets()
{
AssetManager assetManager = getAssets();
InputStream in = null;
OutputStream out = null;
File file = new File(getFilesDir(), "file.pdf");
try
{
in = assetManager.open("file.pdf");
out = openFileOutput(file.getName(), Context.MODE_WORLD_READABLE);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag", e.getMessage());
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file://" + getFilesDir() + "/file.pdf"),
"application/pdf");
startActivity(intent);
}
and copyFile method is as follows:
private 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);
}
}
EDIT
For that purpose you'll have to use an ecternal library. It's explained quite well in the link below:
Render a PDF file using Java on Android
Hope this will help you.
Its better if you can open it using a webview
WebView web = (WebView) findViewById(R.id.webView1);
web.loadUrl("file:///android_asset/yourpdf.pdf");
Hope it works.
Ooops just now I checked, the pdf cannot be loaded in the web view
Sorry
File file = new File("android.resource://com.baltech.PdfReader/assets/raw/"+filename);
if (file.exists()) {
Uri targetUri = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(targetUri, "application/pdf");
try {
startActivity(intent);
}
catch (ActivityNotFoundException e) {
Toast.makeText(PdfReaderActivity.this, "No Application Available to View PDF", Toast.LENGTH_SHORT).show();
}
i want to read .pdf file which is in assets folder. what path i hav to give in filename. plz help. Thanks
I'm not sure if you got an answer to this already, seems pretty old, but this worked for me.
//you need to copy the input stream to a new file, so store it elsewhere
//this stores it to the sdcard in a new folder "MyApp"
String filename = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyApp/solicitation_form.pdf";
AssetManager assetManager = getAssets();
try {
InputStream pdfFileStream = assetManager.open("solicitation_form.pdf");
CreateFileFromInputStream(pdfFileStream, filename);
} catch (IOException e1) {
e1.printStackTrace();
}
File pdfFile = new File(filename);
The CreateFileFromInputStream function is as follows
public void CreateFileFromInputStream(InputStream inStream, String path) throws IOException {
// write the inputStream to a FileOutputStream
OutputStream out = new FileOutputStream(new File(path));
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
inStream.close();
out.flush();
out.close();
}
Really hope this helps anyone else who reads this.
File file = new File("file:///android_asset/raw/"+filename);
replace the above line with below and try..
File file = new File("android.resource://com.com.com/raw/"+filename);
and place your PDF file raw folder instead of asset. Also change com.com.com with your package name.
Since assets files are stored inside apk file, there is no absolute path of the assets folder.
You might use a workaround creating a new file used as a buffer.
You should use AssetManager:
AssetManager mngr = getAssets();
InputStream ip = mngr.open(<filename in the assets folder>);
File assetFile = createFileFromInputStream(ip);
private File createFileFromInputStream(InputStream ip);
try{
File f=new File(<filename>);
OutputStream out=new FileOutputStream(f);
byte buf[]=new byte[1024];
int len;
while((len=inputStream.read(buf))>0)
out.write(buf,0,len);
out.close();
inputStream.close();
}catch (IOException e){}
}
}