Problem reading file in Java with lines of different length - java

I am trying to read a file but I am not able to get the correct output from it. Can someone tell me how should I change the code to make it work? isNum() function in the code is a method that checks whether the string is a number or not (because I need to put 5 and 10 in a separate variable).
Edit: I have changed the code a bit after listening to the suggestions and it looks better now but there still some problem. The code and output below has been updated.
int numEv = 0;
Scanner input = new Scanner(System.in);
ArrayList<String> evtList = new ArrayList<String>();
try {
input = new Scanner(Paths.get("src/idse/Events.txt"));
} catch (IOException e) {
System.out.println(e);
}
try {
while(input.hasNext()) {
String a = input.nextLine();
if (isNum(a)){
numEv = Integer.parseInt(a);
System.out.println(numEv);
}
else if(!a.isEmpty()&&!isNum(a)){
String[] parts = a.split(":");
for (String part : parts) {
evtList.add(part);
}
System.out.println(evtList);
}
if(isNum(a)){
evtList.clear();
}
}
The output that I am getting is:
5
[Logins, 2, Total time online, 1, Emails sent, 1, Orders processed, 1]
[Logins, 2, Total time online, 1, Emails sent, 1, Orders processed, 1, Pizza’s ordered online, 0.5]
10
[Logins, 7, Total time online, 5, Emails sent, 9, Orders processed, 15]
[Logins, 7, Total time online, 5, Emails sent, 9, Orders processed, 15, Pizza’s ordered online, 0.9, Logouts, 6]
The output that I want is:
5
[Logins, 2, Total time online, 1, Emails sent, 1, Orders processed, 1, Pizza’s ordered online, 0.5]
10
[Logins, 7, Total time online, 5, Emails sent, 9, Orders processed, 15, Pizza’s ordered online, 0.9, Logouts, 6]

There are 3 fixes you should do, follow the next steps:
Correct your file format.
change the format to:
5
Logins:2:Total time online:1:Emails sent:1:Orders processed:1:Pizza’s ordered online:0.5:
10
Logins:7:Total time online:5:Emails sent:9:Orders processed:15:Pizza’s ordered online:0.9:Logouts:6:
Thud will sperate the file by lines as you want.
Enter the System.out.println() method to the code blocks:
if (isNum(a)){
numEv = Integer.parseInt(a);
System.out.println(numEv);
}
else if(!a.isEmpty()&&!isNum(a)){
String[] parts = a.split(":");
for (String part : parts) {
evtList.add(part);
}
System.out.println(evtList);
}
This will fix you too long output, because its prints some unneccery stuff.
Clear the event list:
evtList.clear();
Add this line after every iteration in the while loop, to make list update only to the current line, and not full of nodes from previous events.

Based on what you specified in the comments (e.g. You cannot change the input file format), you would always have to check the next line of the file to see if the specific input code has ended. I would use this trick to read the next line without moving the pointer.
int numEv = 0;
Scanner input = new Scanner(System.in); // idk what you need this for
ArrayList<String> evtList = new ArrayList<String>();
try {
BufferedReader reader = new BufferedReader(new FileReader(Paths.get("src/idse/Events.txt")));
} catch (IOException e) {
System.out.println(e);
}
try {
while((a= reader.readLine()) != null) {
if (isNum(a)){ // Reading and printing the number
numEv = Integer.parseInt(a);
System.out.println(numEv);
} else if(!a.isEmpty()){ // Getting and storing the code
String[] parts = a.split(":");
for (String part : parts) {
evtList.add(part);
}
}
reader.mark(0);
a = reader.readLine();
if(a == null || isNum(a)) { // If the next line is a number or doesn't exist, we print and clear the code
System.out.println(evtList);
evtList.clear();
}
reader.reset();
}
I hope this works!

Related

Why does it not equals String and String From List<String>

I got a problem in String type that :
String from list-String is not the same as original String
Here are my sample codes
Map<String, List<String>> parameters_test=new HashMap<String, List<String>>();
parameters_test.put("0",new LinkedList<String>());parameters_test.get("0").add("WM188126M");
parameters_test.put("1",new LinkedList<String>());parameters_test.get("1").add("BXJ006");
parameters_test.put("2",new LinkedList<String>());parameters_test.get("2").add("‭1829690014");
parameters_test.put("3",new LinkedList<String>());parameters_test.get("3").add("16");
and then put the map to another method
if (getParamsMap() != null) {
for (String item : getParamsMap().keySet()) {
List<String> valueList = getParamsMap().get(item);
if (valueList == null || valueList.isEmpty()) {
continue;
}
if (item.equals("0")) {
woCode = valueList.get(0);
} else if (item.equals("1")) {
product = valueList.get(0);
} else if (item.equals("2")) {
purchaseOrder = valueList.get(0);
} else if (item.equals("3")) {
labelNumbers = valueList.get(0);
}
}
}
if(woCode.equals("WM188126M")){
System.out.println("01 true");
}else{
System.out.println("01 fail");
}
if(product.equals("BXJ006")){
System.out.println("02 true");
}else{
System.out.println("02 fail");
}
if(purchaseOrder.equals("1829690014")){
System.out.println("03 true");
}else{
System.out.println("03 fail");
}
if(labelNumbers.equals("16")){
System.out.println("04 true");
}else{
System.out.println("04 fail");
}
Why do I always get an result like this :
01 true
02 true
03 fail
04 fail
It's all okay for a long while.
errors appeared recently.
but I didn't change anything.
The code is used in Java 1.6 64bit - Eclipse
Text file Encoding : UTF-8
I have been tried for a long while.
Best regards for anyone who gives a hand.
The Text file contains some special characters and encoding is not properly set to UTF-8.
re-type below line.
parameters_test.put("2", new LinkedList());
parameters_test.get("2").add("1829690014");
Please take a look at code here - https://gist.github.com/ajinkya-mundankar/240d0e84dc37ee7ea1b222ed5e697db1 .
Please refer it here - Unable to create a file with foreign language characters.
There is a special character in "1829690014". Just re-type the input strings (specially 1) in parameters_test and it should work fine.
Your String "1829690014" in list is [‭, 1, 8, 2, 9, 6, 9, 0, 0, 1, 4] and not [‭1, 8, 2, 9, 6, 9, 0, 0, 1, 4] so when you are comparing these two, it is giving error.

Strange behavior of Nested while loop while iterating over a text file

I am new to java. I am trying to iterate over a couple of .txt files to compare one line of the file to every line of the second file. these are my two files: listread.txt and csvread.txt.
Here is the code I am using:
try {
BufferedReader csvReader = new BufferedReader(new FileReader("/data/csvread.txt"));
BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
String csvItem, listItem;
int count =0;
while((csvItem = csvReader.readLine()) != null){
System.out.println("before second loop:"+csvItem);
while ((listItem = listReader.readLine())!= null) {
System.out.println("list Item: "+listItem.toLowerCase().split("¬")[1]);
System.out.println("csv Item: "+csvItem.toLowerCase());
if(listItem.toLowerCase().split("¬")[1].contains(csvItem.toLowerCase())){
count++;
}
}
}
}catch(Exception e){
e.printStackTrace();
}
When I run this, only the first line in the csvread.txt (which is stored in the variable csvItem) is being compared to each of all the lines in listread.txt. Here is an example output:
before second loop:Record Category
list item: provisions
csv Item: record category
list item: request category
csv Item: record category
list item: elevator
csv Item: record category
list item: assessment
csv Item: record category
list item: associates
csv Item: record category
list item: score
csv Item: record category
list item: attachments
csv Item: record category
It only iterates over all the lines of list.txt file with the first line of the csvread.txt file. Doesn't move on to the second line in the csvread.txt, and the program ends throwing an error in the last:
java.lang.ArrayIndexOutOfBoundsException: 1
at test.main(test.java:52)
Which refers to the line System.out.println("list item: "+listItem.toLowerCase().split("¬")[1]);. This statement has nothing to do with the iterations I guess. Not sure why this error is thrown..
However, When I comment out the second for loop, it runs fine iterating over all the lines in the csvread.txt file. Here's is a sample output with just the first while loop and the second loop commented out:
before second loop:Record Category
before second loop:Type
before second loop:Name
before second loop:State
before second loop:Number
before second loop:ID (Self)
before second loop:Parent
before second loop:Title
This issue is occurring only when there is a nested loop. when there is a single loop, there is no problem at all. can somebody shed some light on this strange behavior? Also how do I overcome it?
EDIT:
I've added an if condition to check if the line contains the ¬ befor I split the line on that character:
if(listItem.contains("¬")){
System.out.println("list item: "+listItem.toLowerCase().split("¬")[1]);
System.out.println("csv Item: "+csvItem.toLowerCase());
if(listItem.toLowerCase().split("¬")[1].contains(csvItem.toLowerCase())){
count++;
}
}
No I don't get the exception anymore. However, The behavior is still strange. Here's the output after adding the if:
before second loop:Record Category
list item: provisions
csv Item: record category
list item: request category
csv Item: record category
list item: elevator
csv Item: record category
list item: assessment
csv Item: record category
list item: associates
csv Item: record category
list item: score
csv Item: record category
list item: attachments
csv Item: record category
before second loop:Type
before second loop:Name
before second loop:State
before second loop:Number
before second loop:ID (Self)
before second loop:Parent
before second loop:Title
The other elements are now being iterated over in the csvread.txt but the comparison with the lines in listread.txt is not hapeening except for the first element.
Any help would be appreciated. Thank you!
Expanded from my comment about listReader pointing to the end of the file after the first iteration. BufferedReader doesn't provide a mechanism to move the file pointer so a simple approach would be to move the creation of listReader to inside the outer loop:
try {
BufferedReader csvReader = new BufferedReader(new FileReader("/data/csvread.txt"));
// BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
String csvItem, listItem;
int count =0;
while((csvItem = csvReader.readLine()) != null){
System.out.println("before second loop:"+csvItem);
BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
while ((listItem = listReader.readLine())!= null) {
System.out.println("list Item: "+listItem.toLowerCase().split("¬")[1]);
System.out.println("csv Item: "+csvItem.toLowerCase());
if(listItem.toLowerCase().split("¬")[1].contains(csvItem.toLowerCase())){
count++;
}
}
}
}catch(Exception e){
e.printStackTrace();
}
so each iteration will have a new listReader which starts at the top of the file.
But that might be too much I/O. If the size of list.txt isn't too big, then perhaps read it once, parse it, and store in a Set<String> for later comparison:
try (BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
BufferedReader csvReader = new BufferedReader(new FileReader("/data/csvread.txt"))) {
String listItem = null;
Set<String> listItems = new HashSet<>();
while ((listItem = listReader.readLine()) != null) {
listItems.add(listItem.toLowerCase().split("¬")[1]);
}
String csvItem;
int count = 0;
while ((csvItem = csvReader.readLine()) != null) {
System.out.println("before second loop:" + csvItem);
for (String item : listItems) {
System.out.println("list Item: " + item);
System.out.println("csv Item: " + csvItem.toLowerCase());
if (item.contains(csvItem.toLowerCase())) {
count++;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Also moved to try-with-resources to make sure csvReader and listReader are properly closed.
Your access to
listItem.toLowerCase().split("¬")[1]
is critical, since you always expect that all lines have your "¬". If this is not the case your split will not return a array and you access the returend array at position [1] which fails and returns the IndexOutOfBounds....
When you use nested loops, the inner loops get executed fully. Then the execution control comes out of the inner loop and starts the next iteration of the outer loop. Hence, if you want to compare the content of the two files line-by-line, you should not have any inner loop. Below is the sample code that you may try to do in this case. Though, I have not tested it.
try {
BufferedReader csvReader = new BufferedReader(new FileReader("/data/csvread.txt"));
BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
String csvItem, listItem;
int count =0;
while((csvItem = csvReader.readLine()) != null){
System.out.println("before second loop:"+csvItem);
listItem = listReader.readLine();
if (listItem != null){
if(listItem.toLowerCase().split("¬")[1].contains(csvItem.toLowerCase())){
count++;
}
}else{
//The listItem has no more lines to compare, so ending the process.
break;
}
}
}catch(Exception e){
e.printStackTrace();
}
I hope this helps.
Note: The above answer was given with a belief that the requirement was to compare the contents of two files line-by-line.

Modifying complex csv files in java

I wanted to write a program which can print, and modify the irregular csv files. The format is as follows:
1.date
2.organization name
3. student name, id number, residence
student name, id number, residence
student name, id number, residence
student name, id number, residence
student name, id number, residence
1.another date
2.another organization name
3. student name, id number, residence
student name, id number, residence
student name, id number, residence
..........
For instance, the data may be given as follows:
1. 10/09/2016
2. cycling club
3. sam, 1000, oklahoma
henry, 1001, california
bill, 1002, NY
1. 11/15/2016
2. swimming club
3. jane, 9001, georgia
elizabeth, 9002, lousiana
I am a beginner and I have not found any viable resource online which deals with this type of problem. My main concern is, how do we iterate through the loop and identify the date and name of the club, and feed them into a array?
Please advise.
I think this should be helpful for you. Basically there should be some pattern in your messed up csv. Below is my code to arrange your csv
public static void main(String[] args) throws FileNotFoundException, UnsupportedEncodingException {
PrintWriter writer = new PrintWriter("file.txt", "UTF-8");
try{
//Create object of FileReader
FileReader inputFile = new FileReader("csv.txt");
//Instantiate the BufferedReader Class
BufferedReader bufferReader = new BufferedReader(inputFile);
//Variable to hold the one line data
String line;
String date="";String org ="";String student ="";
// Read file line by line and print on the console
while ((line = bufferReader.readLine()) != null) {
if(line.contains("1.")){
if(date!="" || org!=""){
writer.println(date+","+org+","+student);
student ="";
}
date = line.substring(2);
}else if(line.contains("2.")){
org = line.substring(2);
}else{
line = "("+line+")";
student += line+",";
}
System.out.println(line);
}
writer.println(date+","+org+","+student);
//Close the buffer reader
bufferReader.close();
}catch(Exception e){
System.out.println("Error while reading file line by line:" + e.getMessage());
}
writer.close();
}
This is the output you will get for this
10/09/2016, cycling club,(3. sam, 1000, oklahoma),( henry, 1001, california),( bill, 1002, NY),
11/15/2016, swimming club,(3. jane, 9001, georgia),( elizabeth, 9002, lousiana),
I am reading the file from csv.txt. while loop goes through each line of text file.all the fields are stored in a variable. When next date comes I write all of them into output file. Last line of the csv is written to file after the while loop terminates.
Try uniVocity-parsers to handle this. For parsing this sort of format, you'll find a few examples here. For writing, look here and here.
Adapting from the examples I've given, you could write:
final ObjectRowListProcessor dateProcessor = new ObjectRowListProcessor();
final ObjectRowListProcessor clubProcessor = new ObjectRowListProcessor();
final ObjectRowListProcessor memberProcessor = new ObjectRowListProcessor();
InputValueSwitch switch = new InputValueSwitch(0){
public void rowProcessorSwitched(RowProcessor from, RowProcessor to) {
//your custom logic here
if (to == dateProcessor) {
//processing dates.
}
if (to == clubProcessor) {
//processing clubs.
}
if (to == memberProcessor){
//processing members
}
};
switch.addSwitchForValue("1.", dateProcessor, 1); //getting values of column 1 and sending them to `dateProcessor`
switch.addSwitchForValue("2.", clubProcessor, 1); //getting values of column 1 and sending them to `clubProcessor`
switch.addSwitchForValue("3.", memberProcessor, 1, 2, 3); //getting values of columns 1, 2, and 3 and sending them to `memberProcessor`
setDefaultSwitch(memberProcessor, 1, 2, 3); //Rows with blank value at column 0 are members. Also get columns 1, 2, and 3 and send them to `memberProcessor`
CsvParserSettings settings = new CsvParserSettings(); //many options here, check the tutorial and examples
// configure the parser to use the switch
settings.setRowProcessor(switch);
//creates a parser
CsvParser parser = new CsvParser(settings);
//parse everying. Rows will be sent to the RowProcessor of each switch, depending on the value at column 0.
parser.parse(new File("/path/to/file.csv"));
Disclaimer: I'm the author of this library, it's open-source and free (Apache 2.0 license)

Finding closest number from two arraylists

Recently one of my data servers went down and a large number of video files are damaged (over 15,000 files, or more than 60TB). I wrote a script to check all files and put results in a very big log.txt file (almost 8GB).
I wrote code to find all lines starting with "Input #0" and lines which contain "damaged", then added their line numbers to ArrayList's. Next, I need to compare those two ArrayLists and find the closest line number in list2 to the number in list1 so I can get back file names from the log file.
For example:
if list1 contains numbers {1, 5, 45, 55, 100, 2000... etc}
and list2 contains numbers {50, 51, 53, 2010... etc} the result should be {45, 2000... etc}
This is my current code:
import java.io.*;
import java.util.*;
public class Log {
public static void main(String [] args) throws IOException{
ArrayList<Integer> list1 = new ArrayList<Integer>();
ArrayList<Integer> list2 = new ArrayList<Integer>();
File file = new File("C:\\log.txt");
try {
Scanner scanner = new Scanner(file);
Scanner scanner2 = new Scanner(file);
int lineNum = 0;
int lineNum2 = 0;
while (scanner.hasNextLine()){
String line = scanner.nextLine();
String line2 = scanner.nextLine();
lineNum++;
lineNum2++;
if((line.startsWith("Input #0"))) {
list1.add(lineNum);
}
if((line2.contains("damaged"))) {
list2.add(lineNum2);
}
}
This is what I'm getting from the code above:
list1 [5, 262, 304, 488, 523, 1189, 1796, 2503, 2722, 4052, 4201, 4230, 4298, 4312, 4559, 4887, 4903, 5067....]
list2 [1838, 1841, 1842, 1844, 1851, 1861, 1865, 1866, 1868, 1875, 1878, 1879, 1880, 1881, 1886, 1887, 1891....]
Some log data:
Input #0, mpegvideo, from '/cinegy/cinegy/VIDEO/BSF/BLOK 3 - 14. NOVHighb668ca7d201411141051110636.m2v':
.
.
.
.
.
.
Data with damage:
Input #0, mpegvideo, from '/cinegy/cinegy/VIDEO/BSF/BLOK 3 - 14. NOVHighb668ca7d201411141051110636.m2v':
.
.
.
.
.
[error 0x090010] file damaged at 16 09
[error 0x090010] file damaged at 19 15
The log for each individual file does not contain any pattern except for the first 5-6 lines or so. Both damaged and non-damaged files contain info written in 20 to 100+ lines.
So, from these numbers the first result should be number 1796.
I'm pretty much a novice in Java and I need help.
Here's a small code that will do the work, but I don't know if you want redundant values in the result, so I saved them in a list and in a set, choose the one you prefer:
public static void main(String[] args) {
int[] list1 = {5, 262, 304, 488, 523, 1189, 1796, 2503, 2722, 4052, 4201, 4230, 4298, 4312, 4559};
int[] list2 = {1838, 1841, 1842, 1844, 1851, 1861, 1865, 1866, 1868, 1875, 1878, 1879, 1880, 1881};
ArrayList<Integer> resultList = new ArrayList<Integer>();
Set<Integer> resultSet = new HashSet<Integer>();
int j = 0;
for(int i = 0; i < list2.length; i++){
for(; j < list1.length; j++){
if(list1[j] > list2[i])
break;
}
resultList.add(list1[j-1]);
resultSet.add(list1[j-1]);
}
System.out.println(resultList);
System.out.println(resultSet);
}
Output:
[1796, 1796, 1796, 1796, 1796, 1796, 1796, 1796, 1796, 1796, 1796, 1796, 1796, 1796]
[1796]
You defined two scanners (seems unnecessary) but you are only using one of them and calling nextline() twice on it. It looks like that is not intended and as a consequence the results you are getting are erroneous. It would be very helpful if you could post a sample excerpt from your logfile (you can filter the sensitive data) so that we can determine what the best approach is for this.
I think you should scrap your current approach because it does not seem like an efficient way to solve your problem of needing to find filenames of damaged files.
Depending on how your data looks, you can use regular expressions and possibly even extract the filenames directly into a Set.
Edit: Added some rough code that should do the job for you if you are indeed correct that each file starts with "Input #0". As long as there is a pattern in the log data for each file, then you should always be able to extract the data you need directly instead of going through the mess of matching entries from two separate arraylists.
public static void main(String [] args) throws FileNotFoundException{
Set<String> damagedFiles = new LinkedHashSet<String>();
File file = new File("C:\\log.txt");
Scanner scanner = new Scanner(file);
String filename = null;
try {
int lineNum = 0;
while (scanner.hasNextLine()){
String line = scanner.nextLine();
if(line.startsWith("Input #0")){
/*if desired, can use a regex lookahead to get only the path and filename
instead of the entire Input #0 line */
filename = line;
}
if(line.contains("damaged")){
if (filename != null){
damagedFiles.add(filename);
}
}
}
} finally {
scanner.close();
for (String s : damagedFiles){
System.out.println(s);
}
}
}
This is the result I got when running this code on a sample log file where I named the damaged files dmg#.m2v
Input #0, mpegvideo, from '/cinegy/cinegy/VIDEO/BSF/BLOK 3 - 14. dmg1.m2v':
Input #0, mpegvideo, from '/cinegy/cinegy/VIDEO/BSF/BLOK 3 - 14. dmg2.m2v':
Input #0, mpegvideo, from '/cinegy/cinegy/VIDEO/BSF/BLOK 3 - 14. dmg3.m2v':
Input #0, mpegvideo, from '/cinegy/cinegy/VIDEO/BSF/BLOK 3 - 14. dmg4.m2v':

Reading txt file, then re organizing it to an array

So basically what I need to do is:
Read a text file like this:
[Student ID], [Student Name], Asg 1, 10, Asg 2, 10, Midterm, 40, Final, 40
01234567, Timture Choi, 99.5, 97, 100.0, 99.0
02345678, Elaine Tam, 89.5, 88.5, 99.0, 100
and present it like this (with calculations of rank and average):
ID Name Asg 1 Asg 2 Midterm Final Overall Rank
01234567 Timture Choi 99.5 97.0 100.0 99.0 99.3 1
02345678
Elaine Tam 89.5 88.5 99.0 100.0 97.4 2
Average: 94.5 92.75 99.5 99.5 98.3
Using printf() function
now this is what I have done so far:
import java.io.*;
import java.util.Scanner;
class AssignmentGrades {
public static void main(String args[]) throws Exception {
Scanner filename = new Scanner(System.in);
String fn = filename.nextLine(); //scannig the file name
System.out.println("Enter your name of file : ");
FileReader fr = new FileReader(fn+".txt");
BufferedReader br = new BufferedReader (fr);
String list;
while((list = br.readLine()) !=null) {
System.out.println(list);
}
fr.close();
}
}
So I can ask the user for the name of the file, then read it and print.
Now.. I'm stuck. I think I need to probably put it in to array and split?
String firstrow = br.readLine();
String[] firstrow = firstrow.split(", ");
something like that?.. ugh ive been stuck here for more than an hour
I really need help!! I appreciate your attention!! ( I started to learn java this week)
There are two ways for splitting the input line just read from the file
Using String object's split() method which would return an array. Read more about the split here.
StringTokenizer Class - This class can be used to divide the input string into separate tokens based on a set of delimeter. Here is a good tutorial to get started.
You should be able to get more examples using google :)
In case you want to parse integers from String. Check this.
Here I store the columns as an array of Strings and I store the record set as an ArrayList of String arrays. In the while loop if the column set is not initialized yet (first iteration) I initialize it with the split. Otherwise I add the split to the ArrayList. Import java.util.ArrayList.
String[] columns = null;
ArrayList<String[]> values = new ArrayList<String[]>();
String list;
while((list = br.readLine()) !=null) {
if (columns != null) {
columns = list.split(", ");
} else {
values.add(list.split(", "));
}
}
fr.close();

Categories