I have a programming mini competition tomorrow and we will be required to create our program on a flash drive given. The judges won't edit our code so it runs and I am worried that the flash drive letter will change and then my program won't be able to locate the text file it needs to read in.
I have always used paths for my flash drive like this:
FileReader file = new FileReader("E:/BPA/Crypto/input.txt");
Is there a way for me to guarantee my program will be able to read in the text file despite if the letter name for my flash drive isn't the same on the judges computer as it was on mine? Thanks!
You may
Put the file inside your sources
Use Class.getResourceAsStream(String name) to get InputStream of the file
For example, if you have class x.y.z.A
Copy input.txt to src folder into x/y/z package
Get corresponding InputStreamReader as InputStreamReader fileStream = new InputStreamReader(A.class.getResourceAsStream("input.txt"));
If you aren't sure what drive the file will be you could do something like this
char drive = 'A';
String filePath = ":/BPA/Crypto/input.txt";
while(drive != 'Z')
{
try{
Scanner readFromFile = new Scanner(new File(drive + filePath));
readFromFile.close(); //add this if you simply want the path or drvie letter
break;
}catch(FileNotFoundException error)
{
System.out.println("Drive: " + drive + " did not contained file in " + drive + filePath);
}
drive += 1;
}
Basically the idea is to attempt to open the file for reading from different drives starting at A up until Y. Obviously you can go further but I am going to assume that drives A-Y would safely exhaust all the possible drives on where ever you are running your software.
By the time you get our of the While loop the variable "drive" will contain the correct letter of the drive you want. You can modify it to be a function that returns the letter, or perhaps the file path, or simply use it once whenever you try to read from the text file. Up to you.
Related
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 know this question has been asked in a myriad of variations, but today I wish to emphasize one particular scenario when one wishes to read from a .txt file without specifying the absolute path.
Suppose we have the following set up in Eclipse.
projectName/packageName/subPackage/
and we have a class named Read.java inside the subPackage. The class will be attempting to read from the input1.txt.
We also have input1.txt inside the very same subPackage.
If one uses absolute paths, the code inside Read.java will be something of the following (let's assume now that input1.txt is placed on my Desktop for illustration purposes):
// Create a list to store the list of strings from each line of the input1.txt.
LinkedList<String> inputStrings = new LinkedList<String>();
BufferedReader bufferedTextIn = null;
try {
String line;
// Specify the file
String fileName = "C:" + File.separator
+ "Users" + File.separator
+ "Kevin" + File.separator
+ "Desktop" + File.separator
+ "input1.txt";
bufferedTextIn = new BufferedReader(new FileReader(fileName));
while ((line = bufferedTextIn.readLine()) != null) {
inputStrings.add(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedTextIn != null) {
bufferedTextIn.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
The problem with the above is the use of absolute paths to my desktop. If I passed the code to my friend, he would need to manually change the path to his desktop. Even if I put input1.txt in my project folder, my friend would still need to manually change the path to make it work.
Note that using File.separator is a good practice because different OS interprets separators a bit differently, but it is still insufficient.
So what do we do instead?
Here is my solution.
String fileName = Read.class.getResource("input1.txt").getPath();
System.out.println(fileName);
bufferedTextIn = new BufferedReader(new FileReader(fileName));
Let's recap the scenario. We have our input1.txt file placed in the SAME FOLDER as the Read.java. So, the code above attempts to go to where Read.class exists (which is somewhere in the bin folder in Eclipse), and look for input1.txt. This is the path RELATIVE to where Read.class is located (in this case, it is trivially in the same folder, but you could very well specify another folder relative to where Read.class is located). The print statement lets you know exactly where it is located and is a good practice while debugging.
When you build in Eclipse, the .java files in the src folder would be compiled into .class files and be placed in the bin folder. The neat thing is that input1.txt is ALSO copied over the bin folder (and all the package hierarchies are maintained).
An important thing to note is to use getPath() rather than toString(), because the latter will add some extra text to the front of the path (I only knew that because I printed it out) and thus you get a NULL pointer exception because the fileName was not formatted correctly.
Another important thing to note is that I used Read.class.getResource("input1.txt").getPath(); instead of this.getClass().getResource("input1.txt").getPath(); because the code was called in a static context (in my main method). If you create an object, then feel free to use the latter.
If you're interested in more advanced features, you can check out the link below:
What is the difference between Class.getResource() and ClassLoader.getResource()?
I hope this helps!
Edit:
You could use the following to get the directory where Read.class resides in also.
String fileName = Read.class.getResource(".").getPath();
Specifying getResource("..") would go to the parent directory.
String fileName = Read.class.getResource("..").getPath();
The above may be useful if you want to have more control specifying the path (e.g. if you want to create output.txt inside the directory where Read.class resides, use
String fileName = Read.class.getResource(".").getPath() + "output.txt";
If you knew the file was going to be located in the same folder in each system this program was run on, you could use system variables to ensure any path defined would still work with different users. For windows, I've used:
String user = new com.sun.security.auth.module.NTSystem().getName();
to get a user name. This could then be substituted in your example to be:
String fileName = "C:" + File.separator
+ "Users" + File.separator
+ user + File.separator
+ "Desktop" + File.separator
+ "input1.txt";
I'm not sure how this would work outside of Windows however.
I'm writing a fairly simple Java program, and some options I require from the user give them the ability to read from a list of text for data comparisons.
What I would like to do is to give them the ability to simply define the file if it is in the current working path, and assume so unless they provide a separate path to their file. I'd like to use the same approach to generate a output file wherever they define.
So I start by checking if the file even exists (which does not work if you do not define a full path):
File f1 = new File(inputFile);
if(f1.exists())
System.out.println("Exists");
else if(!f1.exists())
{
System.out.println("Cannot find file " + inputFile);
System.exit(1);
}
So I could create the file with new File(path/inputFile), but I can break that fairly easily.
I want them to be able to do any of the following:
program.exe -m -1 inputFile.txt outputFile.txt
program.exe -m -1 C:\Users\tmp\Desktop\inputFile.txt outputFile.txt
program.exe -m -1 inputFile.txt C:\outputFile.txt
Any suggestions on where I might make my next step?
you can try something like
String currentUserPath = System.getProperty("user.dir")
to get the current path from where the application is being ran. Then you can check if the user provided on args[0] a full path, something like:
String inputPath = args[0];
inputPath = inputPath.trim().toLowerCase(); // as you are using windows case doesn't matter
if (!inputPath.startsWith("c:"))
inputPath = currentUserPath + inputPath;
and you could do something similar for the outputFile
I am in the process of making a program, which allows you to view your file system.
I was testing it, and ran into a problem: It was saying a directory called "Documents and Settings" was on my C:\ drive, while it wasn't there.
This is how I get my file array:
File f = new File(path); //path being a path sent by the client, for example C:\
if(f.isFile()){
//TODO start downloading it.
out.println("ERR: no dir!");
return;
}
Server.log.log("System path requested: " + f.getAbsolutePath());
File[] files = f.listFiles();
for(int i = 0; i < files.length; i++){
File found = files[i];
if(!found.exists()){
continue;
}
if(found.isDirectory()){
out.println("dir:" + found.getName());
}else{
out.println(found.getName());
}
System.out.println("Printed " + found.getName());
}
out.println("ENDOFLIST"); //Notify the client it has to stop receiving data
For some reason, this outputs quite a lot of directories that I can't seem to find, even with the "Show hidden folders" option on.
When trying to access these directories, it tries to read the contents of the directory, but since the directory doesn't exist it throws an exception, causing no data to get sent over sockets and my client freezing.
My question is: Is there a way to either check if the file/directory REALLY exists? Note, if you look at my code block, if the file/dir doesn't exist it already continues instead of writing it to the socket.
I've given it a google, but no matches were found. Also, I've given the search function a go, but it didn't come up with anything similar.
These are hidden system folders.
They do exist. Really.
You get exceptions because a lot of them don't have read access.
I suggest to use the new Fil I/O API introduced by Java 7, it features greatly improved support of the features a specific file system offers. It also offers the possibility to use walk the file tree.
Have a look at the FileVisitor http://docs.oracle.com/javase/7/docs/api/java/nio/file/FileVisitor.html that will greatly help you.
I was just reading some java book and making some small programs for practice, I created a small code to get information about the path I entered, and the code is:
String path = JOptionPane.showInputDialog("Enter Path to analyze");
File file = new File(path);
if (file.exists())
{
String result = "";
if (file.isDirectory())
{
result += "Path is directory\n ";
String [] resList = file.list();
for (String s : resList)
{
result += s + ", ";
}
}
if (file.isFile())
{
result += "Path is a file\n";
}
JOptionPane.showMessageDialog(null, result);
Now in the input dialogue, when I enter C:, the result is build, build.xml, manifest.mf, nbproject, src, but when I enter C:/, it shows the complete list of directories and files in C.
And strangely it does not happen with the D drive and other drives (i.e. the result is same for D:/ and D:), what is happening please explain?
Update
Same happens in WPF using C#!
C: means "whatever directory is currently selected on drive C:". In your case, it's probably the directory that your application is running from.
D: is the same as D:/ in your case because the root directory is the current working directory in D:.
This is not really a java question, but a windows/dos question.
The explanation comes down to the old dos command for switching drives.
Typing a drive letter followed by a colon is a command to change drives in dos, therefore the 'command' C: does nothing since your working dir is already on the C drive. The 'directory' returned by the native interface to the JRE is the same as if you used the path "", ie your working directory.
On the other hand, add a slash and it is a proper path, to the root of your C drive, therefore your JRE is given this directory by the native interface.
If you go to a dos command (windows>run>cmd) and type in C: you will see that it accepts the command but does not change directory, unless of course you are currently on a different drive at the time.
hope that helps.