I'm going to do a Java library on a simple data frame that can read CSV files, edit the CSV and export CSV file. My problem is on how to export it.
Here is how I read my CSV file:
String line;
List dataFrame = new ArrayList();
String filePath = "C:\\Users\\user\\Desktop\\SimpleDataFrame\\src\\Book1.csv";
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
while ((line = br.readLine()) != null) {
List values = Arrays.asList(line.split(String.valueOf(",")));
dataFrame.add(values);
}
} catch (Exception e) {
System.out.println(e);
}
And this is how I implement the write CSV file:
FileWriter writer = new FileWriter(new File("Book2.csv"));
for(int i = 0; i<dataFrame.size(); i++){
String[] array = (String [])dataFrame.get(i);
for(int j = 0; j<array.length; j++){
writer.write(array[j]);
if(j<array.length-1) writer.write(",");
else writer.write("\n");
}
}
And this is the exception that it throws to me:
Exception in thread "main" java.lang.ClassCastException: class java.util.Arrays$ArrayList cannot be cast to class [Ljava.lang.String; (java.util.Arrays$ArrayList and [Ljava.lang.String; are in module java.base of loader 'bootstrap')
Can I know what is the problem?
In one method you have:
List values = Arrays.asList(line.split(String.valueOf(",")));
dataFrame.add(values);
So here values is a List
Then in the write method you have:
String[] array = (String [])dataFrame.get(i);
String[] is different from List that's why you have an error when you try to cast it.
It would be better if in top you do:
List<String> values = Arrays.asList(line.split(String.valueOf(",")));
dataFrame.add(values);
Adding generics. Then in the write method something like:
List<String> stringList = (List<String>) dataFrame.get(i); //Add generics to data frame here so you don't need that cast!
for(int j = 0; j<stringList.size(); j++){
writer.write(stringList.get(j));
if(j<stringList.size()-1) writer.write(",");
else writer.write("\n");
}
The problem here is your use of rawtypes. Lists in java are generic, and you have to specify the element type you want to use. Also, Lists are not interchangeable with arrays, and cannot directly cast to arrays.
List dataFrame = new ArrayList();
should trigger a warning, and you should not ignore this warning.
Based on your usage, it has to be a
List<List<String>> dataFrame = new ArrayList<>();
The elements are Lists, because you explicitly convert them from arrays to Lists in
List values = Arrays.asList(line.split(String.valueOf(",")));
String.split returns a String[], which you convert to a List with Arrays.asList.
This line should be
List<String> values = Arrays.asList(line.split(","));
(you don't need String.valueOf here, the literal is already a String).
And then in
String[] array = (String [])dataFrame.get(i);
you get a runtime exception because dataFrames contains Lists, not arrays String[]. This can be rewritten as, for example using enhanced for loop and String.join, and wrapping the writer in a try-with-resources, so that you can't forget closing it.
try (FileWriter writer = new FileWriter(new File("Book2.csv"))) {
for (List<String> list : dataFrame) {
writer.write(String.join(",", list));
writer.write("\n");
}
} catch (IOException e) {
e.printStackTrace();
}
Related
(Homework:) I want to use array instead of arraylist in this situation. I have the arraylist name Employee and i have to insert data of it into the tree. I load data line by line from file. But i want to use array for the Employee not arraylist. How can i do that ? There're any ways to use array instead of arraylist in this situation. The following code is my example code for arraylist Employee. I want to change List to Employee[] how can i write the following function in style of Array.
public static void main(String[] args) {
List<Employee> employees = read("employees.txt");
BST bst = new BST();
for(Employee e : employees){
bst.insert(e);
}
}
public static List<Employee> read(String file) {
try {
List<Employee> employees = new ArrayList<>();
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null ){
String[] arr = line.split("-");
Employee emp = new Employee();
emp.ccode = Integer.parseInt(arr[0]);
emp.cus_name = arr[1];
emp.phone = arr[2];
employees.add(emp);
}
return employees;
} catch (IOException ex) {
Logger.getLogger(TestMusic.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
This approach is not the best one, but might solve your problem. to be used for java versions < 8.
The approach is to parse the file to get no. of lines, to create the employee array, and parse again to get data of all the individual employees
public static void main(String[] args) {
int empSize = getNumberOfEmployees("employees.txt");
employees = new Employee[empSize];
employees = read("employees.txt");
BST bst = new BST();
for(Employee e : employees){
bst.insert(e);
}
}
public static int getNumberOfEmployees (String file) {
int totalEmp = 0;
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while((line = reader.readLine()) != null ) {
totalEmp ++;
}
}catch (IOException e) {
e.printStackTrace();
}
return totalEmp;
}
public static Employee[] read(String file) {
try {
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
int i=0;
while((line = reader.readLine()) != null ){
String[] arr = line.split("-");
Employee emp = new Employee();
emp.ccode = Integer.parseInt(arr[0]);
emp.cus_name = arr[1];
emp.phone = arr[2];
employees[i] = emp;
i++;
}
return employees;
} catch (IOException ex) {
Logger.getLogger(TestMusic.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
Without giving you any code (do it by yourself ;-)):
Parse the file twice:
get the number of lines, create an Array based on the number of lines
parse the file again, fill the Array
And some Research (keywords BufferedReader and Array) would help you too.
It is unclear from your requirements what you want to do in the following situations:
one line fails to parse;
cannot open the file for reading.
Here is a solution which (eww) will just ignore the unparseable entries and return an empty array if the file cannot be parsed:
public final class TestMusic
{
private static final Employee[] NO_EMPLOYEES = new Employee[0];
public static void main(final String... args)
{
final BST bst = new BST();
for (final Employee emp: getArray())
bst.insert(emp);
}
private static Employee toEmployee(final String input)
{
final String[] arr = input.split["-"];
final Employee emp = new Employee();
try {
emp.ccode = Integer.parseInt(arr[0]);
emp.cus_name = arr[1];
emp.phone = arr[2];
return emp;
} catch (NumberFormatException | IndexOutOfBoundsException e) {
return null;
}
}
private static Employee[] getArray()
{
final Path path = Paths.get("employees.txt");
try (
Stream<String> lines = Files.lines(path);
) {
return lines.map(TestMusic::toEmployee)
.filter(Objects::nonNull)
.toArray(Employee[]::new);
} catch (IOException ignored) {
return NO_EMPLOYEES;
}
}
}
Note how this solution does not use an intermediate list at all; instead, it makes use of the Java 8 Stream API.
What is left to do here is to handle errors... That is for you to decide :)
if you want to convert ArrayList to array use the following code:
Employee [] arrayOfEmpolyees = new Employee[employees.size()]
employees.toArray(arrayOfEmpolyees);
That is like doing a step backwards. Java collections (for example the List interface and the ArrayList implementation) have various advantages compared to "plain old" arrays.
The only real advantage of arrays is their reduced overhead - but that is only important when dealing with millions or billions of things to store in a container.
So the real answer is: don't do that. Just keep using List/ArrayList.
But in case you insist, you can of course use arrays - but then you have to add that part that makes ArrayList more convenient: you have to provide code that dynamically "grows" your array once you hit its size limit. That works like this:
you start with an initial array of size 100 for example
while populating that array, you keep track of the number of slots "in use"
when your code wants to add the 101st element, you "grow" the array
Growing works by:
creating a new array, that has like currentArray.length + 100 capacity
using System.arraycopy() to move all entries from the old to the new array
Guess the size of the array, for example by taking the size of the file and dividing by 20 (approximately the size of the line in the example you gave). Then read into the array, counting the lines. If the array is full before you have reached the end of the file, allocate a new array double the size, copy everything from the old array to the new array, replace the old array with the new array and continue the same way until done. You can look at the source of ArrayList to see an example of how it is done - basically this is what ArrayList does internally.
I want to write an ArrayList<String> into a text file.
The ArrayList is created with the code:
ArrayList arr = new ArrayList();
StringTokenizer st = new StringTokenizer(
line, ":Mode set - Out of Service In Service");
while(st.hasMoreTokens()){
arr.add(st.nextToken());
}
import java.io.FileWriter;
...
FileWriter writer = new FileWriter("output.txt");
for(String str: arr) {
writer.write(str + System.lineSeparator());
}
writer.close();
You can do that with a single line of code nowadays.
Create the arrayList and the Path object representing the file where you want to write into:
Path out = Paths.get("output.txt");
List<String> arrayList = new ArrayList<> ( Arrays.asList ( "a" , "b" , "c" ) );
Create the actual file, and fill it with the text in the ArrayList:
Files.write(out,arrayList,Charset.defaultCharset());
I would suggest using FileUtils from Apache Commons IO library.It will create the parent folders of the output file,if they don't exist.while Files.write(out,arrayList,Charset.defaultCharset()); will not do this,throwing exception if the parent directories don't exist.
FileUtils.writeLines(new File("output.txt"), encoding, list);
If you need to create each ArrayList item in a single line then you can use this code
private void createFile(String file, ArrayList<String> arrData)
throws IOException {
FileWriter writer = new FileWriter(file + ".txt");
int size = arrData.size();
for (int i=0;i<size;i++) {
String str = arrData.get(i).toString();
writer.write(str);
if(i < size-1)**//This prevent creating a blank like at the end of the file**
writer.write("\n");
}
writer.close();
}
If you want to serialize the ArrayList object to a file so you can read it back in again later use ObjectOuputStream/ObjectInputStream writeObject()/readObject() since ArrayList implements Serializable. It's not clear to me from your question if you want to do this or just write each individual item. If so then Andrey's answer will do that.
You might use ArrayList overloaded method toString()
String tmp=arr.toString();
PrintWriter pw=new PrintWriter(new FileOutputStream(file));
pw.println(tmp.substring(1,tmp.length()-1));
I think you can also use BufferedWriter :
BufferedWriter writer = new BufferedWriter(new FileWriter(new File("note.txt")));
String stuffToWrite = info;
writer.write(stuffToWrite);
writer.close();
and before that remember too add
import java.io.BufferedWriter;
Write a array list to text file using JAVA
public void writeFile(List<String> listToWrite,String filePath) {
try {
FileWriter myWriter = new FileWriter(filePath);
for (String string : listToWrite) {
myWriter.write(string);
myWriter.write("\r\n");
}
myWriter.close();
System.out.println("Successfully wrote to the file.");
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
}
The goal of my code is to replace a certain text value within my .CSV file with the user input of a text field.
My .CSV file has values delimited by commas: hey,hi. If I'm just wanting to replace 'hey' then I would gather the input from the text field and replace 'hey' with 'bye'. Output: bye,hi.
In my code, I believe I am reading in my file and writing the contents of the file to a list, delimited by commas.
I will then iterate through the list and replace an instance of the user input within the list, with another user input and write it back to file.
However, I cannot write it back to file as I'm getting the Object[] cannot be converted to String[] error. Thus I'm stuck as to how to replace the instance of user input within the text file.
Here's my code:
try{
//Convert user input into strings
String strSerial = editSerialField.getText();
String strLocation = editLocationField.getText();
//Read existing file
CSVReader reader = new CSVReader(new FileReader("test test.txt"), ',');
List myEntries = reader.readAll();
//Iterate through my array
for (int i = 0; i < myEntries.size(); i++)
{
//If an entry matches the user input
if (myEntries.get(i).equals(strSerial))
{
//Set the match to the user input from strLocation
myEntries.set(i, strLocation);
break;
}
}
//Write to existing file
CSVWriter writer = new CSVWriter(new FileWriter("test test.txt"), ',');
//Error is here**********************
//Write the new string with the replaced word OVER the same file
writer.writeNext(myEntries.toArray(new String[myEntries.size()]));
writer.close();
}catch (IOException e)
{
System.out.println(e);
}
}
How do I modify my code so that it writes my changes to the .CSV file?
For a start writeNext will write on line at a time, so you need to loop.
Secondly consider using not a raw List but using generics.
Thirdly, it may be cleaner to write as you go
and lastly, each line will contain an Array of Strings
consider this code (not tested)
CSVReader reader = new CSVReader(new FileReader("test test.txt"), ',');
List<String []> myEntries = reader.readAll();
reader.close ();
CSVWriter writer = new CSVWriter(new FileWriter("test test.txt"), ',');
//Iterate through my array
for (String [] line : myEntries)
{
ArrayList<String> newLine = new ArrayList <String>();
for (String word : line) {
{
String newVal = word.replace(strSerial, strLocation);
newLine.add (newVal);
}
writer.writeNext(newLine.toArray(new String[newLine.size()]));
}
Your problem is/ starts at this line:
List myEntries = reader.readAll();
I assume that you did not noticed that the return type of the method readAll() is
List<String[]>
If for example your test file looks like :
hey, hi
hallo, hello
sth, sthelse
After calling readAll() your variable myEntries will be a list of string arrays; each array representing each row in your file and each string from that row as element of the array
myEntries : [hey, hi]
[hallo, hello]
[sth, sthelse]
Keeping this in mind the next issue is
if (myEntries.get(i).equals(strSerial))
where you try to compare a String[] with a String which will not be true.
Try it as follows :
try{
//Convert user input into strings
String strSerial = editSerialField.getText();
String strLocation = editLocationField.getText();
CSVReader reader = new CSVReader(new FileReader("test test.txt"), ',');
// valid but not a good practice how you declare your variable before
// List myEntries = reader.readAll(); // List of what??
List<String[]> myEntries = reader.readAll();
for (String[] row : myEntries){ // go through each array from your list representing a row in your file
for (int i = 0; i < row.length; i++){ //go through each element of that array
if (row[i].equalsIgnoreCase(strSerial)){
row[i] = strLocation;
}
}
}
//add the parameter CSVWriter.NO_QUOTE_CHARACTER to prevent opencsv from writing quotes to file
CSVWriter writer = new CSVWriter(new FileWriter("test test.txt"), ',',CSVWriter.NO_QUOTE_CHARACTER);
for (String[] row : myEntries){
writer.writeNext(row);
}
writer.close();
}catch (IOException e){
System.out.println(e);
}
Not really important but i would prefer test.csv instead of test.txt as file name as long as you store comma-separated values in there.
How can I have only one same name in my combobox? There are 2 same name in my fee text file and I want to get the name from fee text file to the combobox. But it display 2 same name.
There are no error in my code and I cannot find out the questions. I think my combobox function got problems. Below is my expected result.
//fee.txt
john|123|0.00
john|456|0.00
//my expected result in combobox
john
//my result
john
john
//filefuncion.java
public class FileFunction {
public static ArrayList getContent(File f) {
ArrayList ls = null;
try (BufferedReader in = new BufferedReader(new FileReader(f));) {
String line;
ls = new ArrayList();
/*while ((line = in.readLine()) != null) {
ls.add(line);
}*/
while ((line = in.readLine()) != null) {
if (line.trim().length() > 0) {
ls.add(line);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return ls;
}
//my code
private void combobox(){
File file = new File("fee.txt");
ArrayList al = FileFunction.getContent(file);
for (Object obj : al) {
String newobj = obj.toString();
String text[] = newobj.split("\\|");
String name = text[0];
String status = text[2];
if(status.equals("0.00")){
comboboxResident.addItem(name);
}
}
}
First, use generics to ensure a stronger type-checking and reduce bugs due to incorrect types. Write something like ArrayList<String> instead of plain ArrayList.
If you want to remove duplicate elements in an ArrayList instance, the most convenient way is to build a Set (which is a class under the Collection framework) and convert it back to ArrayList (if you need to).
For example, suppose you have an ArrayList instance, then you may write
ArrayList<String> list = ...
LinkedHashSet<String> set = new LinkedHashSet<>(list);
Just iterate through set will do. Or you can convert it back to a list by ArrayList<String> newList = new ArrayList<>(set);.
A LinkedHashSet implements the Set interface and does not contain duplicate elements. It also has predictable iteration order. If you want to further sort you elements, try a TreeSet instead.
In my main class, I loop through 120 files. For each file I create a 2d array of the data contained within.
My 2d Array is "fullData" of type List<List<String>>. ParserIPAM is an inherited class and i declare fullData in its super class.
This is my code within main:
for(String filename : filefetcher.getFiles()){
System.out.println("file to parse: "+ filename);
ipam = new ParserIPAM(filename);
i=0;
boolean flag = true;
System.out.println("------------------------------------------");
for(List<String> row : ipam.getSqlData()){
//queries.insertVars(row);
//System.out.println(row);
}
//System.out.println(i);
ipam.clearSqlData();
}
And here is my code where I fill the 2d Array:
public ParserIPAM(String filename){
super(filename);
try {
Parse(filename);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
SpecialOperations(fullData);
//System.out.println("+++++++++++++++++++++++++++++++++++"+ls2d.size());
}
#Override
void Parse(String filename) throws FileNotFoundException{
fullData.clear();
FileReader input = new FileReader(filename);
ArrayList<String> Raw = new ArrayList<String>();
BufferedReader bufRead = new BufferedReader(input);
Scanner bufferinput = new Scanner(bufRead);
String nextline = bufferinput.nextLine();
int i = 0;
while(bufferinput.hasNext()){
Raw.clear();
nextline = bufferinput.nextLine();
for(String cell: nextline.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)")){
Raw.add(cell);
//System.out.print(i+" "+cell); ////// THIS PRINTS CORRECT DATA
}
i++;
//System.out.println(i + " " + Raw); ////THIS PRINTS CORRECT DATA
fullData.add(Raw);
}
for(List<String> sub: fullData){
//System.out.println(sub); ///THIS DOES NOT PRINT CORRECTLY
}
}
Edit: ParserIPAM is an inherited class. Here is the complete code for the super class:
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
public abstract class Parser {
protected static String filename;
//private List<List<String>> dataArray = new ArrayList<ArrayList<String>()>();
protected List<List<String>> fullData = new ArrayList<List<String>>();
public Parser(String filename){
//this.filename = filename;
}
//Parse will only parse file and put raw data into a 2d ArrayList.
abstract void Parse(String filename) throws FileNotFoundException;
//SpecialOperations will add additional data to raw data for table insertions.
abstract void SpecialOperations(List<List<String>> data);
}
When I print everything out in the last System.out it prints the correct number of elements (256) but it always prints out the last line of the file 256 times in a row. I'm not exactly sure if I'm filling the array incorrectly or if I'm printing it incorrectly. Either way its wrong and I can't seem to figure it out.
I know there is probably a better way to do this than with an ArrayList, but that's not affecting the issue I'm having.
You only create one ArrayList instance (and clear it in your loop), so you only have one reference added (just many times). For Java 7 and above, the easiest solution I can think of is to use new ArrayList<>() diamond operator instead -
// Raw.clear();
Raw = new ArrayList<>();
for Java 6 and 5,
// Raw.clear();
Raw = new ArrayList<String>();
Similarly, you could also use this instead -
// fullData.add(Raw);
fullData.add(new ArrayList<>(Raw)); // <-- copies Raw
Try putting the instantiation of Raw inside the While loop
while(bufferinput.hasNext()){
ArrayList<String> Raw = new ArrayList<String>();
Raw.clear();
nextline = bufferinput.nextLine();
for(String cell: nextline.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)")){
Raw.add(cell);
//System.out.print(i+" "+cell); ////// THIS PRINTS CORRECT DATA
}
i++;
//System.out.println(i + " " + Raw); ////THIS PRINTS CORRECT DATA
fullData.add(Raw);
}