I'm trying to read a text file in Unity. I have problems.
In desktop, when I generate the Stand Alone, I need to copy manually the text file. I don't know how include inside my application.
In web application (and Android), I copy the file manually but my game can't find it.
This is my "Read" code:
public static string Read(string filename) {
//string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, filename);
string filePath = System.IO.Path.Combine(Application.dataPath, filename);
string result = "";
if (filePath.Contains("://")) {
// The next line is because if I use path.combine I
// get something like: "http://bla.bla/bla\filename.csv"
filePath = Application.dataPath +"/"+ System.Uri.EscapeUriString(filename);
//filePath = System.IO.Path.Combine(Application.streamingAssetsPath, filename);
WWW www = new WWW(filePath);
int timeout = 20*1000;
while(!www.isDone) {
System.Threading.Thread.Sleep(100);
timeout -= 100;
// NOTE: Always get a timeout exception ¬¬
if(timeout <= 0) {
throw new TimeoutException("The operation was timed-out ("+filePath+")");
}
}
//yield return www;
result = www.text;
} else {
#if !UNITY_WEBPLAYER
result = System.IO.File.ReadAllText(filePath);
#else
using(var read = System.IO.File.OpenRead(filePath)) {
using(var sr = new StreamReader(read)) {
result = sr.ReadToEnd();
}
}
#endif
}
return result;
}
My questions are:
How can I include my "text file" as a Game Resource?
Is something wrong on my code?
Unity offers a special folder called Resources where you can keep files and load them at runtime through Resources.Load
Resources.Load on Unity docs
Create a folder called Resources in your project, and put your files in it (in this case, you text file).
Here's an example. It assumes that you're sticking your file straight into the Resources folder (not a subfolder in Resources)
public static string Read(string filename) {
//Load the text file using Reources.Load
TextAsset theTextFile = Resources.Load<TextAsset>(filename);
//There's a text file named filename, lets get it's contents and return it
if(theTextFile != null)
return theTextFile.text;
//There's no file, return an empty string.
return string.Empty;
}
Related
I'm making a mobile rhythm game. I get absolute path of song like this.
/storage/emulated/0/Music/a.mp3
I want to convert the mp3 file to audioClip.
But I can't a receive mp3 file from absolute path.
here is my code :
IEnumerator GetSoundFile(string path)
{
//path : '/storage/emulated/0/Music/a.mp3'
testText.text = path;
source = GetComponent<AudioSource>();
using (var www = new WWW(path))
{
yield return www;
source.clip = www.GetAudioClip();
}
SoundManager.instance.PlaySingle(source.clip);
}
How can I receive a music file?
You need to get the persistent path for android location , Try this
https://docs.unity3d.com/ScriptReference/Application-persistentDataPath.html
In android, add this function to get correct path:
...
path = GetUri(path);
...
private string GetUri(string uri)
{
if (uri.Contains("://") || uri.Contains(":///"))
return uri;
return "file://" + uri;
}
How to add files and folders to the apk file when building it in unity.
What I need is to have some files and a folder to be present in the parent directory of the application ( android/data/com.company.product/files) after installing it on Android.
This is my code for copying files from streaming assets into android persist path:
using System.IO;
using UnityEngine;
public static class FileManager
{
public static string RereadFile(string fileName)
{ //copies and unpacks file from apk to persistentDataPath where it can be accessed
string destinationPath = Path.Combine(Application.persistentDataPath, fileName);
#if UNITY_EDITOR
string sourcePath = Path.Combine(Application.streamingAssetsPath, fileName);
#else
string sourcePath = "jar:file://" + Application.dataPath + "!/assets/" + fileName;
#endif
//UnityEngine.Debug.Log(string.Format("{0}-{1}-{2}-{3}", sourcePath, File.GetLastWriteTimeUtc(sourcePath), File.GetLastWriteTimeUtc(destinationPath)));
//copy whatsoever
//if DB does not exist in persistent data folder (folder "Documents" on iOS) or source DB is newer then copy it
//if (!File.Exists(destinationPath) || (File.GetLastWriteTimeUtc(sourcePath) > File.GetLastWriteTimeUtc(destinationPath)))
{
if (sourcePath.Contains("://"))
{
// Android
WWW www = new WWW(sourcePath);
while (!www.isDone) {; } // Wait for download to complete - not pretty at all but easy hack for now
if (string.IsNullOrEmpty(www.error))
{
File.WriteAllBytes(destinationPath, www.bytes);
}
else
{
Debug.Log("ERROR: the file DB named " + fileName + " doesn't exist in the StreamingAssets Folder, please copy it there.");
}
}
else
{
// Mac, Windows, Iphone
//validate the existens of the DB in the original folder (folder "streamingAssets")
if (File.Exists(sourcePath))
{
//copy file - alle systems except Android
File.Copy(sourcePath, destinationPath, true);
}
else
{
Debug.Log("ERROR: the file DB named " + fileName + " doesn't exist in the StreamingAssets Folder, please copy it there.");
}
}
}
StreamReader reader = new StreamReader(destinationPath);
var jsonString = reader.ReadToEnd();
reader.Close();
return jsonString;
}
}
I hope it helps.
Background
I have an App-Manager app, which allows to send APK files to other apps.
Up until Android 4.4 (including), all I had to do for this task is to send the paths to the original APK files (all were under "/data/app/..." which is accessible even without root).
This is the code for sending the files (docs available here) :
intent=new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setType("*/*");
final ArrayList<Uri> uris=new ArrayList<>();
for(...)
uris.add(Uri.fromFile(new File(...)));
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM,uris);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_NO_HISTORY|Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET|Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
The problem
What I did worked since all apps' APK files had a unique name (which was their package name).
Ever since Lollipop (5.0), all apps' APK files are simply named "base.APK" , which make other apps unable to comprehend attaching them.
This means I have some options to send the APK files. This is what I was thinking about:
copy them all to a folder, rename them all to unique names and then send them.
compress them all to a single file and then send it. The compression level could be minimal, as APK files are already compressed anyway.
The problem is that I would have to send the files as quickly as possible, and if I really have to have those temporary files (unless there is another solution), to also dispose them as quickly as possible.
Thing is, I don't get notified when third party apps have finished handling the temporary file, and I also think that choosing multiple files would take quite some time to prepare no matter what I choose.
Another issue is that some apps (like Gmail) actually forbid sending APK files.
The question
Is there an alternative to the solutions I've thought of? Is there maybe a way to solve this problem with all the advantages I had before (quick and without junk files left behind) ?
Maybe some sort of way to monitor the file? or create a stream instead of a real file?
Will putting the temporary file inside a cache folder help in any way?
Any app registered for that Intent should be able to process files with the same file name but different paths. To be able to cope with the fact that access to files provided by other apps can only be accessed while the receiving Activity is running (see Security Exception when trying to access a Picasa image on device running 4.2 or SecurityException when downloading Images with the Universal-Image-Downloader) receiving apps need to copy the files to a directory they have permanently access to. My guess is that some apps haven't implemented that copy process to deal with identical file names (when copied the file path would likely be the same for all files).
I'd suggest to serve the files through a ContentProvider instead of directly from the file system. That way you can create a unique file name for each file you want to send.
Receiving apps "should" receive files more or less like this:
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(uri, new String[] { OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE }, null, null, null);
// retrieve name and size columns from the cursor...
InputStream in = contentResolver.openInputStream(uri);
// copy file from the InputStream
Since apps should open the file using contentResolver.openInputStream() a ContentProvider should/will work instead of just passing a file uri in the Intent. Of course there might be apps that misbehave and this needs to be tested thoroughly but in case some apps won't handle ContentProvider served files you could add two different share options (one legacy and the regular one).
For the ContentProvider part there's this:
https://developer.android.com/reference/android/support/v4/content/FileProvider.html
Unfortunately there's also this:
A FileProvider can only generate a content URI for files in
directories that you specify beforehand
If you can define all directories you want to share files from when the app is built, the FileProvider would be your best option.
I'm assuming your app would want to share files from any directory, so you'll need your own ContentProvider implementation.
The problems to solve are:
How do you include the file path in the Uri in order to extract the very same path at a later stage (in the ContentProvider)?
How do you create a unique file name that you can return in the ContentProvider to the receiving app? This unique file name needs to be the same for multiple calls to the ContentProvider meaning you can't create a unique id whenever the ContentProvider is called or you'd get a different one with each call.
Problem 1
A ContentProvider Uri consists of a scheme (content://), an authority and the path segment(s), e.g.:
content://lb.com.myapplication2.fileprovider/123/base.apk
There are many solutions to the first problem. What I suggest is to base64 encode the file path and use it as the last segment in the Uri:
Uri uri = Uri.parse("content://lb.com.myapplication2.fileprovider/" + new String(Base64.encode(filename.getBytes(), Base64.DEFAULT));
If the file path is e.g.:
/data/data/com.google.android.gm/base.apk
then the resulting Uri would be:
content://lb.com.myapplication2.fileprovider/L2RhdGEvZGF0YS9jb20uZ29vZ2xlLmFuZHJvaWQuZ20vYmFzZS5hcGs=
To retrieve the file path in the ContentProvider simply do:
String lastSegment = uri.getLastPathSegment();
String filePath = new String(Base64.decode(lastSegment, Base64.DEFAULT) );
Problem 2
The solution is pretty simple. We include a unique identifier in the Uri generated when we create the Intent. This identifier is part of the Uri and can be extracted by the ContentProvider:
String encodedFileName = new String(Base64.encode(filename.getBytes(), Base64.DEFAULT));
String uniqueId = UUID.randomUUID().toString();
Uri uri = Uri.parse("content://lb.com.myapplication2.fileprovider/" + uniqueId + "/" + encodedFileName );
If the file path is e.g.:
/data/data/com.google.android.gm/base.apk
then the resulting Uri would be:
content://lb.com.myapplication2.fileprovider/d2788038-53da-4e84-b10a-8d4ef95e8f5f/L2RhdGEvZGF0YS9jb20uZ29vZ2xlLmFuZHJvaWQuZ20vYmFzZS5hcGs=
To retrieve the unique identifier in the ContentProvider simply do:
List<String> segments = uri.getPathSegments();
String uniqueId = segments.size() > 0 ? segments.get(0) : "";
The unique file name the ContentProvider returns would be the original file name (base.apk) plus the unique identifier inserted after the base file name. E.g. base.apk becomes base<unique id>.apk.
While this might all sound very abstract, it should become clear with the full code:
Intent
intent=new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setType("*/*");
final ArrayList<Uri> uris=new ArrayList<>();
for(...)
String encodedFileName = new String(Base64.encode(filename.getBytes(), Base64.DEFAULT));
String uniqueId = UUID.randomUUID().toString();
Uri uri = Uri.parse("content://lb.com.myapplication2.fileprovider/" + uniqueId + "/" + encodedFileName );
uris.add(uri);
}
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM,uris);
ContentProvider
public class FileProvider extends ContentProvider {
private static final String[] DEFAULT_PROJECTION = new String[] {
MediaColumns.DATA,
MediaColumns.DISPLAY_NAME,
MediaColumns.SIZE,
};
#Override
public boolean onCreate() {
return true;
}
#Override
public String getType(Uri uri) {
String fileName = getFileName(uri);
if (fileName == null) return null;
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(fileName);
}
#Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
String fileName = getFileName(uri);
if (fileName == null) return null;
File file = new File(fileName);
return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY);
}
#Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
String fileName = getFileName(uri);
if (fileName == null) return null;
String[] columnNames = (projection == null) ? DEFAULT_PROJECTION : projection;
MatrixCursor ret = new MatrixCursor(columnNames);
Object[] values = new Object[columnNames.length];
for (int i = 0, count = columnNames.length; i < count; i++) {
String column = columnNames[i];
if (MediaColumns.DATA.equals(column)) {
values[i] = uri.toString();
}
else if (MediaColumns.DISPLAY_NAME.equals(column)) {
values[i] = getUniqueName(uri);
}
else if (MediaColumns.SIZE.equals(column)) {
File file = new File(fileName);
values[i] = file.length();
}
}
ret.addRow(values);
return ret;
}
private String getFileName(Uri uri) {
String path = uri.getLastPathSegment();
return path != null ? new String(Base64.decode(path, Base64.DEFAULT)) : null;
}
private String getUniqueName(Uri uri) {
String path = getFileName(uri);
List<String> segments = uri.getPathSegments();
if (segments.size() > 0 && path != null) {
String baseName = FilenameUtils.getBaseName(path);
String extension = FilenameUtils.getExtension(path);
String uniqueId = segments.get(0);
return baseName + uniqueId + "." + extension;
}
return null;
}
#Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0; // not supported
}
#Override
public int delete(Uri uri, String arg1, String[] arg2) {
return 0; // not supported
}
#Override
public Uri insert(Uri uri, ContentValues values) {
return null; // not supported
}
}
Note:
My sample code uses the org.apache.commons library for the file name manipulations (FilenameUtils.getXYZ)
using base64 encoding for the file path is a valid approach because all character used in base64 ([a-zA-Z0-9_-=] according to this https://stackoverflow.com/a/6102233/534471) are valid in an Uri path (0-9, a-z, A-Z, _-!.~'()*,;:$&+=/# --> see https://developer.android.com/reference/java/net/URI.html)
Your manifest would have to define the ContentProvider like so:
<provider
android:name="lb.com.myapplication2.fileprovider.FileProvider"
android:authorities="lb.com.myapplication2.fileprovider"
android:exported="true"
android:grantUriPermissions="true"
android:multiprocess="true"/>
It won't work without android:grantUriPermissions="true" and android:exported="true" because the other app wouldn't have permission to access the ContentProvider (see also http://developer.android.com/guide/topics/manifest/provider-element.html#exported) . android:multiprocess="true" on the other hand is optional but should make it more efficient.
Here's a working solution for using SymLinks. Disadvantages:
works from API 14, and not on API 10 , not sure about in between.
uses reflection, so might not work in the future, and on some devices.
must create the symlinks in the path of "getFilesDir", so you have to manage them by yourself, and create unique files names as needed.
The sample shares the APK of the current app.
Code:
public class SymLinkActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(lb.com.myapplication2.R.layout.activity_main);
final Intent intent=new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setType(MimeTypeMap.getSingleton().getMimeTypeFromExtension("apk"));
final String filePath;
try
{
final android.content.pm.ApplicationInfo applicationInfo=getPackageManager().getApplicationInfo(getPackageName(),0);
filePath=applicationInfo.sourceDir;
}
catch(NameNotFoundException e)
{
e.printStackTrace();
finish();
return;
}
final File file=new File(filePath);
final String symcLinksFolderPath=getFilesDir().getAbsolutePath();
findViewById(R.id.button).setOnClickListener(new android.view.View.OnClickListener(){
#Override
public void onClick(final android.view.View v)
{
final File symlink=new File(symcLinksFolderPath,"CustomizedNameOfApkFile-"+System.currentTimeMillis()+".apk");
symlink.getParentFile().mkdirs();
File[] oldSymLinks=new File(symcLinksFolderPath).listFiles();
if(oldSymLinks!=null)
{
for(java.io.File child : oldSymLinks)
if(child.getName().endsWith(".apk"))
child.delete();
}
symlink.delete();
// do some dirty reflection to create the symbolic link
try
{
final Class<?> libcore=Class.forName("libcore.io.Libcore");
final java.lang.reflect.Field fOs=libcore.getDeclaredField("os");
fOs.setAccessible(true);
final Object os=fOs.get(null);
final java.lang.reflect.Method method=os.getClass().getMethod("symlink",String.class,String.class);
method.invoke(os,file.getAbsolutePath(),symlink.getAbsolutePath());
final ArrayList<Uri> uris=new ArrayList<>();
uris.add(Uri.fromFile(symlink));
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM,uris);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_NO_HISTORY|Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET|Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
startActivity(intent);
android.widget.Toast.makeText(SymLinkActivity.this,"succeeded ?",android.widget.Toast.LENGTH_SHORT).show();
}
catch(Exception e)
{
android.widget.Toast.makeText(SymLinkActivity.this,"failed :(",android.widget.Toast.LENGTH_SHORT).show();
e.printStackTrace();
// TODO handle the exception
}
}
});
}
}
EDIT: for the symlink part, for Android API 21 and above, you can use this instead of reflection :
Os.symlink(originalFilePath,symLinkFilePath);
ey up. ive built a simple music app that reads wav files from the sdcard and plays them.
how do i access the default media directory?
this is how i get the sdcard
public void LoadSounds() throws IOException
{
String extState = Environment.getExternalStorageState();
if(!extState.equals(Environment.MEDIA_MOUNTED)) {
//handle error here
}
else {
File sd = new File(Environment.getExternalStorageDirectory ()); //this needs to be a folder the user can access, like media
as usual the docs dont give an actual example of usage but it says this - If you're using API Level 8 or greater, use getExternalFilesDir() to open a File that represents the external storage directory where you should save your files. This method takes a type parameter that specifies the type of subdirectory you want, such as DIRECTORY_MUSIC...
how do i use it?
thank you
edit:
this makes it crash if i try to fill a spinner array with file path Strings.
File path = getExternalFilesDir(Environment.DIRECTORY_MUSIC);
File sd = new File(path, "/myFolder");
File[] sdDirList = sd.listFiles(new WavFilter());
if (sdDirList != null)
{
//sort the spinner
amountofiles = sdDirList.length;
array_spinner=new String[amountofiles];
......
final Spinner s = (Spinner) findViewById(R.id.spinner1); //crashes here
ArrayAdapter<?> adapter = new ArrayAdapter<Object>(this,
android.R.layout.select_dialog_item, array_spinner);
EDIT2:
ok so ive done this test that is supposed to write a txt file to the music directory.
i run the app, no txt file is written anywhere on the device i can find.
// Path to write files to
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).getAbsolutePath();
String fname = "mytest.txt";
// Current state of the external media
String extState = Environment.getExternalStorageState();
// External media can be written onto
if (extState.equals(Environment.MEDIA_MOUNTED))
{
try {
// Make sure the path exists
boolean exists = (new File(path)).exists();
if (!exists){ new File(path).mkdirs(); }
// Open output stream
FileOutputStream fOut = new FileOutputStream(path + fname);
fOut.write("Test".getBytes());
// Close output stream
fOut.flush();
fOut.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
another edit: i will get this working!!
so if i use this line it creates a folder on the sdcard called 'Musictest'. dont understand??
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC + "test").getAbsolutePath();
////////////////////////////////////////////////////////////////////
Final Edit:
right so this will look for a folder called test in the devices music directory.
if it doesnt exist, it will be created.
(some fixing to be done here, error if empty) it then lists the files in the directory and adds them to an array.
public void LoadSounds() throws IOException
{
String extState = Environment.getExternalStorageState();
// Path to write files to
String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC + "/test").getAbsolutePath();
if(!extState.equals(Environment.MEDIA_MOUNTED)) {
//handle error here
}
else {
//do your file work here
// Make sure the path exists
boolean exists = (new File(path)).exists();
//if not create it
if (!exists){ new File(path).mkdirs(); }
File sd = new File(path);
//This will return an array with all the Files (directories and files)
//in the external storage folder
File[] sdDirList = sd.listFiles();
if (sdDirList != null)
{
//add the files to the spinner array
array_spinnerLoad=new String[sdDirList.length];
files = new String[sdDirList.length];
for(int i=0;i<sdDirList.length;i++){
array_spinnerLoad[i] = sdDirList[i].getName();
files[i] = sdDirList[i].getAbsolutePath();
}
}
}
}
as mentioned in the docs, getExternalFilesDir() return File. And File object can represent either file or directory.
Therefore:
File musicDirectory = new File( getExternalFilesDir(Environment.DIRECTORY_MUSIC));
Will give you the object to play with.
I have been trying to get the URI path for an asset file.
uri = Uri.fromFile(new File("//assets/mydemo.txt"));
When I check if the file exists I see that file doesn't exist
File f = new File(filepath);
if (f.exists() == true) {
Log.e(TAG, "Valid :" + filepath);
} else {
Log.e(TAG, "InValid :" + filepath);
}
Can some one tell me how I can mention the absolute path for a file existing in the asset folder
There is no "absolute path for a file existing in the asset folder". The content of your project's assets/ folder are packaged in the APK file. Use an AssetManager object to get an InputStream on an asset.
For WebView, you can use the file Uri scheme in much the same way you would use a URL. The syntax for assets is file:///android_asset/... (note: three slashes) where the ellipsis is the path of the file from within the assets/ folder.
The correct url is:
file:///android_asset/RELATIVEPATH
where RELATIVEPATH is the path to your resource relative to the assets folder.
Note the 3 /'s in the scheme. Web view would not load any of my assets without the 3. I tried 2 as (previously) commented by CommonsWare and it wouldn't work. Then I looked at CommonsWare's source on github and noticed the extra forward slash.
This testing though was only done on the 1.6 Android emulator but I doubt its different on a real device or higher version.
EDIT: CommonsWare updated his answer to reflect this tiny change. So I've edited this so it still makes sense with his current answer.
Finally, I found a way to get the path of a file which is present in assets from this answer in Kotlin. Here we are copying the assets file to cache and getting the file path from that cache file.
#Throws(IOException::class)
fun getFileFromAssets(context: Context, fileName: String): File = File(context.cacheDir, fileName)
.also {
if (!it.exists()) {
it.outputStream().use { cache ->
context.assets.open(fileName).use { inputStream ->
inputStream.copyTo(cache)
}
}
}
}
Get the path to the file like:
val filePath = getFileFromAssets(context, "fileName.extension").absolutePath
Please try this code working fine
Uri imageUri = Uri.fromFile(new File("//android_asset/luc.jpeg"));
/* 2) Create a new Intent */
Intent imageEditorIntent = new AdobeImageIntent.Builder(this)
.setData(imageUri)
.build();
Be sure ,your assets folder put in correct position.
Works for WebView but seems to fail on URL.openStream(). So you need to distinguish file:// protocols and handle them via AssetManager as suggested.
Try this out, it works:
InputStream in_s =
getClass().getClassLoader().getResourceAsStream("TopBrands.xml");
If you get a Null Value Exception, try this (with class TopBrandData):
InputStream in_s1 =
TopBrandData.class.getResourceAsStream("/assets/TopBrands.xml");
InputStream is = getResources().getAssets().open("terms.txt");
String textfile = convertStreamToString(is);
public static String convertStreamToString(InputStream is)
throws IOException {
Writer writer = new StringWriter();
char[] buffer = new char[2048];
try {
Reader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
int n;
while ((n = reader.read(buffer)) != -1) {
writer.write(buffer, 0, n);
}
} finally {
is.close();
}
String text = writer.toString();
return text;
}
try this :
Uri uri = Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.cat);
I had did it and it worked
Yeah you can't access your drive folder from you android phone or emulator because your computer and android are two different OS.I would go for res folder of android because it has good resources management methods. Until and unless you have very good reason to put you file in assets folder. Instead You can do this
try {
Resources res = getResources();
InputStream in_s = res.openRawResource(R.raw.yourfile);
byte[] b = new byte[in_s.available()];
in_s.read(b);
String str = new String(b);
} catch (Exception e) {
Log.e(LOG_TAG, "File Reading Error", e);
}
If you are okay with not using assets folder and want to get a URI without storing it in another directory, you can use res/raw directory and create a helper function to get the URI from resID:
internal fun Context.getResourceUri(#AnyRes resourceId: Int): Uri =
Uri.Builder()
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
.authority(packageName)
.path(resourceId.toString())
.build()
Now if you have a mydemo.txt file under res/raw directory you can simply get the URI by calling the above helper method
context.getResourceUri(R.raw.mydemo)
Reference: https://stackoverflow.com/a/57719958
Worked for me Try this code
uri = Uri.fromFile(new File("//assets/testdemo.txt"));
String testfilepath = uri.getPath();
File f = new File(testfilepath);
if (f.exists() == true) {
Toast.makeText(getApplicationContext(),"valid :" + testfilepath, 2000).show();
} else {
Toast.makeText(getApplicationContext(),"invalid :" + testfilepath, 2000).show();
}