Iteration is not writing on the right Array Index - java

I found a code that iterates trough a folder and return the fileNames.
I created a String[] Array with 8000 positions, since I have around 7500 files and getting more.
If I use the code that I found with system.out.println it returns every single file name, but if I use my code to write the position into the Array index, I only get 1 position and rest full of null.
Unlucky I cannot figure out the problem.
import java.io.*;
public class Tester {
public static void main(String[] args) {
File folder = new File("mypath\\myfilefolder");
File[] listOfFiles = folder.listFiles();
String[] fileNames = new String[8000];
for (int i = 0; i < listOfFiles.length; i++) {
int c = 0;
if (listOfFiles[i].isFile()) {
fileNames[c++] = listOfFiles[i].getName();
// Seems not to be doing anything like supposed
// System.out.println(listOfFiles[i].getName());
// Prints every filename on a new line
} else if (listOfFiles[i].isDirectory()) {
System.out.println("Directory " + listOfFiles[i].getName());
}
}
for (String element: fileNames) {
System.out.println(element);
}
}
}
I expect to be able to iterate trough fileNames and get the filesNames so I can work with it.
But actually only the first positions get changed, all the others are still null.

The value changed at 'c++' is never used. Every time before your code execute to c++ the variable of c being reset to 0.

And this would be the same algorithm with the use of the stream API (Java 1.8 and above):
String[] fileNames = Arrays.stream(folder.listFiles()) // stream all the files in the directory
.filter(file -> !file.isDirectory()) // filter any directory files in there
.map(File::getName) // map an item to its name
.toArray(String[]::new); // collect as a String array

Related

Item Counter program that will display the number of names that are stored on a file

Can someone help me with this java program that I've been puzzled on for a while. I'll post the question alone with the code but its a Files in java that I've recently started and I'm having trouble adding a loop counter variable to hold and display the number of names stored in the file.
For better understanding here the question I'm working on:
Assume that a file containing a series of names (as strings) is named names.dat and exists on the computers disk. Design a program that displays the number of names that are stored in the file. (Hint: Open the file and read every string stored in it. Each time you read a string, increment a counter variable. When you've read all the strings from the file, the counter variable will contain the number of names stored in the file.)
I don't know how much trouble it will be to aid assist being that this question is file related in java.
Here is my java code so far for better understanding:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class Item_Counter {
public static void main(String[] args) throws FileNotFoundException {
int numLines = 0;
int sum = 0;
File namesFile = new File("C:\\Users\\Tyrese\\JAVA 2\\Chapter 10\\names.dat");
Scanner bot = new Scanner(namesFile);
System.out.println(bot.nextLine());
while (bot.hasNext()) {
numLines = numLines + 1;
numLines = bot.nextInt();
}
System.out.println("The file has" + numLines);
}
}
Feel free to replace my file path and name that is a simple notepad document containing a few names, with your own if necessary.
You have some errors in your code, the way Scanner works for file reading is simple, you open the file the way you did like this : Scanner bot = new Scanner(namesFile); but in order to go to the next line you need to do bot.nextLine() so if you do it before you are in the while or do it twice it will go on 2 lines, so you just need to do like this :
public static void main(String[] args) throws FileNotFoundException {
int numLines = 0; // initialise variable
File namesFile = new File("C:\\Users\\Tyrese\\JAVA 2\\Chapter 10\\names.dat"); // fetch the file
Scanner bot = new Scanner(namesFile); // open the file
while (bot.hasNextLine()) { // while the file has a next line -> go on
numLines++; // add +1 to the variable numLines
numLines = bot.nextLine(); // go to the next line (if it has one)
}
System.out.println("The file has" + numLines); // print the result
}
You can ask me if you have any further questions
This is the problematic part of your code:
System.out.println(bot.nextLine());
while (bot.hasNext()) {
numLines = numLines + 1;
numLines = bot.nextInt();
}
Your println types a line being read and therefore that line will be ignored later. You need hasNextLine in the while loop and nextLine instead of nextInt.
Fix:
while (bot.hasNextLine()) {
numLines = numLines + 1;
bot.nextLine();
}
You can compute the sum of integers inside a file similarly. However, the actual solution depends on the structure of the file. If the file contains the integers as lines, without white characters beside the newline, such as
1
5
4
7
2
7
then the solution is:
int sum = 0;
while (bot.hasNextLine()) {
sum += 1;
bot.nextLine();
}
however, if the file is a list of numbers, separated by space, such as
3 7 8 2 8 3 6 9
then you read the content of the file via
String content = bot.nextLine();
String[] splited = str.split("\\s+");
int sum = 0;
for (int index = 0; index < splited.length; index++) {
sum += Integer.parseInt(splited[index])
}

Why is sequential file naming not working?

I am trying to solve this question.
Problem Statement
You are developing a File Manager but encountered a problem. You realised that two files cannot have the same names and if a conflict arises, the file which came later has to be appended with a number N such that N is the smallest positive number that is not used with that particular file name. The number is append in the form of file_name(N). Write a code to solve your problem. You will be given an array of strings of file names. You need to assume that if a file name appears earlier in an array, it was created first.
NOTE: file_name and file_name(2) are two different file names i.e if a file name already has a number appended to it, its a different file name.
Input
The first line contains N, the number of strings.
The next line contains N space-separated strings (file names).
Output
Print the names of files, after making the necessary changes separated by space.
Constraints
1 ≤ N ≤ 50
1 ≤ file_name.length ≤ 25
filename has no white space characters
Sample Input
7
file sample sample file file file(1) file(1)
Sample Output
file sample sample(1) file(1) file(2) file(1)(1) file(1)(2)
Below is my code. When I tested it with my own file names, it renames well but when I submit it, the tests fail. I would like to know what's wrong with my code and why its not working.
import java.util.Scanner;
public class Dcoder {
public static void main (String[] args) {
Scanner scanner = new Scanner (System.in);
// Read number of file names and create
// an array to hold them
String[] fileNames = new String[scanner.nextInt ()];
// Fill the array with the supplied names
// from System.in
for (int i = 0; i < fileNames.length; i++)
fileNames [i] = scanner.next ();
// Modify the file names
for (String fileName : fileNames) {
int count = 0;
for (int i = 0; i < fileNames.length; i++)
if (fileName.equals (fileNames [i])) {
fileNames [i] = fileNames [i] + (count == 0 ? "" : "(" + count + ")");
count++;
}
}
// Print out the modified list of file names
for (String fileName : fileNames)
System.out.print (" " + fileName);
}
}
If all tests fail, then it is likely because your output has a space before the first name.
The output should be the file name, space-separated, not space-prefixed.
If you try input "file file(1) file file", your code outputs
file file(1) file(1)(1) file(2)
but correct output is
file file(1) file(2) file(3)
For better performance, you should use a Set.
static void printUnique(String... fileNames) {
Set<String> used = new HashSet<>();
for (int i = 0; i < fileNames.length; i++) {
String newName = fileNames[i];
for (int j = 1; ! used.add(newName); j++)
newName = fileNames[i] + "(" + j + ")";
if (i != 0)
System.out.print(" ");
System.out.print(newName);
}
System.out.println();
}
Test
printUnique("file", "sample", "sample", "file", "file", "file(1)", "file(1)");
printUnique("file", "file(1)", "file", "file");
Output
file sample sample(1) file(1) file(2) file(1)(1) file(1)(2)
file file(1) file(2) file(3)
Your solution is a procedural approach to the Problem.
Procedural approaches are not bad on their own.
But Java is an Object Oriented programming language and if you want to become a good Java programmer you should start looking for more OO-like solutions.
But OOP doesn't mean to "split up" code into random classes.
The ultimate goal of OOP is to reduce code duplication, improve readability and support reuse as well as extending the code.
Doing OOP means that you follow certain principles which are (among others):
information hiding / encapsulation
single responsibility
separation of concerns
KISS (Keep it simple (and) stupid.)
DRY (Don't repeat yourself.)
"Tell! Don't ask."
Law of demeter ("Don't talk to strangers!")
So what could a more OO-like approach look like?
The underlaying question of that problem is: "How often does a specific file name appear in the input?" We want to find an association between Strings (file Names) and integer values (number of occurrence). This could be represented as a Map<String,Integer>. The whole logic is as simple as looking in the output if the current fileName already exists there and if so add the counter suffix. This means we need another Collection to hold the output.
My Solution would look like this:
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class FileNameCounter {
public List<String> renameDoubledFiles(List<String> input) {
Map<String, Integer> occurrencesOfNames = new HashMap<>();
LinkedList<String> output = new LinkedList<>();
for (String fileName : input) {
if (output.contains(fileName)) {
Integer counter = updateCountFor(fileName, occurrencesOfNames);
String suffixedName = appendCounterSuffix(fileName, counter);
output.add(suffixedName);
} else {
output.add(fileName);
}
}
return output;
}
private Integer updateCountFor(String fileName, Map<String, Integer> occurrencesOfNames) {
Integer counter = occurrencesOfNames.getOrDefault(fileName, Integer.valueOf(0));
occurrencesOfNames.put(fileName, ++counter);
return counter;
}
private String appendCounterSuffix(String fileName, Integer counter) {
return String.format("%s(%d)", fileName, counter);
}
}
and here is the JUnit test to prove that it works:
import static org.junit.jupiter.api.Assertions.*;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
class FileNameCounterTest {
#Test
void test() {
List<String> input = Arrays.asList("file sample sample file file file(1) file(1)".split(" "));
List<String> renamedDoubledFiles = new FileNameCounter().renameDoubledFiles(input);
String output = renamedDoubledFiles.stream().collect(Collectors.joining(" "));
assertEquals("file sample sample(1) file(1) file(2) file(1)(1) file(1)(2)", output);
}
}

Print Total Number of Different Words (case sensitive) from a file

**Edit after reviewing Tormod's answer and implementing his advice.
As the title states I'm attempting to print the total number of different words after receiving a file name from command line input. I receive the following message after attempting to compile the program:
Note: Project.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Here is my code. Any help is greatly appreciated:
import java.lang.*;
import java.util.*;
import java.io.*;
public class Project {
public static void main(String[] args) throws IOException {
File file = new File(args[0]);
Scanner s = new Scanner(file);
HashSet lib = new HashSet<>();
try (Scanner sc = new Scanner(new FileInputStream(file))) {
int count = 0;
while(sc.hasNext()) {
sc.next();
count++;
}
System.out.println("The total number of word in the file is: " + count);
}
while (s.hasNext()) {
String data = s.nextLine();
String[] pieces = data.split("\\s+");
for (int count = 0; count < pieces.length; count++)
{
if(!lib.contains(pieces[count])) {
lib.add(pieces[count]);
}
}
}
System.out.print(lib.size());
}
}
I would implement it using a HashSet Add all the words, and read out the size. If you want to make it case insensitive just manipulate all the words to uppercase or something like that. this uses some memory but...
one problem you got with the algorithm is that you do only have one "words". it only holds the words at the same line. so you only count same words at the same line.
HashSet stores strings by their hash value, and thus stores one word only one time.
construction: HashSet lib = new HashSet<>();
inside the loop: if(!lib.contains(word)){lib.add(word);}
check the word count: lib.size()
for(String s : words) {
if(s.equals(word))
count++;
}
You are comparing the words to an empty String, since it's a word it's always gonna be false.
Like Tormod said, the best would be to store the words in a HashSet, as it won't keep duplicates. Then just read out its size.

Search for a word in a file results in java.util.NoSuchElementException

This is my code. It produces the error java.util.NoSuchElementException.
It is meant to search a file, example.txt for a word (eg. and) and find all instances of the the word and print the word either side of it also (eg. cheese and ham, tom and jerry) in ONE JOptionPane. Code:
import java.io.File;
import java.util.Arrays;
import java.util.Scanner;
import javax.swing.JOptionPane;
public class openFileSearchWord {
public static void main(String Args[])
{
int i=0,j=0;
String searchWord = JOptionPane.showInputDialog("What Word Do You Want To Search For?");
File file = new File("example.txt");
try
{
Scanner fileScanner = new Scanner(file);
String[] array = new String[5];
String[] input = new String[1000];
while (fileScanner.hasNextLine())
{
for(i=0;i<1000;i++)
{
input[i] = fileScanner.next();
if(input[i].equalsIgnoreCase(searchWord))
{
array[j] = input[i-1] + input[i] + input[i+1];
j++;
}
}
}
Arrays.toString(array);
JOptionPane.showMessageDialog(null, array);
fileScanner.close();
}
catch(Exception e)
{
System.out.println(e);
}
}
}
It looks like you're assuming each line will have 1000 words.
while (fileScanner.hasNextLine())
{
for(i=0;i<1000;i++) <-------- Hardcoded limit?
{
....
}
}
You can try putting another catch loop, or check hasNext() during that for loop.
while (fileScanner.hasNextLine())
{
for(i=0;i<1000 && fileScanner.hasNext();i++)
{
....
}
}
There are also many issues with your code, like if input[i-1] hits the -1 index, or if your 'array' array hits the limit.
I took the liberty to have some fun.
Scanner fileScanner = new Scanner(file);
List<String> array = new ArrayList<String>();
String previous, current, next;
while (fileScanner.hasNext())
{
next = fileScanner.next()); // Get the next word
if(current.equalsIgnoreCase(searchWord))
{
array.add( previous + current + next );
}
// Shift stuff
previous = current;
current = next;
next = "";
}
fileScanner.close();
// Edge case check - if the last word was the keyword
if(current.equalsIgnoreCase(searchWord))
{
array.add( previous + current );
}
// Do whatever with array
....
I see a few error here ...
You are creating two arrays one with 5 and one with 1000 elements.
In your code you are referencing elements directly by index ... but this index might not be present.
input[i-1] ... what if i = 0? ...index is -1
array[j] ... what if j > 4 ... index 5 doesn't exist
I suggest using List of elements instead of fixed arrays.
List<String> array = new ArrayList<>();
You are assuming that the input is something but don't do anything to check what it actually is.
Just as Drejc told you, The first iteration would fail because of the negative index and the program will fail as well if it finds more than 5 matches of the desired word.
Also I want to add another one. You should think that when you do this line:
array[j] = input[i-1] + input[i] + input[i+1];
You have not assigned input[i+1] yet. In that iteration you've just assigned input[i], but no the next one.
You should process the concatenation of the three elements (previousWord + match + nextWord) when reaching nextWord.
Another solution, but inefficient, would be copying all the words to an Array at beginning and using your actual code without modifying. This would work, but you would go twice through all the words.

Java - Indenting the line each time a for loop runs

I am writing a method to list all the files in a directory but I can not figure out how to make each subdirectory have one more tab than the last one.
Here is my code:
private static void recurseDirectoryHelper(File rootDirectory){
File[] list = rootDirectory.listFiles();
if (rootDirectory.isDirectory()){
for (int f = 0; f < list.length; f++){
if (list[f].isFile()){
System.out.println("\t" + list[f].getName());
countFiles++;
}
}
for (int d = 0; d < list.length; d++){
if (list[d].isDirectory()){
System.out.println("Subdir: " + list[d].getName());
recurseDirectoryHelper(list[d]);
}
}
}
//System.out.println("Total Files: " + countFiles + "\t" + "Total Directories: " + countDirs);
}
Add another parameter to your function called count, like so:
private static void recurseDirectoryHelper(File rootDirectory, int count){
Each time you recursively call your function, pass count + 1, like so:
recurseDirectoryHelper(list[d], count+1);
Then when you do your System.out.println, you know exactly how many tabs to do.
I would simply add a tabSpace string parameter in the recursion method to avoid unnecessary looping inside as:
private static void recurseDirectoryHelper(File rootDirectory, String tabSpace){
In first call, I would pass tabSpace as empty String ("") or single tab("\t") as desired and then with-in the recursive calls for sub-directory, simply pass tabSpace+"\t" as
recurseDirectoryHelper(list[d], ""); //<-- First call from outside
recurseDirectoryHelper(list[d], tabSpace+"\t"); //<-- recursive calls
While printing the list, simply use the tabSpace for indentation:
System.out.println(tabSpace + list[f].getName());
Have a second parameter to store the level at which your method has recursed. When it's first called, it will be zero. When you call the method recursively, pass in level + 1.
When printing, use level as the number of tabs to print.
private static void recurseDirectoryHelper(File rootDirectory, String indent){
if (rootDirectory.isDirectory()){
File[] list = rootDirectory.listFiles();
for(File file : list) {
if (file.isFile()){
System.out.print(indent);
System.out.println(file.getName());
}
}
for(File file : list) {
if (file.isDirectory()){
System.out.print("Subdir: ");
System.out.println(file.getName());
recurseDirectoryHelper(file, indent + indent);
}
}
}
}

Categories

Resources