I am reading in a CSV file and putting each delimited element into a two-dimensional array. The code looks like this:
public DataProcess(String filename, String[][] contents, int n) {//n is 6 for contents, 5 for fiveMinContents
Scanner fileReader = null;
try {
fileReader = new Scanner(new File(filename));
} catch (FileNotFoundException ex) {
System.out.println(ex + " FILE NOT FOUND ");
}
fileReader.useDelimiter(",");
int rowIndex = 0;
while (fileReader.hasNext()) {
for (int j = 0; j < n; j++) {
contents[rowIndex][j] = fileReader.next();
System.out.println("At (" + rowIndex +", "+j+"): " +
contents[rowIndex][j]);
}
rowIndex++;
fileReader.nextLine();
}
}
I am not sure why it reads every other line of this particular CSV file because this is file 2/2 that is being read in this manner. The first one reads fine, but now this one skips every other line. Why would it work for one but not the other? I am running this on Eclipse's latest update.
I also checked out this answer and it did not help.
Because the last line of your loop reads a line and discards it. You need something like,
while (fileReader.hasNextLine()) {
String line = fileReader.nextLine();
contents[rowIndex] = fileReader.split(",\\s*");
System.out.println("At (" + rowIndex + "): "
+ Arrays.toString(contents[rowIndex]));
rowIndex++;
}
You could also print the multi-dimensional array with one call like
System.out.println(Arrays.deepToString(contents));
While the approach may work for you, it's not optimal. There are premade CSV readers for Java. One example is commons-csv:
Reader in = new FileReader("path/to/file.csv");
Iterable<CSVRecord> records = CSVFormat.EXCEL.parse(in);
for (CSVRecord record : records) {
String date = record.get(1);
String time = record.get(2);
// and so on, so forth
}
There are a small number of dependencies that have to be on your classpath. Hope that helps.
I found the issue to this problem.
First, I recommend using the external library that was suggested.
The issue was that since this second file was reading the entire row, whereas the first CSV file was reading what I wanted it to, but there was a column at the end of the file that I was ignoring. There must be a way that a CSV file is structured where the end of a row has a different delimiter or something along those lines--not sure. To fix this issue, I just added an extra column to the second file and I am not reading it in; it is just there.
In short, use an external CSV-reader library. If you don't want to do that, then just add a column directly after the last column in the file and do not read it.
Related
I'm fairly new at programming and programming in Java. Currently I'm learning about Exceptions and how to handle them. In this one lab I am given multiple text files containing numbers in a grid like manner. I was told to use the command-line arguments to run all the files at once.
The way the text files look (screenshot)
All files are named valid or invalid. The invalid files have some unique error in them that I have to check for. The first line of each text file gives the total number of rows and columns. I'm stuck trying to figure out how I can check the validity of text files: invalid2, invalid5, and invalid7. I can write some bad code that catches the errors in files invalid5 and invalid7 (which I don't want do), but invalid2 is really giving me a hard time. The problem with invalid2 is that the first line in the file tells me that the grid has 3 rows and 4 columns, but the actual grid has 4 rows and 3 columns.
invalid2 text file screenshot
I am currently trying to break the grids into individual rows. My logic (and here is where I want to know if its faulty) is that I'm using a while loop that checks if there is a next line in the text file. If there is, I will increase my row counter (even though I already know how many rows the grid has). I then check if the row counter is bigger than the actual number of rows given which would throw an exception that there are too many rows. If not, I move onto parsing each row of the grid. I use a String "nextLine" that contains all the numbers in that one row of the grid and parse that string with the Scanner "parse". I use a for loop that goes on the same number of times as there are columns (The # given by the file). I then set the variable "num" of type double to get the next double in that string. At this point my program breaks down. I don't know why I'm getting a NoSuchElementException at that line in my code. Screenshot on Eclipse I don't really need to do anything with the information I'm reading from the files so the "num" variable is just there to move onto the next number in the row.
I have two questions
Why am I getting the NoSuchElementException in that part of my code?
Is my logic correct in how I'm trying to check for the validity of each text file?
The output to the console should look something like this:
valid1.dat
VALID
invalid1.dat
java.lang.NumberFormatException: For input string: "X"
INVALID
etc...
This is my code:
public class FormatChecker {
public static void main(String[] args) {
for(int n = 3; n < args.length; n++) { // Loops through command-line arguments
String fileName = args[n]; // Sets specific file
try {
File file = new File(fileName); // new File from specified file name
Scanner read = new Scanner(file); // Scanner object to read the new file
String firstLine = read.nextLine(); // String to hold the first line of the file
Scanner parse = new Scanner(firstLine); // Scanner object to parse the first line (reads first line)
int row = parse.nextInt(); // Gets first token from Scanner object 'parse' to get # of rows
int col = parse.nextInt(); // Gets second token from Scanner object 'parse' to get # of columns
if(parse.hasNext()) { // Checks if there are more than two tokens (for invalid4.dat)
throw new GridSizeException("Too many dimensions"); // If yes, throws created exception "GridSizeException"
} else { // HERE IS WHERE I NEED HELP W/ MY LOGIC!
int rowCount = 0; // Row counter even thought we already know the # of rows
while(read.hasNextLine()) { // While loop that loops until the end of the file
rowCount++; // row count is increased
if(rowCount > row) { // if row counter is > than our given # of rows, we will throw an exception
throw new GridSizeException("Too many rows");
}
String nextLine = read.nextLine(); // String to hold the next line of the file
parse = new Scanner(nextLine); // For parsing that next line
for(int j = 0; j < col; j++) { // Loops the same # of times as the # of columns
double num = parse.nextDouble(); // Move through the String
if(j == col-1 && parse.hasNext()) { // Checks if there are more numbers in that row than expected.
throw new GridSizeException("Too many columns");
}
}
}
System.out.println(fileName);
System.out.println("VALID");
System.out.println();
}
} catch (FileNotFoundException e){
System.out.println(fileName);
System.out.println(e.toString() + " for input string: " + fileName);
System.out.println("INVALID\n");
} catch (NumberFormatException e) {
System.out.println(fileName);
System.out.println(e.toString() + " for input string: " + fileName);
System.out.println("INVALID\n");
} catch (InputMismatchException e) {
System.out.println(fileName);
System.out.println(e.toString() + " for input string: " + fileName);
System.out.println("INVALID\n");
} catch (GridSizeException e) {
System.out.println(fileName);
System.out.println(e.toString() + " for input string: " + fileName);
System.out.println("INVALID\n");
}
}
}
}
When you have read line with scanner, use string.split(" ") ( or whatever separates values )
Result of split() is an array of strings and you can
check for amount of values with array.length ( and decide thether there is enough values at all, or there is an error )
convert individual strings to number and catch an exception ( if number is not valid )
I have an assignment to create a "map" which is really an array that contains rooms. In the rooms there are artifacts that you can look at or examine and put into your inventory or "backpack". You are also able to save and restore your placement on the map, along with the artifact locations and your inventory. The save function saves it to a text file with the location, artifacts, and inventory. The problem that I am running into is trying to get the artifact data from the text file to restore on the program. I have no problem loading the location, but can not load any artifacts. While running the debugger it skips over the line. Here is the piece of code I am trying to work.
File fileRestore = new File("C:\\Users\\mike\\Desktop\\GCPU.txt");
try
{
FileReader reader = new FileReader(fileRestore);
BufferedReader buffer = new BufferedReader(reader);
String line = buffer.readLine();
while (line !=null)
{
String[] contents = line.split(",");
String key = contents[0];
if (key.equals("StartLocation"))
{
row = Integer.parseInt(contents[1]);
col = Integer.parseInt(contents[2]);
}
key = contents [1];
if (key.equals("Artifact"))
{
String name = contents [1];
row = Integer.parseInt(contents [2]);
col = Integer.parseInt(contents [3]);
if (name.equals("vending"))
map.rooms[row][col].contents = map.vending;
if (name.equals("beaker"))
map.rooms[row][col].contents = map.beaker;
if (name.equals("gameboy"))
map.rooms[row][col].contents = map.gameboy;
if (name.equals("paper"))
map.rooms[row][col].contents = map.paper;
if (name.equals("trees"))
map.rooms[row][col].contents = map.trees;
if (name.equals("desk"))
map.rooms[row][col].contents = map.desk;
if (name.equals("brewer"))
map.rooms[row][col].contents = map.brewer;
if (name.equals("statue"))
map.rooms[row][col].contents = map.statue;
}
Here is the text file that I am reading from:
StartLocation,0,2
Artifact,Eerie statue,2,0
Artifact,A small redwood sprout,3,0
Artifact,Gameboy Color,0,1
Artifact,Lapdesk,1,1
Artifact,A piece of paper,2,1
Artifact,Industrial coffee maker,1,3
So to reiterate my question, how am I able to read the Artifact line from the text along with the StartLocation line?
Thank you for taking the time to read this.
You are only reading once from the file. Replacing these two lines:
String line = buffer.readLine();
while (line !=null)
...
With something like so:
String line = "";
while((line = buffer.readLine()) != null)
...
Should allow you to read the next line each time the while loop iterates.
Alternatively, you could also have a line = buffer.readLine() just before your closing brace for the while loop. This approach is also valid, however, judging by the tutorials I went through, simply less popular.
String line = buffer.readLine();
should be inside the while loop. It is being executed only once.
Although make sure to modify initial value of line and the loop condition such that the loop starts .
Good luck.
String line = buffer.readLine(); will skip over the first line.
2.
if (key.equals("StartLocation"))
{ row = Integer.parseInt(contents[1]);
col = Integer.parseInt(contents[2]);
}
will fail because key = " StartLocation". there is a space in your
text file. use line=line.trim() to remove unnecessary characters.
3. Your program will read only 1 line.
How do i append an existing line in a text file? What if the line to be edited is in the middle of the file? Please kindly offer a suggestion, given the following code.
Have went through & tried the following:
How to add a new line of text to an existing file in Java?
How to append existing line within a java text file
My code:
filePath = new File("").getAbsolutePath();
BufferedReader reader = new BufferedReader(new FileReader(filePath + "/src/DBTextFiles/Customer.txt"));
try
{
String line = null;
while ((line = reader.readLine()) != null)
{
if (!(line.startsWith("*")))
{
//System.out.println(line);
//check if target customer exists, via 2 fields - customer name, contact number
if ((line.equals(customername)) && (reader.readLine().equals(String.valueOf(customermobilenumber))))
{
System.out.println ("\nWelcome (Existing User) " + line + "!");
//w target customer, alter total number of bookings # 5th line of 'Customer.txt', by reading lines sequentially
reader.readLine();
reader.readLine();
int total_no_of_bookings = Integer.valueOf(reader.readLine());
System.out.println (total_no_of_bookings);
reader.close();
valid = true;
//append total number of bookings (5th line) of target customer # 'Customer.txt'
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(filePath + "/src/DBTextFiles/Customer.txt")));
writer.write(total_no_of_bookings + 1);
//writer.write("\n");
writer.close();
}
catch (IOException ex)
{
ex.printStackTrace();
}
//finally
// {
//writer.close();
//}
}
}
}
To be able to append content to an existing file you need to open it in append mode. For example using FileWriter(String fileName, boolean append) and passing true as second parameter.
If the line is in the middle then you need to read the entire file into memory and then write it back when all editing was done.
This might be workable for small files but if your files are too big, then I would suggest to write the actual content and the edited content into a temp file, when done delete the old one an rename the temp file to be the same name as the old one.
The reader.readLine() method increments a line each time it is called. I am not sure if this is intended in your program, but you may want to store the reader.readline() as a String so it is only called once.
To append a line in the middle of the text file I believe you will have to re-write the text file up to the point at which you wish to append the line, then proceed to write the rest of the file. This could possibly be achieved by storing the whole file in a String array, then writing up to a certain point.
Example of writing:
BufferedWriter writer = new BufferedWriter(new FileWriter(new File(path)));
writer.write(someStuff);
writer.write("\n");
writer.close();
You should probably be following the advice in the answer to the second link you posted. You can access the middle of a file using a random access file, but if you start appending at an arbitrary position in the middle of a file without recording what's there when you start writing, you'll be overwriting its current contents, as noted in this answer. Your best bet, unless the files in question are intractably large, is to assemble a new file using the existing file and your new data, as others have previously suggested.
AFAIK you cannot do that. I mean, appending a line is possible but not inserting in the middle. That has nothing to do with java or another language...a file is a sequence of written bytes...if you insert something in an arbitrary point that sequence is no longer valid and needs to be re-written.
So basically you have to create a function to do that read-insert-slice-rewrite
I have strings which look like this -
String text = "item1, item2, item3, item4 etc..."
I made java code to write these strings to a text file which will be converted to csv by simply changing the extension. The logic is - print a string, then move to new line and print another string.
Output in text file was perfect when test strings had only 10-20 items.
BUT, my real strings have about 3000 unique items each. There are about 20,000 such strings.
When i write all these strings to the text file, it gets messed up.
I see 3000 rows instead of 20,000 rows.
I think there is no need for code for this problem because its been done and tested.
I only need to be able to format my data properly.
For those who want to see the code -
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Texty {
public static void main(String[] args) {
System.out.println("start");
String str = "";
String enter = System.getProperty( "line.separator" );
for(int i = 0; i< 5; i++){
str = str + i + ",";
}
str = str + 5;
System.out.println(str);
FileWriter fw = null;
File newTextFile = new File("C:\\filez\\output.txt");
try {
fw = new FileWriter(newTextFile);
} catch (IOException e) {
e.printStackTrace();
}
try {
for(int i = 0; i < 10; i++){
fw.write(str + enter);
}
fw.close();
} catch (IOException iox) {
//do stuff with exception
iox.printStackTrace();
}
System.out.println("stop");
}
}
You are right that there is no difference between 10 columns and 3000 columns, you just have longer lines
Also there is no difference between 10 rows and 20,000 rows, you juts have more lines.
While you can have much, much larger files in Java or on your files system, some old versions of excel could not load so many columns (it had a limit of 256 columns) or such large files (it had a limit of about 1 GB of raw data)
I would check the file is correct in another program e.g. one you wrote and you might find all the data is there.
If the data is not there, you have a bug, There is no limitation in Java or Windows or Linux which would explain the behaviour you are seeing.
currently i creating a java apps and no database required
that why i using text file to make it
the structure of file is like this
unique6id username identitynumber point
unique6id username identitynumber point
may i know how could i read and find match unique6id then update the correspond row of point ?
Sorry for lack of information
and here is the part i type is
public class Cust{
string name;
long idenid, uniqueid;
int pts;
customer(){}
customer(string n,long ide, long uni, int pt){
name = n;
idenid = ide;
uniqueid = uni;
pts = pt;
}
FileWriter fstream = new FileWriter("Data.txt", true);
BufferedWriter fbw = new BufferedWriter(fstream);
Cust newCust = new Cust();
newCust.name = memUNTF.getText();
newCust.ic = Long.parseLong(memICTF.getText());
newCust.uniqueID = Long.parseLong(memIDTF.getText());
newCust.pts= points;
fbw.write(newCust.name + " " + newCust.ic + " " + newCust.uniqueID + " " + newCust.point);
fbw.newLine();
fbw.close();
this is the way i text in the data
then the result inside Data.txt is
spencerlim 900419129876 448505 0
Eugene 900419081234 586026 0
when user type in 586026 then it will grab row of eugene
bind into Cust
and update the pts (0 in this case, try to update it into other number eg. 30)
Thx for reply =D
Reading is pretty easy, but updating a text file in-place (ie without rewriting the whole file) is very awkward.
So, you have two options:
Read the whole file, make your changes, and then write the whole file to disk, overwriting the old version; this is quite easy, and will be fast enough for small files, but is not a good idea for very large files.
Use a format that is not a simple text file. A database would be one option (and bear in mind that there is one, Derby, built into the JDK); there are other ways of keeping simple key-value stores on disk (like a HashMap, but in a file), but there's nothing built into the JDK.
You can use OpenCSV with custom separators.
Here's a sample method that updates the info for a specified user:
public static void updateUserInfo(
String userId, // user id
String[] values // new values
) throws IOException{
String fileName = "yourfile.txt.csv";
CSVReader reader = new CSVReader(new FileReader(fileName), ' ');
List<String[]> lines = reader.readAll();
Iterator<String[]> iterator = lines.iterator();
while(iterator.hasNext()){
String[] items = (String[]) iterator.next();
if(items[0].equals(userId)){
for(int i = 0; i < values.length; i++){
String value = values[i];
if(value!=null){
// for every array value that's not null,
// update the corresponding field
items[i+1]=value;
}
}
break;
}
}
new CSVWriter(new FileWriter(fileName), ' ').writeAll(lines);
}
Use InputStream(s) and Reader(s) to read file.
Here is a code snippet that shows how to read file.
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("c:/myfile.txt")));
String line = null;
while ((line = reader.readLine()) != null) {
// do something with the line.
}
Use OutputStream and Writer(s) to write to file. Although you can use random access files, i.e. write to the specific place of the file I do not recommend you to do this. Much easier and robust way is to create new file every time you have to write something. I know that it is probably not the most efficient way, but you do not want to use DB for some reasons... If you have to save and update partial information relatively often and perform search into the file I'd recommend you to use DB. There are very light weight implementations including pure java implementations (e.g. h2: http://www.h2database.com/html/main.html).