Get relative path to file within project in JNI - java

Using JNI I can't get access to files like this:
ifstream file("file.txt");
file.txt is in folder jni, which is the same folder as the native code files
I can only access absolute path ("/sdcard/file.txt"), but this trick is not what I'm looking for.
Tried "data/data/com.example.SomeExample/jni/file.txt" but no luck.
How should I refer to a file as reletive path when working in native code?

The jni folder is not added to your APK. If you want files to be bundled with your application, I'd suggest putting them in the assets folder. If the assets folder doesn't already exist, place it at the same level as the jni folder (so they are siblings).
If you take this approach you will have to use the Asset Manager. This has a native interface, found in android/asset_manager.h. To open your file use:
AAsset *a = AAssetManager_open(pAssetManager, "file.txt", AASSET_MODE_BUFFER);
if (a)
{
const void *res = AAsset_getBuffer(a);
//do something with the file!
AAsset_close(a);
}
There are different flags you can pass in instead of AASSET_MODE_BUFFER.

Related

Java can't get relative path for file

Image DescriptionTrying to access a test.txt file that is in the same location as my HelloController.java file but for some reason, it is showing that the file does not exist. I've tried moving the file around but it does not work.
Using the absolute path works, but this is a shared project so it will be ran on other computers. Any suggestions would be much appreciated.
Your best bet is to add it to the class path and reading it as a class path resource.
The relative path root is your "working directory". Which means if you try to access "." you will start at your working directory. This directory is only set once for your application and is normally the folder which was opened when you started it.
When working with IDEs (like in your case) the working directory will be the root folder of your project (So the folder in which the pom.xml and src folders are located.
If you want to access the file via the normal file API you are currently using, just put the file in that diretory and it should work (given you share it with the other people in the same location).
If you need the file to be inside your generated output jar-file, you will need to use the File as a resource (See duffymo's answer), as the file does not exist by itself on the file system, but as a file inside your jar-file.
If you want to know your current working directory, you can create a File refrence to "." and expand it to an absolute path (Which will replace refrences like "." and ".." and generate a file path from your root) and then write it to the console. This would look something like this:
// Get refrence to the current working directory
File workingDirectoryReference = new File(".");
// Convert it to an absolute path string
String absolutePath = workingDirectoryReference.getAbsolutePath();
// Output to console
System.out.println(absolutePath );

Android Studio cannot read from file, does not exist

I'm trying to read from a file in Android Studio, in a small Java app. So I'm trying this:
File test = new File("C:\\testing\\testFile.dat");
if (test.exists()) {
System.out.println("test exists");
}
else {
System.out.println("test doesn't exist");
}
The file definitely exists, but it keeps on reporting that the file doesn't exist. I was able to work around this with another file by using the AssetManager and reading it through a stream, but the method I'm calling now requires a File's absolute path, but it's point blank refusing to find the file.
Am I doing something dumb, or misunderstanding something?
UPDATE
Ok, thanks for the input, I've now solved the problem. First I had to upload the file I wanted into the virtual device's storage, then I was able to get the path to it.
File test = new File(this.getFilesDir().getAbsolutePath(), "testFile.dat");
but the method I'm calling now requires a File's absolute path
Assets are files on your development machine. They are not files on the device.
Ideally, you switch to some library that supports InputStream or similar options, rather than requiring a filesystem path. If that is not an option, you can always get the InputStream from AssetManager and use that to make a copy of the data in some file that you control (e.g., in getCacheDir()). You can then pass the path to that file to this method.
You can place this file in your assets/ folder inside the android project and access using the following code.
val inputSteam = assets.open("testFile.dat")
or place it inside the res/raw folder and access it like below.
val inputStream = resources.openRawResource(R.raw.testFile)
We can't access a file on a development machine like this and won't be available on an android device so it will break so it's better if we move this somewhere inside the project and access it as above.

fopen in JNI C code get failed for file placed in assets folder in android application

I have kept some files in assets folder of android application.
Now i compile that application and get apk. [when i extract that apk my files are there in assets folder]
Now i install that apk in mobile device
and in That application has some code in c programing with JNI interface.
Now my fopen() call in c programming for that file get failed.
fopen("myfile","r");
I know while installing apk android copy assets file to /data/data/com.packagename/something
So does anyone knows that path so i can give it in fopen()
or is there any other method to open that file in C programming.
If i keep those files in sdcard folder and access like fopen("/sdcard/myfile","r"); then it works file. But i want to keep those files in assets folder only
You can use the asset manager to access assets in JNI code. It's part of NDK.
http://developer.android.com/ndk/reference/group___asset.html
Something like:
EXPORT_API void LoadAsset(char* filename, jobject assetManager){
AAssetManager* mgr = AAssetManager_fromJava(env, assetManager);
AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_BUFFER);
AAsset_read(asset, ...);
}
And then in Java something like:
LoadAsset("myfile", getContext().getAssetManager());
One way I've found is to write a test line in the code, something like:
System.out.println("Working Directory = " +
System.getProperty("user.dir"));
Now, if you know where your assets are stored by Android, /data/data/com.packagename/assets/file.png, for example, then you will know the reletive or absolute path to the assets. I hope this works for you, it helped me!

Problems with loading CLP file from JAR

I am using CLIPSJNI.
What I have is:
Environment clips = new Environment();
clips.load("main.clp");
where main.clp is put in the same level as src and bin folder.
This runs fine in Eclipse. However when I export to JAR. It cannot work.
I understand that there are some problems with the path when we export to JAR.
So I've seen people suggesting using this.getClass().getResourceStream() but this is not the case. Because what I need is the name of the file, not its content.
Any suggestions on how to fix this?
The issue is that the load is being done within the native library on the C side which is being passed a file name as an argument. The C code has no concept of a JAR file or how to extract files embedded within one. I think what you would need to do is always place your .clp files within the JAR file and then have a routine which extracts the data from the JAR file and saves it to a file. You can then load it using the load method and delete the file once done.

Absolute Path of Project's folder in Java

Lots of confusion in this topic. Several Questions have been asked. Things still seem unclear.
ClassLoader, Absolute File Paths etc etc
Suppose I have a project directory structure as,
MyProject--
--dist
--lib
--src
--test
I have a resource say "txtfile.txt" in "lib/txt" directory. I want to access it in a system independent way. I need the absolute path of the project.
So I can code the path as abspath+"/lib/Dictionary/txtfile.txt"
Suppose I do this
java.io.File file = new java.io.File(""); //Dummy file
String abspath=file.getAbsolutePath();
I get the current working directory which is not necessarily project root.
Suppose I execute the final 'prj.jar' from the 'dist' folder which also contains "lib/txt/txtfile.txt" directory structure and resource,It should work here too. I should absolute path of dist folder.
Hope the problem is clear.
You should really be using getResource() or getResourceAsStream() using your class loader for this sort of thing. In particular, these methods use your ClassLoader to determine the search context for resources within your project.
Specify something like getClass().getResource("lib/txtfile.txt") in order to pick up the text file.
To clarify: instead of thinking about how to get the path of the resource you ought to be thinking about getting the resource -- in this case a file in a directory somewhere (possibly inside your JAR). It's not necessary to know some absolute path in this case, only some URL to get at the file, and the ClassLoader will return this URL for you. If you want to open a stream to the file you can do this directly without messing around with a URL using getResourceAsStream.
The resources you're trying to access through the ClassLoader need to be on the Class-Path (configured in the Manifest of your JAR file). This is critical! The ClassLoader uses the Class-Path to find the resources, so if you don't provide enough context in the Class-Path it won't be able to find anything. If you add . the ClassLoader should resolve anything inside or outside of the JAR depending on how you refer to the resource, though you can certainly be more specific.
Referring to the resource prefixed with a . will cause the ClassLoader to also look for files outside of the JAR, while not prefixing the resource path with a period will direct the ClassLoader to look only inside the JAR file.
That means if you have some file inside the JAR in a directory lib with name foo.txt and you want to get the resource then you'd run getResource("lib/foo.txt");
If the same resource were outside the JAR you'd run getResource("./lib/foo.txt");
First, make sure the lib directory is in your classpath. You can do this by adding the command line parameter in your startup script:
$JAVA_HOME/bin/java -classpath .:lib com.example.MyMainClass
save this as MyProject/start.sh or any os dependent script.
Then you can access the textfile.txt (as rightly mentioned by Mark) as:
// if you want this as a File
URL res = getClass().getClassLoader().getResource("text/textfile.txt");
File f = new File(res.getFile());
// As InputStream
InputStream in = getClass().getClassLoader()
.getResourceAsStream("text/textfile.txt");
#Mark is correct. That is by far the simplest and most robust approach.
However, if you really have to have a File, then your best bet is to try the following:
turn the contents of the System property "java.class.path" into a list of pathnames,
identify the JAR pathname in the list based on its filename,
figure out what "../.." is relative to the JAR pathname to give you the "project" directory, and
build your target path relative to the project directory.
Another alternative is to embed the project directory name in a wrapper script and set it as a system property using a -D option. It is also possible to have a wrapper script figure out its own absolute pathname; e.g. using whence.

Categories