I am trying to learn how to use the Simple XML Framework as detailed in this thread : Best practices for parsing XML.
I am using the following code :
public class SimpleXMLParserActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
Serializer serializer = new Persister();
Example example = new Example("Example message", 123);
File result = new File("example.xml");
try {
Log.d("Start", "Starting Serializer");
serializer.write(example, result);
} catch (Exception e) {
// TODO Auto-generated catch block
Log.d("Self", "Error");
e.printStackTrace();
}
}
}
I am having a problem understanding the line
File result = new File("example.xml");
1) Does this line create a new file in my app called example.xml ? If so where is this file located.
2) Or does this line look for an existing file called example.xml and then add to it ? If so where should the example.xml file be placed in my app bundle so that it can be found. I do notice at the moment I am getting an error message :
java.io.FileNotFoundException: /example.xml (Read-only file system)
Thank you.
File result = new File("example.xml")
This line will just store the filename "example.xml" in a new File object. There is no check if that file actually exists and it does not try to create it either.
A file without specifying an absolute path (starting with / like new File("/sdcard/example.xml")) is considered to be in the current working directory which I guess is / for Android apps (-> /example.xml (Read-only file system))
I guess serializer.write(example, result); tries to create the actual file for your but fails since you can't write to '/'.
You have to specify a path for that file. There are several places you can store files, e.g.
Context#getFilesDir() will give you a place in your app's home directory (/data/data/your.package/files/) where only you can read / write - without extra permission.
Environment#getExternalStorageDirectory() will give you the general primary storage thing (might be /sdcard/ - but that's very different for devices). To write here you'll need the WRITE_EXTERNAL_STORAGE permission.
there are more places available in Environment that are more specialized. E.g. for media files, downloads, caching, etc.
there is also Context#getExternalFilesDir() for app private (big) files you want to store on the external storage (something like /sdcard/Android/data/your.package/)
to fix your code you could do
File result = new File(Environment.getExternalStorageDirectory(), "example.xml");
Edit: either use the provided mechanisms to get an existing directory (preferred but you are limited to the folders you are supposed to use):
// via File - /data/data/your.package/app_assets/example.xml
File outputFile = new File(getDir("assets", Context.MODE_PRIVATE), "example.xml");
serializer.write(outputFile, result);
// via FileOutputStream - /data/data/your.package/files/example.xml
FileOutputStream outputStream = openFileOutput("example.xml", Context.MODE_PRIVATE);
serializer.write(outputStream, result);
or you may need to create the directories yourself (hackish way to get your app dir but it should work):
File outputFile = new File(new File(getFilesDir().getParentFile(), "assets"), "example.xml");
outputFile.mkdirs();
serializer.write(outputFile, result);
Try to avoid specifying full paths like "/data/data/com.simpletest.test/assets/example.xml" since they might be different on other devices / Android versions. Even the / is not guaranteed to be /. It's safer to use File.separatorChar instead if you have to.
2 solutions to do it cleanly :
use openFileOutput to write a private file in the application private directory (which could be located in the internal memory or the external storage if the app was moved there). See here for a snippet
or use the File constructor to create the File anywhere your app has write access. This is if you want to store the file on the SDCard for example. Instantiating a file doesn't create it on the file system, unless you start writiung to it (with FileOutputStream for example)
I'd recommend approach 1, it's better for users because these files get erased when your app is uninstalled. If the file is large, then using the External Storage is probably better.
What I read on the Android pages, I see it creates a file with that name:
File constructor
I think it writes it to the /data/data/packagname directory
edit: the 'packagename' was not shown in the tekst above. I put it between brackets. :s
Try saving to /sdcard/example.xml.
Related
I would like to be able to upload files in my JSF2.2 web application, so I started using the new <h:inputFile> component.
My only question is, how can I specify the location, where the files will be saved in the server? I would like to get hold of them as java.io.File instances. This has to be implemented in the backing bean, but I don't clearly understand how.
JSF won't save the file in any predefined location. It will basically just offer you the uploaded file in flavor of a javax.servlet.http.Part instance which is behind the scenes temporarily stored in server's memory and/or temporary disk storage location which you shouldn't worry about.
Important is that you need to read the Part as soon as possible when the bean action (listener) method is invoked. The temporary storage may be cleared out when the HTTP response associated with the HTTP request is completed. In other words, the uploaded file won't necessarily be available in a subsequent request.
So, given a
<h:form enctype="multipart/form-data">
<h:inputFile value="#{bean.uploadedFile}">
<f:ajax listener="#{bean.upload}" />
</h:inputFile>
</h:form>
You have basically 2 options to save it:
1. Read all raw file contents into a byte[]
You can use InputStream#readAllBytes() for this.
private Part uploadedFile; // +getter+setter
private String fileName;
private byte[] fileContents;
public void upload() {
fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
try (InputStream input = uploadedFile.getInputStream()) {
fileContents = input.readAllBytes();
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
In case you're not on Java 9 yet and therefore can't use InputStream#readAllBytes(), then head to Convert InputStream to byte array in Java for all other ways to convert InputStream to byte[].
Keep in mind that each byte of an uploaded file costs one byte of server memory. Be careful that your server don't exhaust of memory when users do this too often or can easily abuse your system in this way. If you want to avoid this, better use (temporary) files on local disk file system instead.
2. Or, write it to local disk file system
In order to save it to the desired location, you need to get the content by Part#getInputStream() and then copy it to the Path representing the location.
private Part uploadedFile; // +getter+setter
private File savedFile;
public void upload() {
String fileName = Paths.get(uploadedFile.getSubmittedFileName()).getFileName().toString(); // MSIE fix.
savedFile = new File(uploads, fileName);
try (InputStream input = file.getInputStream()) {
Files.copy(input, savedFile.toPath());
}
catch (IOException e) {
// Show faces message?
}
}
Note the Path#getFileName(). This is a MSIE fix as to obtaining the submitted file name. This browser incorrectly sends the full file path along the name instead of only the file name.
The uploads folder and the filename is fully under your control. E.g. "/path/to/uploads" and Part#getSubmittedFileName() respectively. Keep in mind that any existing file would be overwritten, you might want to use File#createTempFile() to autogenerate a filename. You can find an elaborate example in this answer.
Do not use Part#write() as some prople may suggest. It will basically rename the file in the temporary storage location as identified by #MultipartConfig(location). Also do not use ExternalContext#getRealPath() in order to save the uploaded file in deploy folder. The file will get lost when the WAR is redeployed for the simple reason that the file is not contained in the original WAR. Always save it on an absolute path outside the deploy folder.
For a live demo of upload-and-preview feature, check the demo section of the <o:inputFile> page on OmniFaces showcase.
See also:
Write file into disk using JSF 2.2 inputFile
How to save uploaded file in JSF
Recommended way to save uploaded files in a servlet application
I'm developing a program with NetBeans 8.0 and JavaFX Scene Builder 2.0 that need store some variables in a file, where admin users can modify it when needed, (like change server IP address, or a number value from a no editable textfield) and if they close and load again the program, the changes made in variables are kept. Like any settings section of a program.
I just try do it with the Properties file, but i have problems to store it in the same folder as .jar file. When the program execute the line new FileOutputStream("configuration.properties"); the file is created at root of the disk. As the folder of the file can be stored anywhere, i not know how indicate the right path.
Creating the properties file in the package of the main project and using getClass().getResourceAsStream("configuration.properties"); i can read it but then i can not write in for change values of variables.
Is there a better method to create a configuration file? Or properties file is the best option for this case?
My other question is whether it is possible to prevent access to the contents of the file or encrypt the content?
PD: I've been testing this part of the code in Linux operating system currently, but the program will be used in Windows 7 when ready.
If you use Maven, you can store your property files in your resources folder, say resources/properties/. When you need to load them, do this:
private Properties createProps(String name)
{
Properties prop = new Properties();
InputStream in = null;
try
{
in = getClass().getResourceAsStream(name);
prop.load(in);
}
catch (IOException ex)
{
System.err.println("failed to load \"" + name + "\": " + ex);
}
finally
{
try
{
if (in != null)
{
in.close();
}
}
catch (IOException ex)
{
System.err.println("failed to close InputStream for \"" + name + "\":\n" + FXUtils.extractStackTrace(ex));
}
}
return prop;
}
Where name is the full path to your properties file within your resources folder. For example, if you store props.properties in resources/properties/, then you would pass in properties/props.properties.
I am not 100% sure if you can carry over this exact procedure to a non-Maven project. You'd need to instruct whatever compiler tool you are using to also include your property files.
As far as your final question goes, in regards to encrypting your properties, I would consider posting that as a separate question (after having done thorough research to try to discover an existing solution that works for you).
At last i found how obtain the absolute path from folder where is .jar file to create properties file in, and read/write it. Here is the code:
File file = new File(System.getProperty("java.class.path"));
File filePath = file.getAbsoluteFile().getParentFile();
String strPath = filePath.toString();
File testFile = new File(strPath+"/configuration.properties");
Tested in Ubuntu 13.04 And Windows 7 and it works.
For encrypt the properties values i found this thread that answer how do it.
I would like to ask if its possible to put text files into my jar, I use them to make my map in my game, but users can get Highscores. now I want to save the Highscores with the map, so I have to save the map on the user their PC. Is there any way how I could do this? I've searched the internet for some ideas but I could not find anything that even came close to what I've wanted. I only had 3/4th of a year java so I don't know much about these things, everything that happens outside the debug of eclipse are problems for me(files are mainly one of those things, null exceptions, etc).
The main question now.
Is it possible to do? If yes, do you have any terms I could search on, or some sites/guides/tutorials? If no, is there any other way how I could save the highscores?
EDIT:
to make clear
Can I get the text file (the text inside the file) to be extracted to a different file in like the home directory of my game (where I save the settings and stuff) the basic maps are inside the jar file, so I want them to be extracted on the first start-up of the program
Greetings Carolien
"extracted to a different file in like the home directory of my game (where i save the settings and stuff) the basic maps are inside the jar file, so i want them to be extracted on the first startup of the program"
You can get the URL by using getClass().getResource()
URL url = getClass().getResource("/res/myfile.txt");
Then create a File object from the URI of the URL
File file = new File(url.toURI());
Then just perform your normal file operations.
if (file.renameTo(new File(System.getProperty("user.home") + "\\" + file.getName()))) {
System.out.println("File is moved successful!");
} else {
System.out.println("File is failed to move!");
}
Assuming your file structure is like below, it should work fine
ProjectRoot
src
res
myfile.txt
Note: the above is moving the entire file. If you want to extract just the data inside the file, then you can simple use
InputStream is = getClass().getResourceAsStream("/res/myfile.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
The just do normal IO operation with the reader. See here for help with writing the file.
I am trying to output numeric values one at a time from an Android application I'm writing, but I'm having a lot of trouble figuring out what's going on. Tried looking for answers, but only confused further. This strikes me as something that should be relatively straightforward, so I feel pretty dumb for being so confused by it.
String directory = Environment.getExternalStorageDirectory().getAbsolutePath();
When I log the directory I get a path "/storage/emulated/0" Where is that? Is that different from what I would get if I wasn't debugging?
Then I have:
String fileName = directory + "/Android/data/com.sample.app/files/test.txt"
File myFile = new File(fileName);
FileOutputStream fos;
try {
fos = new FileOutputStream(myFile);
String text = "Test text\n";
fos.write(text.getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e){
e.printStackTrace();
}
I tried using the Windows Explorer to figure out where stuff is saving and/or is supposed to be saved but I don't see it. This is code based on the information in this link: http://developer.android.com/guide/topics/data/data-storage.html, but I really don't understand where the "/storage/emulated/0" comes from and how I either access that location or get rid of it.
EDIT: Right now I just want to save all the numbers so I can check what is coming out. The numbers are recorded from the audio input.
EDIT: Using the ASTRO File app on my phone revealed the files
Didn't need the "/Android/data/com.sample.app/files/" part, don't know how to use that.
Path wrong?
/storage/emulated/0 is a path at your filesystem which represents the external storage. At earlier versions of Android we often had /mnt/sdcard/ or something similiar, but many devices today don't have a sdcard but emulate an external storage anyway.
To view the files at your Android filesystem I'd recommend to use an App like Astro File Manager. Just take a look if your file has been written.
One possible mistake could be, that you you are missing a File.separator between your directory and the local path.
String fileName = directory + File.seperator + "Android/data/com.sample.app/file/test.txt"
Directory created?
You should also make sure, that the directory exists by calling myDir.mkDirs();, where myDir is the complete path without the filename.
To create the directory you can use the following code
directory = directory + "/Android/data/com.sample.app/file/test.txt"
new File(directory).mkDirs();
Uses-Permission in Manifest?
Last error source could be, that you might miss the external storage permission, you need a
You also need to make sure, that you require the permission for writing to the external storage. Take a look for <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> in your Android Manifest file.
I have a file called Gate.IC inside my assets in my Android App.
I use this code to measure the length of the file in the assets:
private byte[] Buf = new byte[1024*512];
public int FileLength (String s)
{
int Count = 0;
try {
InputStream s2 = assetManager.open(s);
int tmp = 0;
while ((tmp=s2.read(Buf))>0)
Count+=tmp;
s2.close();
}
catch (IOException e) {
String Message = e.getMessage();
}
return Count;
}
This code works fine for all files except this one.
When it gets to this file, it does open it(and shows the correct file length), but when it reads it I get an IOException and the LogCat says "Error reading asset data" and then "Unable to access asset data: -1"
If I take a different file and change it's name to Gate.IC and don't have the actual Gate.IC file in the assets, it works.
If I change the name of the original Gate.IC into another asset's name, then I get the same error with the "cover" name.
I don't know what it is in this file that it just can't read it.
Here is the Rogue file:
https://dl.dropbox.com/u/8025882/RPG/Gate.IC
you can use this for getting length of the file:
getAssets().openFd( "filename" ).getLength();
I have solved the issue.
Well as I mentioend, it turns out ADT or the Android SDK packaging would compress some fo the assets. My file being my own custom format would be compressed.
Once your file is compressed you cannot read it the same way I did.
There is a program in Android SDK called aapt.exe. It does the packaging of the assets.
All you need to do is call this command with the flag -0 .
Sounds simple, right?
The issue is that eclipse does not let you add flags to this command from within the ADT plugin.
You need to either edit the Android SDK XML build files, or to replace aapt.exe with your own program that calls the original aapt.exe program with the flags you want.
I did the latter.
Here is my devblog entry about it.
http://pompidev.net/2012/10/27/unable-to-access-asset-data-1-and-compressed-assetsandroid/