Hi. I'm having the issue in an error of exception. I don't know what is wrong. But please help me fix this. I'm trying to store data from the file to ArrayList and display the data in the ArrayList. Here, I attached my code and data Code and data source.
the NoSuchElementException appears because you are calling input.nextToken(); while input doesn't have any token.It's due to the last empty line of your file listbook.txt. By deleting this line, the exception shouldn't appear.
A proper manner could be to ensure that you have sufficient tokens to retrieve all your fields for a given line.
public class TextFile
{
public static void main(String[] args)
{
try
{
FileReader read = new FileReader("C:\\Users\\ogawi\\Downloads\\listbook.txt");
BufferedReader bf = new BufferedReader(read);
Book B = new Book();
ArrayList<Book> bookList = new ArrayList<Book>();
String data = null;
StringTokenizer input = null;
while((data = bf.readLine()) != null)
{
input = new StringTokenizer(data,";");
//we ensure that we have enough tokens to retrieve all fields
if(input.countTokens() == 6)
{
String title = input.nextToken();
String author = input.nextToken();
String publisher = input.nextToken();
String genre = input.nextToken();
int year = Integer.parseInt(input.nextToken());
int page = Integer.parseInt(input.nextToken());
B = new Book(title, author, publisher, genre, year, page);
bookList.add(B);
}
}
//This part of code has been moved outside the while loop
//to avoid to print the total content of the array each time
//an element is added
int count=0;
for(int i=0;i<bookList.size();i++)
{
B = (Book)bookList.get(i);
System.out.println(B.toString());
System.out.println("=============================");
count++;
}
System.out.println("Number of Books: " + count);
bf.close();
}
catch(FileNotFoundException fnf)
{ System.out.println(fnf.getMessage());}
catch(EOFException eof)
{ System.out.println(eof.getMessage());}
catch(IOException io)
{ System.out.println(io.getMessage());}
finally
{ System.out.println("System end here..TQ!!");}
}
}
This issue is due to the extra line without book information:
You can see the line 31 and 32 in above figure.
To solve this issue you can add one if condition data.contains(";") . Text file has ; delimiter if we check the condition if given line has ; delimiter then it won't cause an issue.
while ((data = bf.readLine()) != null) {
if (data.contains(";")) {
input = new StringTokenizer(data, ";");
String title = input.nextToken();
String author = input.nextToken();
String publisher = input.nextToken();
String genre = input.nextToken();
int year = Integer.parseInt(input.nextToken());
int page = Integer.parseInt(input.nextToken());
B = new Book(title, author, publisher, genre, year, page);
bookList.add(B);
int count = 0;
for (int i = 0; i < bookList.size(); i++) {
B = (Book) bookList.get(i);
System.out.println(B.toString());
System.out.println("=============================");
count++;
}
System.out.println("Number of Books: " + count);
}
}
Here is the screenshot for successful execution of the code.
Related
there are 12 excel files that contain different products sales data, I try to sum up each month and entire year's sales using java but I can't add up sales for the whole year. Is there a way to do that? Thanks for your help.
public class Main {
public static void listOfSales(String fileName,String month){
List<PriceList> list = readsListFroExcel(fileName);
int sumOfInYearSale = 0;
int sumOfInOnlineSale =0;
int sumOfTotalMonthlySale = 0;
for (PriceList x : list){
sumOfInYearSale = sumOfInYearSale + x.getTotalPhysicalSale();
sumOfInOnlineSale = sumOfInYearSale + x.getTotalOnlineSale();
}
System.out.println(month +" Physical Sales : "+sumOfInYearSale);
System.out.println(month+ " Online Sales :" +sumOfInOnlineSale);
}
private static List<PriceList> readsListFroExcel(String fileName) {
List<PriceList> list = new ArrayList<>();
Path pathTofile = Paths.get(fileName);
try (BufferedReader br = Files.newBufferedReader(pathTofile)){
String headerLine = br.readLine();
String line = br.readLine();
while (line!=null){
String[] attributes = line.split(",");
PriceList listOfPrice = createList(attributes);
list.add(listOfPrice);
line = br.readLine();
}
} catch (IOException e) {
e.printStackTrace();
}
return list;
}
}
I have code that basically reads the file and stores it in an object.
I'm having issues when trying to turn one of the String in the array into int/double etc.
I'm using a linked list to save the object.
I have tried debugging but I can't find the issue. The program runs fine and dandy until it reaches the changing of variables part. No matter what I do, what I change, or how I try to fix it the same exception occurs. And then sometimes when it works it doesn't save it.
private void readFile() {
BufferedReader in;
String line = "";
try {
in = new BufferedReader(new FileReader("Doggie.txt"));//file name
try {
line = in.readLine();
} catch (Exception e) {
line = null;
}
while (line != null) {
String[] lineArray = line.split(",");
String name = lineArray[0];
String a = lineArray[1];
String phone = lineArray[2];
String location = lineArray[3];
String p = lineArray[4];
String id = lineArray[5];
String dogName = lineArray[6];
String breed = lineArray[7];
String w = lineArray[8];
String t = lineArray[9];
String vet = lineArray[10];
int age = Integer.parseInt(a);
double payment = Double.parseDouble(p);
double weight = Double.parseDouble(w);
int times = Integer.parseInt(t);
Dog doggo = new Dog(name, phone, location, payment, id, dogName, breed, age, weight, times, vet);
dogsList.addNode(doggo);
try {
line = in.readLine();
} catch (Exception e) {
line = null;
}
}
DogsLoaded = true;
} catch (Exception e) {
JOptionPane.showMessageDialog(this, "Error opening files, please check the information provided", "Error!", JOptionPane.ERROR_MESSAGE);
}
}
In the loop I do not see a repetition of readLine, a bug.
Evidently you need input validation and better error reporting.
Data errors may be hard to find, so line content and line number might be benificial.
I added some validation, but it can be done nicer.
I gave the cryptic Exception.getMessage (or getLocalizedMessage), as that at least will inform you to the cause.
String message = "";
int lineno = 0;
try (BufferedReader in = Files.newBufferedReader(
Paths.get("Doggie.txt"), Charset.defaultCharset())) {
String line;
while ((line = in.readLine())!= null) {
++lineno;
String[] lineArray = line.split("\\s*,\\s*");
Above I allowed whitespace around the comma. This trims the fields, which otherwise would not be able to be converted to a number.
Checking the number of fields is important; for instance the name could contain a comma.
if (lineArray.length != 11) {
throw new IllegalArgumentException("Wrong number of fields: " + line);
}
String name = lineArray[0];
String a = lineArray[1];
String phone = lineArray[2];
String location = lineArray[3];
String p = lineArray[4];
String id = lineArray[5];
String dogName = lineArray[6];
String breed = lineArray[7];
String w = lineArray[8];
String t = lineArray[9];
String vet = lineArray[10];
The following conversions seem to go wrong, give a NumberFormatException probably.
You certainly want to know the source.
message = "Age wrong: " + lineno + ". " +line;
int age = Integer.parseInt(a);
message = "Payment wrong: " + lineno + ". " +line;
double payment = Double.parseDouble(p);
message = "Weight wrong: " + lineno + ". " +line;
double weight = Double.parseDouble(w);
message = "Times wrong: " + lineno + ". " +line;
int times = Integer.parseInt(t);
message = "";
Dog doggo = new Dog(name, phone, location, payment,
id, dogName, breed, age, weight, times, vet);
dogsList.addNode(doggo);
}
DogsLoaded = true;
} catch (Exception e) {
if (message.isEmpty()) {
message = e.getMessage()
}
JOptionPane.showMessageDialog(this,
"Error opening files: " + message,
"Error", JOptionPane.ERROR_MESSAGE);
}
Additionally I used Files with Paths and Path, which is the swiss knife utility to go with.
The try-with-resources-syntax ensures that the file is closed also on exception or return.
Files has also functions for reading all lines, writing all lines, reading in a Stream of lines.
I have a csv file which is hashmapped, whenever the user enter the city name(key) it will display all the details of that city. I have to optimize the search result time, everytime the it is reading the file(instead of only once) and displaying the values.
The CSV files contains data like this :
city,city_ascii,lat,lng,country,iso2,iso3,admin_name,capital,population,id
Malishevë,Malisheve,42.4822,20.7458,Kosovo,XK,XKS,Malishevë,admin,,1901597212
Prizren,Prizren,42.2139,20.7397,Kosovo,XK,XKS,Prizren,admin,,1901360309
Zubin Potok,Zubin Potok,42.9144,20.6897,Kosovo,XK,XKS,Zubin
Potok,admin,,1901608808
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.io.IOException;
public class CSVFileReaders{
public static void main(String[] args) {
String filePath = "C:\\worldcities1.csv";
Scanner in = new Scanner(System.in);
System.out.println(" \n Enter the City name to be Searched : \n _> ");
long start = System.currentTimeMillis();
String searchTerm = in.nextLine();
readAndFindRecordFromCSV(filePath, searchTerm);
long end = System.currentTimeMillis();
System.out.println(" \n It took " + (end - start) + " Milli Seconds to search the result \n");
in.close();
}
public static void readAndFindRecordFromCSV( String filePath, String searchTerm) {
try{
HashMap<String,ArrayList<String>> cityMap = new HashMap<String,ArrayList<String>>();
Scanner x = new Scanner (new File(filePath),"UTF-8");
String city= "";
while(x.hasNextLine()) {
ArrayList<String> values = new ArrayList<String>();
String name = x.nextLine();
//break each line of the csv file to its elements
String[] line = name.split(",");
city = line[1];
for(int i=0;i<line.length;i++){
values.add(line[i]);
}
cityMap.put(city,values);
}
x.close();
//Search the city
if(cityMap.containsKey(searchTerm)) {
System.out.println("City name is : "+searchTerm+"\nCity details are accordingly in the order :"
+ "\n[city , city_ascii , lat , lng , country , iso2 , iso3 , admin_name , capital , population , id] \n"
+cityMap.get(searchTerm)+"");
}
else {
System.out.println("Enter the correct City name");
}
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}`
the time should be optimized and every time i search it is reading the entire file(which should happen)
Currently you mix the map initialization inside the search function.
You don't want that.
First, init the map, then use it in the search function.
To do that, extract a method for statements that instantiate and value the map and then refactor the readAndFindRecordFromCSV() method so that it accepts a Map as additional parameter :
public static void readAndFindRecordFromCSV( String filePath, String searchTerm, HashMap<String,ArrayList<String>> dataByCity) {...}
With refactoring IDE features, it should be simple enough : "extracting method" then "change signature".
Here is a code (not tested at runtime but tested at compile time) that splits the logical in separated tasks and also rely on instance methods :
public class CSVFileReaders {
private final String csvFile;
private HashMap<String, ArrayList<String>> cityMap;
private final Scanner in = new Scanner(System.in);
public static void main(String[] args) {
String filePath = "C:\\worldcities1.csv";
CSVFileReaders csvFileReaders = new CSVFileReaders(filePath);
csvFileReaders.createCitiesMap();
csvFileReaders.processUserFindRequest(); // First search
csvFileReaders.processUserFindRequest(); // Second search
}
public CSVFileReaders(String csvFile) {
this.csvFile = csvFile;
}
public void createCitiesMap() {
cityMap = new HashMap<>();
try (Scanner x = new Scanner(new File(csvFile), "UTF-8")) {
String city = "";
while (x.hasNextLine()) {
ArrayList<String> values = new ArrayList<String>();
String name = x.nextLine();
//break each line of the csv file to its elements
String[] line = name.split(",");
city = line[1];
for (int i = 0; i < line.length; i++) {
values.add(line[i]);
}
cityMap.put(city, values);
}
x.close();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public void processUserFindRequest() {
System.out.println(" \n Enter the City name to be Searched : \n _> ");
long start = System.currentTimeMillis();
String searchTerm = in.nextLine();
long end = System.currentTimeMillis();
System.out.println(" \n It took " + (end - start) + " Milli Seconds to search the result \n");
//Search the city
if (cityMap.containsKey(searchTerm)) {
System.out.println("City name is : " + searchTerm + "\nCity details are accordingly in the order :"
+ "\n[city , city_ascii , lat , lng , country , iso2 , iso3 , admin_name , capital , population , id] \n"
+ cityMap.get(searchTerm) + "");
} else {
System.out.println("Enter the correct City name");
}
}
}
The interesting part is here :
String filePath = "C:\\worldcities1.csv";
CSVFileReaders csvFileReaders = new CSVFileReaders(filePath);
csvFileReaders.createCitiesMap();
csvFileReaders.processUserFindRequest(); // First search
csvFileReaders.processUserFindRequest(); // Second search
The logical is clearer now.
Why do you create / load the CSV into a HashMap with every search ?
Just create the HashMap only once in the beginning, and then on every search just check whether it exists in the HashMap, eg move the read part into a separate method :
HashMap<String,ArrayList<String>> cityMap = new HashMap<String,ArrayList<String>>();
public static void readCSVIntoHashMap( String filePath) {
try{
Scanner x = new Scanner (new File(filePath),"UTF-8");
String city= "";
while(x.hasNextLine()) {
ArrayList<String> values = new ArrayList<String>();
String name = x.nextLine();
//break each line of the csv file to its elements
String[] line = name.split(",");
city = line[1];
for(int i=0;i<line.length;i++){
values.add(line[i]);
}
cityMap.put(city,values);
}
x.close();
...
}
Then have a separate method for searching :
public static void search(String searchTerm) {
if(cityMap.containsKey(searchTerm)) {
...
}
}
I currently have a database access class to pull the data from my list listed like so:
Pique:CBPique.png:41:22:55:91
Ronaldo:STRonaldo.png:89:85:92:91
...
The class is as follows:
class DatabaseAccess {
static DatabaseAccess dataAccessor;
static DatabaseAccess getInstance(String dbPath) {
if (dataAccessor == null) {
dataAccessor = new DatabaseAccess(dbPath);
}
return dataAccessor;
}
private DatabaseAccess(String dbPath) {
dbLocation = dbPath;
}
List<FootballPlayer> getCards() {
return this.getData();
}
private List<FootballPlayer> getData() {
List<FootballPlayer> theData = new ArrayList<FootballPlayer>();
// create a Scanner and grab the data . . .
Scanner scanner = null;
String dataPath = dbLocation + File.separator + "text" + File.separator + "players.db";
String imagePath = dbLocation + File.separator + "images";
try {
scanner = new Scanner(new File(dataPath));
} catch (FileNotFoundException fnf) {
System.out.println(fnf.getMessage());
System.exit(0);
}
// scan players.db file line-by-line
scanner.useDelimiter("\n");
while (scanner.hasNext()) {
String line = scanner.next().trim();
// trim used to trim for new line
String[] bits = line.split(":");
String t = bits[0]; // title
String imgFileName = bits[1]; // image file name
int pa = Integer.parseInt(bits[2]); // pace
int sh = Integer.parseInt(bits[3]); // shooting
int dr = Integer.parseInt(bits[4]); // dribbling
int ph = Integer.parseInt(bits[5]); // physical
// create the image
ImageIcon img = new ImageIcon(imagePath + File.separator + imgFileName);
// Create the business object
FootballPlayer player = new FootballPlayer(t, img, pa, sh, dr, ph);
// add it to the list ... simple as ...
theData.add(player);
}
scanner.close();
return theData;
}
What I want to do is pull the data from this list and display it / use it within another class, for example pulling the image file names for use, or even displaying all the data in a list.
Been struggling with it and any help would be really appreciated.
This could be a way your Scanner may look like: It reads the file and saves line per line into an ArrayList.
ArrayList<String> singleParts = new ArrayList<String>();
try {
int index = 0;
Scanner scanner = new Scanner( new File("files/"+filename+".txt") );
while ( scanner.hasNextLine() ) {
String actualLine = scanner.nextLine();
singleParts.add(actualLine);
}
scanner.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(Throwable te) {
te.printStackTrace();
}
After this, you could iterate through your ArrayList line per line, char per char. To make things easier, you could use your ':' as a seperator.
Example first line, Name:
String name = "";
boolean saved = false;
for(int line = 0; line < singleParts.size(); line++) {
for(int char = 0; char < singleParts.get(line).length(); char++) {
if(char<singleParts.get(line).indexOf(':') {
name += singleParts.get(line).charAt(char);
}
}
}
To get the rest, you have a lot of possibilities. For example, cut away the already used chars and reuse the loop similar to this one.
Does your Player object have attributes/properties that are unique, such as name or ID?
Since you already have the Player object containing all the properties you need, why not put it in a HashMap instead of Arraylist, considering if you have a key to identify the specific Player?
FootballPlayer player = new FootballPlayer(t, img, pa, sh, dr, ph);
yourKey = t // an identifier to you player, in this case i used t for example
playersMap.put(t,player);
This way you can easily retrieve your Player by using
Player myPlayer = playersMap.get(yourKey)
// you can then get the properties of the Player
myPlayer.getImg();
myPlayer.getPa();
Hope this helps
I have a problem with my code. I need to do several operations on a log file with this structure:
190.12.1.100 2011-03-02 12:12 test.html
190.12.1.100 2011-03-03 13:18 data.html
128.33.100.1 2011-03-03 15:25 test.html
128.33.100.1 2011-03-04 18:30 info.html
I need to get the number of visits per month, number of visits per page and number of unique visitors based on the IP. That is not the question, I managed to get all three operations working. The problem is, only the first choice runs correctly while the other choices just return values of 0 afterwards, as if the file is empty, so i am guessing i made a mistake with the I/O somewhere. Here's the code:
import java.io.*;
import java.util.*;
public class WebServerAnalyzer {
private Map<String, Integer> hm1;
private Map<String, Integer> hm2;
private int[] months;
private Scanner input;
public WebServerAnalyzer() throws IOException {
hm1 = new HashMap<String, Integer>();
hm2 = new HashMap<String, Integer>();
months = new int[12];
for (int i = 0; i < 12; i++) {
months[i] = 0;
}
File file = new File("webserver.log");
try {
input = new Scanner(file);
} catch (FileNotFoundException fne) {
input = null;
}
}
public String nextLine() {
String line = null;
if (input != null && input.hasNextLine()) {
line = input.nextLine();
}
return line;
}
public int getMonth(String line) {
StringTokenizer tok = new StringTokenizer(line);
if (tok.countTokens() == 4) {
String ip = tok.nextToken();
String date = tok.nextToken();
String hour = tok.nextToken();
String page = tok.nextToken();
StringTokenizer dtok = new StringTokenizer(date, "-");
if (dtok.countTokens() == 3) {
String year = dtok.nextToken();
String month = dtok.nextToken();
String day = dtok.nextToken();
int m = Integer.parseInt(month);
return m;
}
}
return -1;
}
public String getIP(String line) {
StringTokenizer tok = new StringTokenizer(line);
if (tok.countTokens() == 4) {
String ip = tok.nextToken();
String date = tok.nextToken();
String hour = tok.nextToken();
String page = tok.nextToken();
StringTokenizer dtok = new StringTokenizer(date, "-");
return ip;
}
return null;
}
public String getPage(String line) {
StringTokenizer tok = new StringTokenizer(line);
if (tok.countTokens() == 4) {
String ip = tok.nextToken();
String date = tok.nextToken();
String hour = tok.nextToken();
String page = tok.nextToken();
StringTokenizer dtok = new StringTokenizer(date, "-");
return page;
}
return null;
}
public void visitsPerMonth() {
String line = null;
do {
line = nextLine();
if (line != null) {
int m = getMonth(line);
if (m != -1) {
months[m - 1]++;
}
}
} while (line != null);
// Print the result
String[] monthName = {"JAN ", "FEB ", "MAR ",
"APR ", "MAY ", "JUN ", "JUL ", "AUG ", "SEP ",
"OCT ", "NOV ", "DEC "};
for (int i = 0; i < 12; i++) {
System.out.println(monthName[i] + months[i]);
}
}
public int count() throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream("webserver.log"));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
while ((readChars = is.read(c)) != -1) {
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n')
++count;
}
}
return count;
} finally {
is.close();
}
}
public void UniqueIP() throws IOException{
String line = null;
for (int x = 0; x <count(); x++){
line = nextLine();
if (line != null) {
if(hm1.containsKey(getIP(line)) == false) {
hm1.put(getIP(line), 1);
} else {
hm1.put(getIP(line), hm1.get(getIP(line)) +1 );
}
}
}
Set set = hm1.entrySet();
Iterator i = set.iterator();
System.out.println("\nNumber of unique visitors: " + hm1.size());
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
System.out.print(me.getKey() + " - ");
System.out.println(me.getValue() + " visits");
}
}
public void pageVisits() throws IOException{
String line = null;
for (int x = 0; x <count(); x++){
line = nextLine();
if (line != null) {
if(hm2.containsKey(getPage(line)) == false)
hm2.put(getPage(line), 1);
else
hm2.put(getPage(line), hm2.get(getPage(line)) +1 );
}
}
Set set = hm2.entrySet();
Iterator i = set.iterator();
System.out.println("\nNumber of pages visited: " + hm2.size());
while(i.hasNext()) {
Map.Entry me = (Map.Entry)i.next();
System.out.print(me.getKey() + " - ");
System.out.println(me.getValue() + " visits");
}
}
Any help figuring out the problem would be much appreciated as I am quite stuck.
I didn't read the code thoroughly yet, but I guess you're not setting the read position back to the beginning of the file when you start a new operation. Thus nextLine() would return null.
You should create a new Scanner for each operation and close it afterwards. AFAIK scanner doesn't provide a method to go back to the first byte.
Currently I could also think of 3 alternatives:
Use a BufferedReader and call reset() for each new operation. This should cause the reader to go back to byte 0 provided you didn't call mark() somewhere.
Read the file contents once and iterate over the lines in memory, i.e. put all lines into a List<String> and then start at each line.
Read the file once, parse each line and construct an apropriate data structure that contains the data you need. For example, you could use a TreeMap<Date, Map<Page, Map<IPAdress, List<Visit>>>>, i.e. you'd store the visits per ip address per page for each date. You could then select the appropriate submaps by date, page and ip address.
The reset method of BufferedReader that Thomas recommended would only work if the file size is smaller than the buffer size or if you called mark with a large enough read ahead limit.
I would recommend reading throught the file once and to update your maps and month array for each line. BTW, you don't need a Scanner just to read lines, BufferedReader has a readLine method itself.
BufferedReader br = ...;
String line;
while (null != (line = br.readLine())) {
String ip = getIP(line);
String page = getPage(line);
int month = getMonth(line);
// update hashmaps and arrays
}