Data reading in a jar File (in Java) and counting files - java

So here is my problem (I read the other answers, but didn't quite get it).
In a group of 4, we have created a game in Java as a University Project. Part of this is creating a *.jar File via Ant. There is several GameBoards saved in GameBoardx.txt Data where x is the number. We want to randomly select one of those. Therefore, every time a GameBoard is loaded, the files in the GameBoard directory are counted in order to generate a random number in the correct range. Our code works perfectly fine when running it from Eclipse. It fails to run from the *.jar File and exits with a NullPointerException.
int number = 0;
int fileCount = new File(new File("").getAbsolutePath()+"/GameBoards/").listFiles().length;
Random rand = new Random();
number = rand.nextInt(fileCount);
These Files are read later on using this:
static String fileName = new File("").getAbsolutePath();
static String line = null;
boolean verticalObstacles[][] = new boolean[16][17];
int currentLine = 1;
try {
FileReader fileReader = new FileReader(fileName+"/GameBoards/Board"+boardNumber+".txt");
BufferedReader bufferedReader = new BufferedReader(fileReader);
while ((line = bufferedReader.readLine()) != null){
if (currentLine <17){
for (int i=0; i<17; i++){
if (line.charAt(i) == '1'){
verticalObstacles[currentLine-1][i] = true;
} else {
verticalObstacles[currentLine-1][i] = false;
}
}
}
currentLine ++;
}
bufferedReader.close();
The rest of the code works with the *.jar File and the *.txt Files are included in it.
The solutions I found were not good for us, because the code has to work with the *.jar File as well as just starting it from Eclipse to pass the test.
What's the solution here to make in work in both?

Problem here is you can not read content of a Jar using File, you shall use java.nio classes to deal with this.
First of all you can read/get count of files from Jar/normal folder by using FileSystem, Path and FileVisitor classes:
Following code will work for both jar as well as IDE
ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader();
URI uri = sysClassLoader.getResource("GameBoards").toURI();
Path gameBoardPath = null;
if (uri.getScheme().equals("jar")) {
FileSystem fileSystem = FileSystems.newFileSystem(uri,
Collections.<String, Object> emptyMap());
gameBoardPath = fileSystem.getPath("/GameBoards");
} else {
gameBoardPath = Paths.get(uri);
}
PathVisitor pathVistor = new PathVisitor();
Files.walkFileTree(gameBoardPath, pathVistor);
System.out.println(pathVistor.getFileCount());
Following is the code for PathVisitor class
class PathVisitor extends SimpleFileVisitor<Path> {
private int fileCount = 0;
#Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throws IOException {
fileCount++;
return FileVisitResult.CONTINUE;
}
public int getFileCount() {
return fileCount;
}
}
And then you shall read content of specific file by using ClassLoader#getResourceAsStream
// ADD your random file picking logic here based on file Count to get boardNum
int boardNum = 1;
InputStream is = sysClassLoader.getResourceAsStream("GameBoards/Board" + boardNum + ".txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while((line=reader.readLine())!=null) {
System.out.println(line);
}
Hope this resolves your concerns and helps you in right direction.

Related

Copying Multiple files using SWT filedialog

I'm working a transfer file program and my program is working but I'm having a problem because when I select multiple files and put it on a textbox the source directory can't read what is on the textbox
this is my code
Opening file/files
btnSearchFile.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
FileDialog fd = new FileDialog(shell, SWT.MULTI);
Collection files = new ArrayList();
String firstFile = fd.open();
if (firstFile != null) {
String[] selectedFiles = fd.getFileNames();
File file = new File(firstFile);
for (int ii = 0; ii < selectedFiles.length; ii++ )
{
if (file.isFile())
{
displayFiles(new String[] { file.toString()});
}
else
displayFiles(file.list());
}
}
}
});
Displaying Files on textbox
public void displayFiles(String[] files) {
for (int i = 0; files != null && i < files.length; i++) {
txtSource.append(files[i]);
txtSource.setEditable(false);
}
}
Copy Files
public static void copyFile(File src, File dest) throws IOException
{
InputStream oInStream = new FileInputStream(src);
OutputStream oOutStream = new FileOutputStream(dest);
// Transfer bytes from in to out
byte[] oBytes = new byte[1024];
int nLength;
BufferedInputStream oBuffInputStream = new BufferedInputStream( oInStream );
while ((nLength = oBuffInputStream.read(oBytes)) > 0)
{
oOutStream.write(oBytes, 0, nLength);
}
oInStream.close();
oOutStream.close();
}
PS: One file is okay but if multiple files are selected and put on the textbox the source directory can't be found
In order to be completely helpful, we could really use some more detail (specific exceptions, a complete MCVE, which SWT widgets are used, etc.).
That said, I think you've provided enough to see that there are some issues with your code:
For starters, when you have multiple files selected, you're displaying the same file name (the name of the first one) over and over. Perhaps this is intentional, but worth mentioning:
String[] selectedFiles = fd.getFileNames();
File file = new File(firstFile);
for (int ii = 0; ii < selectedFiles.length; ii++ )
{
// You've used a FileDialog, so this should always be true
if (file.isFile())
{
// Will always be the first file
displayFiles(new String[] { file.toString()});
}
else
displayFiles(file.list());
}
Based on the context, I'm assuming txtSource is a Text widget. With that in mind, if we look at your displayFiles() method, you have the following:
txtSource.append(files[i]);
When you call displayFiles() repeatedly, you will be tacking on a file name after all the others, effectively building one long String which is the combination of all file names. When you go to copy the files listed, splitting that String back into valid file paths will be tricky.
My guess is that when you say:
"the source directory can't be found"
...you're just grabbing the content of txtSource. Something like this:
new File(txtSource.getText());
"...One file is okay..."
That will certainly work if there's only one file name in the Text object, but if there are multiple names it will result in a non-existent File.
For example, if you've selected two files:
C:\Users\me\FileA
C:\Users\me\FileB
Your txtSource would display C:\Users\me\FileAC:\Users\me\FileB. And the path C:\Users\me\FileAC:\Users\me\FileB most likely does not exist.
In that case, new File(txtSource.getText()).exists() would return false, and using that File in the constructor for FileInputStream (inside copyFile()) would result in a FileNotFoundException.
In short, just make sure that when you make your call to copyFile() and create the source File object that you're giving the path that you think you are, and not the concatenation of all files selected.

Having a variable from another class as the file name (GUI)

One class of my GUI has a variable for the file name. I want to pass this to another class so that I can process a file without having to hard code the file's name every time. The program compiles fine but I can't seem to run it correctly.
public void run() {
WordsCounter2 fileName = new WordsCounter2();
essayName = fileName.getFileList();
File f = new File(essayName);
//other code
WordsCounter2 is the class that houses the variable fileName, I'm calling it from this class and assigning it as the file's name, but this doesn't work. Could someone help?
if (rVal == JFileChooser.APPROVE_OPTION) {
File[] selectedFile = fileChooser.getSelectedFiles();
fileList = "nothing";
if (selectedFile.length > 0)
fileList = selectedFile[0].getName();
for (int i = 1; i < selectedFile.length; i++) {
fileList += ", " + selectedFile[i].getName();
}
statusBar.setText("You chose " + fileList);
}
else {
statusBar.setText("You didn't choose a file.");
}
fileList isn't empty because I have a label on the GUI that lists whatever file I chose.
Here's my new edit: now the exception occurs at the last line with the scanner and throws a NPE. Can you help?
public void run() {
WordsCounter2 pathNamesList = new WordsCounter2();
essayName = pathNamesList.getPathNamesList();
essayTitle = new String[essayName.size()];
essayTitle = essayName.toArray(essayTitle);
for (int i = 0; i < essayTitle.length; i++) {
f = new File(essayTitle[i]);
}
try {
Scanner scanner = new Scanner(f);
Your code is failing because File will not accept comma separated file names, in fact, it needs a single file path to create the file in the mentioned path. See here: https://docs.oracle.com/javase/7/docs/api/java/io/File.html
You'll have to get complete paths in an array and put the file creation statement as follows:
File f;
for (int i=0; i<fileList.length; i++)
f = new File(fileList[i]);
where fileList is a String array holding the list of pathnames.
In case you're trying to write some content to these files as well, this should be helpful: Trying to Write Multiple Files at Once - Java

Search a text file for List of names in JAVA

I have the following:
Folder that contains many files (about 300000), named "AllFilesFolder"
list of names, named "namesList"
An empty folder, named "filteredFolder"
I want to filter the folder "AllFilesFolder", by moving any file that contins any of the names in the list to the empty folder "filteredFolder".
I have approche this problem by the following code:
public static void doIt(List<String>namesList, String AllFilesFolder, String filteredFolder) throws FileNotFoundException {
// here we put all the files in the original folder in List variable name "filesList"
File[] filesList = new File(AllFilesFolder).listFiles();
// went throught the files one by one
for (File f : filesList) {
try {
FileReader fr = new FileReader(f);
BufferedReader reader = new BufferedReader(fr);
String line = "";
//this varibale used to test withir the files contins names or not
//we set it to false.
boolean goodDoc = false;
//go through the file line by line to chick the names (I wounder if there are a simbler whay)
while ((line = reader.readLine()) != null) {
for(String name:namesList){
if ( line.contains(name)) {
goodDoc = true;
}
}
}
reader.close();
// if this file contains the name we put this file into the other folder "filteredFolder"
if (goodDoc) {
InputStream inputStream = new FileInputStream(f);
OutputStream out = new FileOutputStream(new File(filteredFolder + f.getName()));
int read = 0;
byte[] bytes = new byte[4096];
while ((read = inputStream.read(bytes)) != -1) {
out.write(bytes, 0, read);
}
inputStream.close();
out.flush();
out.close();
}
} catch (Exception e) {
System.err.println(e);
}
}
}
By doing this I have two problems that I need your advice to solve:
I am reading each file twice, one time to search and the other to put it into the other folder.
When searching namesList I have for loop to takes the names one by one, Is there a way to search the list one time (without loop).
Many thanks in advance
I am reading each file twice, one time to search and the other to put it into the other folder.
Using NIO improves the copy performance. Here is the code example. If you can use Java 7 then you can use Files.copy()
When searching namesList I have for loop to takes the names one by one, Is there a way to search the list one time (without loop).
Use HashSet to store the names and use contains() method. It is a O(1) operation. Or another suggestion is to use Scanner.findWithinHorizon(pattern, horizon)

How do you make a function that will create a .jar file in Java?

I've made some code in Java that will change some files in another .jar file, and I know that the unpacking/changing works, but the repacking doesn't. It does succeed, but when I compare the new one and the original (I removed the code that changed the files), they differed. What's interesting is that when I extracted them both into different directories, and I runned diff -rqy on them both, it didn't show any difference.
Here is the current function:
public static void add(File source, JarOutputStream target, String removeme)
throws IOException
{
BufferedInputStream in = null;
try
{
File source2 = new File(source.getPath().replaceAll("^" + removeme,
""));
// File source2 = source;
if (source.isDirectory())
{
String name = source2.getPath().replace("\\", "/");
if (!name.isEmpty())
{
if (!name.endsWith("/"))
name += "/";
JarEntry entry = new JarEntry(name);
entry.setTime(source.lastModified());
target.putNextEntry(entry);
target.closeEntry();
}
for (File nestedFile : source.listFiles())
add(nestedFile, target, removeme);
return;
}
JarEntry entry = new JarEntry(source2.getPath().replace("\\", "/"));
entry.setTime(source.lastModified());
target.putNextEntry(entry);
in = new BufferedInputStream(new FileInputStream(source));
byte[] buffer = new byte[2048];
while (true)
{
int count = in.read(buffer);
if (count == -1)
break;
target.write(buffer, 0, count);
}
target.closeEntry();
}
finally
{
if (in != null)
in.close();
}
}
I call it like this:
JarOutputStream zip = new JarOutputStream(
new FileOutputStream(JARFILE));
for (File nestedFile : new File(DIRECTORY).listFiles())
{
Utils.add(nestedFile, zip,
new File(DIRECTORY).getAbsolutePath());
}
zip.close();
Can anyone direct me on what to change in the function, or what other function I should use? The directory has subdirectories, so I need a function that will scan them.
Thanks in advance!
Edit: I don't want something using the jar command, because I don't want the user to need to install the JDK. I want something using pure Java (libraries are OK, as long as I can include them in the program).
Edit 2: I'm making a Minecraft modder (like MCPatcher and ModLoader), but when I run java -jar minecraft.jar, it gives me this: Invalid or corrupt jarfile. The correct .jar doesn't give this (just a main class error, which is supposed to happen).
I think you maybe interested in java.util.jar. This link maybe useful for you..
http://www.theserverside.com/discussions/thread.tss?thread_id=32600

What variable should I put into this declaration to make it work?

So I have this code that pops up a file chooser and reads the file:
JFileChooser chooser = new JFileChooser();
File file = null;
int returnValue = chooser.showOpenDialog( null ) ;
if( returnValue == JFileChooser.APPROVE_OPTION ) {
file = chooser.getSelectedFile() ;
}
if(file != null) {
String filePath = file.getPath();
}
// String filePath (that's what i'm trying to input) = "Users/Bill/Desktop/hello.txt";
try {
ReadFile files = new ReadFile(***);
String[] lines = files.OpenFile();
the three asterisks (*) represent the class path of the file to be read. What should I put there if I want to read the file? Before this, I hard-coded the class-path and passed it in and it worked, but now, the class-path can be whatever the user chooses. Thanks for your help!
I don't know what your ReadFile thing is, but it looks like it takes a string representing the file path. In which case, you probably want to give it file.getPath().
Try using this instead of your code in try block:
FileReader fr = new FileReader(filePath);
FileWriter outputStream = new FileWriter("filename.txt");;
int c;
while ((c = fr.read()) != -1) {
outputStream.write(c);
}

Categories