Reading data from Excel using Java - java

I have 2 columns in an excel sheet, A and B, and I need to divide column A (randomly) into 2 and calculate the average of the first and second halves of column B separately. Then I need to divide column A again but each time moving with one cell downwards and calculate the averages etc. Can this be done using Java only? Since I am finding you have to use software like Apache and I have never used them.
Thanks

Yes, you can save the Excel data as a text file and use classes like java.io.File, java.util.Scanner to read the text file.

A simple approach would be to save the Excel file as a comma-separated values (.CSV) file.
Since you have never used a framework before, I will show you how to use the OpenCSV framework.
First you need to add this framework to your Build Path. Drag the downloaded .jar files to your workspace in Eclipse. Open the project's properties, Select Java Build Path, Select Libraries tab, and then Add a Library from Workspace and select that jar file.
To use it, your class will look something like this,
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import au.com.bytecode.opencsv.CSVReader;
public class CSV {
private List<String[]> fileContent;
public CSV(String filePath) {
try {
readCSV(filePath);
} catch (IOException e) {
System.out.print("There was an error reading this CSV file. Error follows:");
e.printStackTrace();
}
}
public void readCSV(String csvPath) throws IOException {
// Store coupon objects in array list
CSVReader csvReader = new CSVReader(new FileReader(csvPath));
// Store each row into a String list
List<String[]> csvData = csvReader.readAll();
csvReader.close();
fileContent = csvData;
}
public void printFileContent() {
System.out.println("");
for (String[] row : fileContent.subList(1, fileContent.size())) {
for (String s: row) {
System.out.print(s + " ");
}
System.out.println();
}
System.out.println("");
}
}
Inside the main method, you can use a simple
CSV csvFile = new CSV("csv/Path/Here.csv");
// Verify Results
csvFile.printFileContent();
As always, please use my code as a reference. It is always better to learn how to write code yourself, especially when this question pertains to a homework assignment.

Related

How to read a text file into an array list of objects in Java

I'm currently working on a project and I'm running into a couple of issues. This project involves working with 2 classes, Subject and TestSubject. Basically, I need my program (in TestSubject class) to read details (subject code and subject name) from a text file and create subject objects using this information, then add those to an array list. The text file looks like this:
ITC105: Communication and Information Management
ITC106: Programming Principles
ITC114: Introduction to Database Systems
ITC161: Computer Systems
ITC204: Human Computer Interaction
ITC205: Professional Programming Practice
the first part is the subject code i.e. ITC105 and the second part is the name (Communication and Information Management)
I have created the subject object with the code and name as strings with getters and setters to allow access (in the subject class):
private static String subjectCode;
private static String subjectName;
public Subject(String newSubjectCode, String newSubjectName) {
newSubjectCode = subjectCode;
newSubjectName = subjectName;
}
public String getSubjectCode() {
return subjectCode;
}
public String getSubjectName() {
return subjectName;
}
public void setSubjectCode(String newSubjectCode) {
subjectCode= newSubjectCode;
}
public void setSubjectName(String newSubjectName) {
subjectName = newSubjectName;
}
The code I have so far for reading the file and creating the array list is:
public class TestSubject {
#SuppressWarnings({ "null", "resource" })
public static void main(String[] args) throws IOException {
File subjectFile = new File ("A:\\Assessment 3 Task 1\\src\\subjects.txt");
Scanner scanFile = new Scanner(subjectFile);
System.out.println("The current subjects are as follows: ");
System.out.println(" ");
while (scanFile.hasNextLine()) {
System.out.println(scanFile.nextLine());
}
//This array will store the list of subject objects.
ArrayList <Object> subjectList = new ArrayList <>();
//Subjects split into code and name and added to a new subject object.
String [] token = new String[3];
while (scanFile.hasNextLine()) {
token = scanFile.nextLine().split(": ");
String code = token [0] + ": ";
String name = token [1];
Subject addSubjects = new Subject (code, name);
//Each subject is then added to the subject list array list.
subjectList.add(addSubjects);
}
//Check if the array list is being filled by printing it to the console.
System.out.println(subjectList.toString());
This code isn't working, the array list is just printing as blank. I have tried doing this several ways including a buffered reader but I can't get it to work so far. The next section of code allows a user to enter a subject code and name, which is then added to the array list as well. That section of code works perfectly, I'm just stuck on the above part. Any advice on how to fix it to make it work would be amazing.
Another small thing:
File subjectFile = new File ("A:\\Assessment 3 Task 1\\src\\subjects.txt"); //this file path
Scanner scanFile = new Scanner(subjectFile);
I'd like to know how I can change the file path so that it will still work if the folder is moved or the files are opened on another computer. The .txt file is in the source folder with the java files. I have tried:
File subjectFile = new File ("subjects.txt");
But that doesn't work and just throws errors.
That is because you have already read through the file
while (scanFile.hasNextLine()) {
System.out.println(scanFile.nextLine());
}
The contents are exhausted. So when you do
while (scanFile.hasNextLine()) {
token = scanFile.nextLine().split(": ");
there is no data left.
Remove the first loop or re-open the file.
Or as #UsagiMiyamoto mentions
Or read the line to a String variable, print it, then split it... All in one loop.
I assume you are just beginning with learning Java and hence the below code is probably way too advanced, but it may help others who are trying to do something similar to you and also give you a glimpse of what you will probably learn in future.
The below code uses the following (in no particular order):
Streams
Accessing resources
Records
try-with-resources
Multi-catch
Method references
NIO.2
More notes after the code.
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public record Subject(String subjectCode, String subjectName) {
private static final String DELIMITER = ": ";
private static Path getPath(String filename) throws URISyntaxException {
URL url = Subject.class.getResource(filename);
URI uri = url.toURI(); // throws java.net.URISyntaxException
return Paths.get(uri);
}
private static Subject makeSubject(String line) {
String[] parts = line.split(DELIMITER);
return new Subject(parts[0].trim(), parts[1].trim());
}
/**
* Reads contents of a text file and converts its contents to a list of
* instances of this record and displays that list.
*
* #param args - not used.
*/
public static void main(String[] args) {
try {
Path path = getPath("subjects.txt");
try (Stream<String> lines = Files.lines(path)) { // throws java.io.IOException
lines.map(Subject::makeSubject)
.collect(Collectors.toList())
.forEach(System.out::println);
}
}
catch (IOException | URISyntaxException x) {
x.printStackTrace();
}
}
}
A Java record is applicable for an immutable object and it simply saves you from writing code for methods including getters as well as equals, hashCode and toString. (There are no setters since a record is immutable.) It's a bit like Project Lombok. I would say that a Subject is immutable since I don't think the code or name would need to be changed and that's why I thought making Subject a record was applicable.
Running the above code produces the following output:
Subject[subjectCode=ITC105, subjectName=Communication and Information Management]
Subject[subjectCode=ITC106, subjectName=Programming Principles]
Subject[subjectCode=ITC114, subjectName=Introduction to Database Systems]
Subject[subjectCode=ITC161, subjectName=Computer Systems]
Subject[subjectCode=ITC204, subjectName=Human Computer Interaction]
Subject[subjectCode=ITC205, subjectName=Professional Programming Practice]
Regarding
I'd like to know how I can change the file path so that it will still work if the folder is moved
I placed file subjects.txt in the same folder as file Subject.class, which allowed me to use method getResource. Refer to the Accessing resources link, above. Note that this can't be used if
the files are opened on another computer
Alternatively, there are several directories whose paths are stored in System properties including
java.home
java.io.tmpdir
user.home
user.dir
what did your debug console said about the exception?
your code works very well in my editor.
code result
and you should code like below if you want to read file through relative path
before ->
new File ("A:\Assessment 3 Task 1\src\subjects.txt");
after ->
new File (".\\subjects.txt");

Trying to add substrings from newLines in a large file to a list

I downloaded my extended listening history from Spotify and I am trying to make a program to turn the data into a list of artists without doubles I can easily make sense of. The file is rather huge because it has data on every stream I have done since 2016 (307790 lines of text in total). This is what 2 lines of the file looks like:
{"ts":"2016-10-30T18:12:51Z","username":"edgymemes69endmylifepls","platform":"Android OS 6.0.1 API 23 (HTC, 2PQ93)","ms_played":0,"conn_country":"US","ip_addr_decrypted":"68.199.250.233","user_agent_decrypted":"unknown","master_metadata_track_name":"Devil's Daughter (Holy War)","master_metadata_album_artist_name":"Ozzy Osbourne","master_metadata_album_album_name":"No Rest for the Wicked (Expanded Edition)","spotify_track_uri":"spotify:track:0pieqCWDpThDCd7gSkzx9w","episode_name":null,"episode_show_name":null,"spotify_episode_uri":null,"reason_start":"fwdbtn","reason_end":"fwdbtn","shuffle":true,"skipped":null,"offline":false,"offline_timestamp":0,"incognito_mode":false},
{"ts":"2021-03-26T18:15:15Z","username":"edgymemes69endmylifepls","platform":"Android OS 11 API 30 (samsung, SM-F700U1)","ms_played":254120,"conn_country":"US","ip_addr_decrypted":"67.82.66.3","user_agent_decrypted":"unknown","master_metadata_track_name":"Opportunist","master_metadata_album_artist_name":"Sworn In","master_metadata_album_album_name":"Start/End","spotify_track_uri":"spotify:track:3tA4jL0JFwFZRK9Q1WcfSZ","episode_name":null,"episode_show_name":null,"spotify_episode_uri":null,"reason_start":"fwdbtn","reason_end":"trackdone","shuffle":true,"skipped":null,"offline":false,"offline_timestamp":1616782259928,"incognito_mode":false},
It is formatted in the actual text file so that each stream is on its own line. NetBeans is telling me the exception is happening at line 19 and it only fails when I am looking for a substring bounded by the indexOf function. My code is below. I have no idea why this isn't working, any ideas?
import java.util.*;
public class MainClass {
public static void main(String args[]){
File dat = new File("SpotifyListeningData.txt");
List<String> list = new ArrayList<String>();
Scanner swag = null;
try {
swag = new Scanner(dat);
}
catch(Exception e) {
System.out.println("pranked");
}
while (swag.hasNextLine())
if (swag.nextLine().length() > 1)
if (list.contains(swag.nextLine().substring(swag.nextLine().indexOf("artist_name"), swag.nextLine().indexOf("master_metadata_album_album"))))
System.out.print("");
else
try {list.add(swag.nextLine().substring(swag.nextLine().indexOf("artist_name"), swag.nextLine().indexOf("master_metadata_album_album")));}
catch(Exception e) {}
System.out.println(list);
}
}
Find a JSON parser you like.
Create a class that with the fields you care about marked up to the parsers specs.
Read the file into a collection of objects. Most parsers will stream the contents so you're not string a massive string.
You can then load the data into objects and store that as you see fit. For your purposes, a TreeSet is probably what you want.
Your code will throw a lot of exceptions only because you don't use braces. Please do use braces in each blocks, whether it is if, else, loops, whatever. It's a good practice and prevent unnecessary bugs.
However, everytime scanner.nextLine() is called, it reads the next line from the file, so you need to avoid using that in this way.
The best way to deal with this is to write a class containing the fields same as the json in each line of the file. And map the json to the class and get desired field value from that.
Your way is too much risky and dependent on structure of the data, even on whitespaces. However, I fixed some lines in your code and this will work for your purpose, although I actually don't prefer operating string in this way.
while (swag.hasNextLine()) {
String swagNextLine = swag.nextLine();
if (swagNextLine.length() > 1) {
String toBeAdded = swagNextLine.substring(swagNextLine.indexOf("artist_name") + "artist_name".length() + 2
, swagNextLine.indexOf("master_metadata_album_album") - 2);
if (list.contains(toBeAdded)) {
System.out.print("Match");
} else {
try {
list.add(toBeAdded);
} catch (Exception e) {
System.out.println("Add to list failed");
}
}
System.out.println(list);
}
}

Creating files in a separate thread

I have a method that starts creating JSON files in each of the folders in my tree.
public static void fill(List<String> subFoldersPaths) {
for (int i = 0; i < subFoldersPaths.size(); i++) {
String fullFileName = subFoldersPaths.get(i) + FILE_NAME;
String formatFullFileName = String.format(fullFileName, i)+"%d";
Runnable runnable = new JsonCreator(formatFullFileName);
new Thread(runnable).start();
}
}
List<String> subFoldersPaths is a list that contains paths to each folder in order.
Here is my folder structure:
I want each folder to be filled with files in a separate thread every 0.08 seconds. But my class will not fill every folder.
Here is a class that implements Runnable, which should perform the filling:
import com.epam.lab.model.Author;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import net.andreinc.mockneat.MockNeat;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.FileWriter;
import java.io.IOException;
public class JsonCreator implements Runnable {
private static Logger logger = LogManager.getLogger();
private static String fileName;
private static final int FILES_COUNT = 100;
public JsonCreator(String s){
this.fileName = s;
}
#Override
public void run() {
for (int i = 0; i < FILES_COUNT; i++) {
try {
String formatFullFileName = String.format(fileName, i)+".json";
FileWriter fileWriter = new FileWriter(formatFullFileName);
fileWriter.write(createJsonString());
fileWriter.close();
Thread.sleep(80);
} catch (IOException | InterruptedException e) {
logger.error("File was not created", e);
}
}
}
private static String createJsonString() {
MockNeat mockNeat = MockNeat.threadLocal();
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.create();
String json = mockNeat
.reflect(Author.class)
.field("authorName", mockNeat.names().first())
.field("authorSurname", mockNeat.names().last())
.map(gson::toJson)
.val();
return json;
}
}
But this class fills not every folder with files. (maybe there is a problem with the file names) I can not figure it out.
And I want each folder below "foo" to be filled in a separate thread of JSON files in the amount of FILES_COUNT = 10
some examples of algorithm execution:
The folder structure is created with the participation of the random, so it is almost always different. but this does not affect the fact that files are not created in all folders
Your code is buggy; you cannot ever use that FileWriter constructor. Use new FileWriter(formatFullFileName, StandardCharsets.UTF_8), which is only in jdk11. If you're not on JDK11, you can't use FileWriter at all (it uses platform default encoding, and that is not acceptable; JSON must be in UTF-8 as per the JSON spec, and you have no guarantee that UTF-8 is your platform default).
you aren't guarding your FileWriter with an ARM block - you should add that.
In the initial block, formatFullFileName is a variable that is a format string. In the run() method, it's the opposite (it's the result of running a String.format op on one). Makes your code very hard to read.
Most likely your filenames are incorrect. You should be using List<Path> which would have removed any doubt. If your List<String> subFoldersPaths contains, for example, /home/misnomer/project/foo/1stLayerSubFolder0 in it, and the constant FILE_NAME (which you did not put in your pastes) is, say, example, then the path for the very first file to be created becomes: /home/misnomer/project/foo/1stLayerSubFolder0example0.json which is not what you wanted - you're missing a slash.
NB: If using the newer path API, writing a string to a file becomes vastly simpler: Files.write(path, string) is all you need (and note that the Files API defaults to UTF-8, unlike most other parts of the java libraries that involve turning strings to bytes or vice versa).
The paste needs more info, or you should debug this on your own: Print when you write a file, preferably including the thread ID (you can get it with Thread.currentThread().getName()). That's how programming works: You don't just stare at it, go --heck, I dunno, better ask stack overflow!-- and then give up. You debug it. Use a debugger, or if you can't/don't want to, use the poor man's debugger: Add a whole bunch of System.out.println statements. Go through your code and imagine (write it down if you have to) which each step is doing. Then, add a println statement that confirms this. The very place where what the program says it is doing does not match with what you thought it would do? That's where a bug is. Fix it, and keep going until all bugs are eliminated.

Calling An Array That Was Created in An Iteration

so I'm writing a program that will read a csv file and put each individual line of the file into an array. I would like to know if it would be possible to name a singular array that was created in the while loop. I would also love to know if you have any ideas on how I'd be able to separate the lines (containing the rows of the csv file) by the columns of the csv file.
This is my code:
package sample.package;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class SampleClass {
/**
* #param args
*/
public static String fileLocation; //Used to declare the file path
public static void readAndArray(String fileLocation) throws IOException { //Method to read a file and put each line into an array
BufferedReader lineRead = new BufferedReader(new FileReader(fileLocation)); //Read the file and be able to parse it into separate lines
String line = lineRead.readLine(); //Put line into variable so it isn't a boolean statement
while ((line = lineRead.readLine()) !=null) { //Make it possible to print out array as BufferedReader is used
String[] oneLine = new String[] {line}; //Put parsed line in new array and parsing that data for individual spots in array
System.out.println(oneLine[0]); //Print out each oneLine array
}
lineRead.close(); //Neatly close BufferedReader and FileReader
}
public static void main(String[] args) throws IOException{
readAndArray("filePath"); //Initialize method by inputting the file path
}
}
Thanks so much guys!
First of: Welcome to stackoverflow!
I assume that your question relates to some sort of educational programming task, if not: There are a number of libraries dealing with CSV files (with additional features like reading header rows and read row entries by header/column name, etc).
But ... why should it be a complicated task to write a CSV parser, i mean, its basically just values separated by commas, phhh!?
To cut a long story short: There is RFC 4180, but don't expect that all your .csv files stick to it. Quoting Wikipedia:
The CSV file format is not fully standardized. The basic idea of
separating fields with a comma is clear, but that idea gets
complicated when the field data may also contain commas or even
embedded line-breaks. CSV implementations may not handle such field
data, or they may use quotation marks to surround the field. Quotation
does not solve everything: some fields may need embedded quotation
marks, so a CSV implementation may include escape characters or escape
sequences.
After you are aware of and hopefully understand the provided warning about compatibility the following code example completely ignores it and provides a quick and dirty solution (don't use it in production, seriously ... how to not be fired 101: use a well tested library like opencsv or Apache Commons CSV):
public static void main(String[] args)
{
Path path = Paths.get("some path"); // TODO Change to path to an CSV file
try (Stream<String> lines = Files.lines(path))
{
List<List<String>> rows = lines
// Map each line of the file to its fields (String[])
.map(line -> line.split(","))
// Map the fields of each line to unmodifiable lists
.map(fields -> Collections.unmodifiableList(Arrays.asList(fields))
// Collect the unmodifiable lists in an unmodiable list (listception)
.collect(Collectors.toUnmodifiableList());
// Ensure file is not empty.
if (rows.isEmpty())
{
throw new IllegalStateException("empty file");
}
// Ensure all lines have the same number of fields.
int fieldsPerRow = rows.get(0).size();
if (!rows.stream().allMatch(row -> row.size() == fieldsPerRow))
{
throw new IllegalStateException("not all rows have the same number of fields");
}
// Assume the file has a header line appearing as the first line.
System.out.printf("Column names: %s\n", rows.get(0));
// Read the data rows.
rows.stream()
.skip(1) // Skip header line
.forEach(System.out::println);
}
catch (IOException | UncheckedIOException e)
{
e.printStackTrace(); // TODO Handle exception
}
}
This code assumes:
Fields are separated by commas
A line is considered to be terminated by any one of a line feed ('\n'), a carriage return ('\r'), or a carriage return followed immediately by a linefeed (behaviour of BufferedReader used by Files.lines())
All lines have the same number of fields
The first line is a header line
The implementor was too lazy to mind fields enclosed in double quotes
Quick and dirty ... and violates the RFC ;)

populating JComboBox from text file with delimiters

I'm not looking for a complete answers just help on how to start it or maybe some references I could look at that may help me with this. Ok so I have to populate the JComboBox (accountnumber) from a text file. The txt files reads as:
1231<>Jack Williams<>2015/1/21<>463.02
1232<>Jane Brown<>2015/1/21<>13510.54
1233<>Paul Gonzales<>2015/1/22<>680.17
1234<>Jian Chen<>2015/1/22<>1117.54
1235<>Lily Makki<>2015/1/22<>1124.89
1236<>Michael Lopez<>2015/1/23<>800.0
1237<>Jose Alvarez<>2015/1/23<>607.21
1238<>Tina Lin<>2015/1/24<>11077.0
It reads as acctNumber<>CustomerName<>openDate<>balance
How would I go about starting this? Which would be easiest to split the 4 variables. array/arraylist/hashmap etc.?
I'm not familiar with file I/O. and trouble with collections so this is the only part I'm stuck on.
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class AccountUtility {
List<String> accountsInfo = new ArrayList<>();
BufferedReader in;
File file = new File("accounts.txt");
public AccountUtility(){
ReadFile();
}
public void ReadFile(){
String nxtLine = " ";
try{
in = new BufferedReader(new FileReader(file));
while(nxtLine != null){
nxtLine = in.readLine();
accountsInfo.add(nxtLine);
}
for(String items : accountsInfo)
System.out.println(items);
in.close();
}catch(IOException ex){
}
}
public static void main(String[] args) {
AccountUtility ut = new AccountUtility();
}
}
so i decided to use a list , this is just my accountutility class I just added a mainmethod so i can test just this class and the result when i Run it comes to
1231<>Jack Williams<>2015/1/21<>463.02
1232<>Jane Brown<>2015/1/21<>13510.54
1233<>Paul Gonzales<>2015/1/22<>680.17
1234<>Jian Chen<>2015/1/22<>1117.54
1235<>Lily Makki<>2015/1/22<>1124.89
1236<>Michael Lopez<>2015/1/23<>800.0
1237<>Jose Alvarez<>2015/1/23<>607.21
1238<>Tina Lin<>2015/1/24<>11077.0
null
How do i split an list using a delimiter?
You're primary identifier is the account number, from this you need to be able to ascertain the account details.
This would lead me to use some kind of Map.
I would then create an Account class which held all the information in a simple, easy to use class, which provided appropriate setters and getters.
This would then lean me to the fact that I wouldn't actually need the Map, because all the information I need was in the Account class, so instead, I would simply create a ListCellRenderer for the combo box that would be capable of taking the account number from an instance of the Account class and display it appropriately...
This would mean I'd only need a List or a ComboBoxModel to hold the account details
Take a closer look at How to Use Combo Boxes for more details
To display an Object, Swing components will use the toString() method the Object placed in it.
One approach is to create a Data class that holds the name, ID, etc., implement toString() to display what you want (in your case, the Account Number), and then put a list of these objects in your JComboBox.
Then on change of selection in the combo, get the selected item, cast it to the data class, and then call getDate(), getName(), etc. to populate the textfields.
If you want to actually show the extra details of the Customer in the combo (after all, who really knows the person by account number?), then take a look at one approach here:
DetailedComboBox
Justin, I'm in the same boat and created a similar program that reads from text file. There was an excellent given for cells (e.g. Excel or Sql), but need to have it read from a text file. I'm thinking:
String tmp [] = line.split ("<>");
this will output data from each break.

Categories