Numeric data file sort write Issue - java

I have a data file with the entries (5 numbers per line:
8,1,3,7,9
2,4,7,10,11
9,99,4,7,3
5,1,2,3,17
The complete data file is extremely large but has similar data throughout.
I am trying to read the data line by line from the input file,
Sort the numbers on that line,
Then write the sorted numbers to a new output file.
Rather than storing the entire input file into an array or memory, I want to only store the numbers for each line, one line at a time, sort it, and write those sorted numbers to the next line in the output file. I have come up with an initial way to read and write the smaller data set to a different file, but its writing the array which appears within braces such as [ 1, 3, 7, 8, 9] instead of as 1, 3, 7, 8, 9 . When I figure out what the correct, more efficient way is, I was also planning on creating a seperate class just for the sorting and would read one line at a time from the data file, pass it to the seperate class which would sort it and write it to the output datafile. How can I correctly input each line one at a time into the array, sort it, and write it to the new output datafile?
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Soup {
public static void main(String[] args) throws IOException {
File dir = new File(".");
String source = dir.getCanonicalPath() + File.separator + "Code.txt";
String dest = dir.getCanonicalPath() + File.separator + "Dest.txt";
File fin = new File(source);
FileInputStream fis = new FileInputStream(fin);
BufferedReader in = new BufferedReader(new InputStreamReader(fis));
FileWriter fstream = new FileWriter(dest, true);
BufferedWriter out = new BufferedWriter(fstream);
String aLine = null;
while ((aLine = in.readLine()) != null) {
//Process each line and add output to Dest.txt file
//Arrays.sort(aLine);
String[] strings = aLine.split(",");
int[] numbers = new int[strings.length];
for (int i=0; i < numbers.length; i++)
{
numbers[i] = Integer.parseInt(strings[i]);
}
Arrays.sort(numbers);
System.out.println(Arrays.toString(numbers));
//for(int k=0; k < numbers.length; k++)
//out.writeObject(numbers[k]);
//out.write(aLine);
out.write(Arrays.toString(numbers));
//out.write(numbers
//out.write((numbers));
out.newLine();
}
// do not forget to close the buffer reader
in.close();
// close buffer writer
out.close();

Your Arrays.toString(numbers) adds the brackets. Just replace the brackets with an empty string before you write it to the file -
out.write(Arrays.toString(numbers).replaceAll("\[|\]", ""));

out.write(Arrays.toString(numbers).replaceAll("\[|\]", "")); does not work, error: at java.lang.String.replaceAll(Unknown Source)
Also, I am trying to figure out a better method of performing the sort and write task, Im sure my code is not efficient and am looking for a more efficient way to accomplish the task. I am open to suggestions.

Related

Adler32 generated checksum doesnt match the .txt files checksum

im tasked with written two java programs. One program creates a file called 'userinput.txt', then writes everything the user inputs into the file. Once done a new file is created called 'Checksum.txt' and this file will write down the checksum for the 'userinput.txt' file after reading whats inside of it.
The 2nd program just reads the same 'userinput.txt' file and then generates a checksum and prints it onto the console (i also have to get the program to read the other checksum.txt file and display it int the console to compare the two but i havent gotten around to that yet).
Iv written the program for these two but my problem is they are both different checksum even though they are reading the same file. Im using Adler32 but CRC32 also gives me two different checksums (the one on console is always different to the one stored in checksum.txt) and im not sure whats causing it frankly :/
Here is the code that takes userinput and generates the checksum file:
package attemp2;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.util.zip.Adler32;
import java.util.zip.CheckedInputStream;
public class main {
public static void main(String[] args) throws IOException {
System.out.println("All inputs will be recorded into a sigle file. Enter 'x' when done. A checksum File will aslo be created at the end");
FileWriter fw = new FileWriter("d:/input.txt", false); // clears previous entry in file.
while (true) {
Scanner input = new Scanner(System.in); //get user input
String ch = input.nextLine(); //stores user input
System.out.println(ch); //prints out what user just inputed
if (ch.equals("x")) { //stops running if 'x' is entered
break;
}
BufferedWriter writer = new BufferedWriter(new FileWriter("d:/input.txt", true));
writer.write(ch);
writer.newLine(); // Add new line
writer.close();
}
try {
FileReader reader = new FileReader("d:/input.txt");
BufferedReader br = new BufferedReader(reader);
// read line by line String line;
String read = "";
String line;
while ((line = br.readLine()) != null) {
read = read + line;
//prints out text in file currently
System.out.println(line);
}
//checksum.txt generation
byte buffer[] = read.getBytes();
ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
CheckedInputStream cis = new CheckedInputStream(bais, new Adler32());
byte readBuffer[] = new byte[buffer.length];
cis.read(readBuffer);
FileOutputStream out = new FileOutputStream("d://checksum.txt");
BufferedWriter wrt = new BufferedWriter(new FileWriter("d:/checksum.txt", false));
wrt.write(Long.toString(cis.getChecksum().getValue()));
wrt.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
The code that reads the file and generates a checksum in console:
package check;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;
import java.util.zip.Adler32;
public class CheckSum {
private Adler32 checksum;
private String filepath;
InputStream inputStream;
public CheckSum(String filepath) throws FileNotFoundException{
this.filepath = filepath;
checksum = new Adler32();
inputStream = new FileInputStream(filepath);
}
public long generateChecksum() throws IOException{
int c;
while((c = inputStream.read())!=-1){
checksum.update(c);
}
return checksum.getValue();
}
public void read() throws IOException{
File file = new File(filepath);
BufferedReader br = new BufferedReader(new FileReader(file));
String st;
while ((st = br.readLine()) != null) {
System.out.println(st);
}
}
public static void main(String[] args) throws Exception{
Scanner scanner = new Scanner(System.in);
String filepath = "d:/input.txt";
CheckSum checksum = new CheckSum(filepath);
checksum.read();
System.out.println("For the file: "+filepath);
System.out.println("The checksum generated is: "+checksum.generateChecksum());
}
}
Please learn how to use a debugger, see What is a debugger and how can it help me diagnose problems?.
That being said, you have some problems with your code. First you are calculating the checksum on an empty array. When you write:
byte readBuffer[] = new byte[buffer.length];
cis.read(readBuffer);
you are reading an empty array of the size of the buffer array. You don't need to create a new array. In fact, you should read the buffer array you already have, since there is your content. In this case you just write:
cis.read(buffer);
The next problem is that you are using readers and writers, which are used for text/string files, but checksum/hash algorithm usually works on byte level. This can result in several errors like encoding (ASCII, UTF-8, etc. stuff) and line-termination issues (\n vs. \r\n vs. \r).
However, in this case you are working with readLine(). This method does not return the line-termination at the end, see the documentation of readLine():
Returns:
A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached
So, what you are reading from the file is not the same what is actually in the file. But your CheckSum class reads every byte in the saved file (as it should). Assume you enter only the string "abc". Your first calculation will be run on the 3 bytes long array with the values:
[97,98,99]
The line-termination is ignored by the readLine() method, but it is still present in the file. When you check the checksum with the second program, the InputStream you are using will see the following bytes:
[97,98,99,10]
(The bytes at the end depends on the OS you are using)
As you see you run the checksum on different byte arrays, resulting in different checksum values. So, make sure you are running the checksum checks on the same byte array content (or InputStream content) to get the same checksum in both applications.

How to take a specific line from a text file and read it into an array? (Java)

I've been trying to code a quiz game in javafx where I store the questions on a text file and then randomize a number then use it to call the line of the same number on the text file and read it into an array.
After looking online I can only seem to find how to read a text file line by line instead of a specific line. I also use the following code to read the text file but am unsure where to go on from there.
File file = new File("/Users/administrator/Desktop/Short Questions.txt");
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line;
This may help you
You need to change file path as per your file location
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("C:\\Users\\everestek22\\Desktop\\Invoice.txt"));
String[] strArray =
bufferedReader.lines().map(String::new).toArray(String[]::new);
// String line = bufferedReader.readLine();
// while (line != null) {
// System.out.println(line);
// line = bufferedReader.readLine();
// String[] strArray = bufferedReader.lines().map(String::new).toArray(String[]::new);
// }
bufferedReader.close();
for (String s : strArray) {
System.out.println(s);
}
}
}
Don't bother trying to read specific lines from the file, just read all the lines from the file, then lookup your question by index in the resultant list.
List<String> questions = Files.readAllLines(
Paths.get("<your file path>")
);
Then you could choose a question at random:
Random random = new Random(42);
int randomQuestionIndex = random.nextInt(questions.size());
String randomQuestion = questions.get(randomQuestionIndex);
Using 42 as the seed to the random number generator makes the random sequence repeatable, which is good for testing. To have it truly psuedo-random, then remove the seed (e.g. just new Random());
If the structure of the data you wish to read is complex, then use a helper library such as Jackson to store and retrieve the data as serialized JSON objects. If it is even more complex, then a database can be used.
If you have a really large file and you know the position in the file of each specific thing you wish to read, then you can use a random access file for lookup. For example, if the all the questions in the file are exactly the same length and you know how many questions are stored there, then a random access file might be used fairly easily. But, from your description of what you need to do, this is likely not the case, and the simpler solution of reading everything rather than using a random access file is better.

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1 (Am I saving my file wrong in Java)?

I am trying to save a file line by line of a file in the form of:
number -> number
number -> number
number -> number
number -> number
etc. etc.
I have saved the file as the following (in Netbeans)
BufferedReader in = new BufferedReader(new FileReader("C:\\Users\\jon\\Desktop\\data.txt"));
String str=null;
ArrayList<String> lines = new ArrayList<String>();
while((str = in.readLine()) != null){
lines.add(str);
}
String[] graph = lines.toArray(new String[lines.size()]);
I get this error when I run my function (code is syntax past storing the file line by line):
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
-1
at different places along my function. I'm assuming this is a problem because I am storing my file, wrong? Why?
So you just want to read in line by line?
I'd use a file and a scanner, also for the array using an arraylist might be easier.
imports you will have to use
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
also use throws IOException
File fileData = new File("C:\\Users\\jon\\Desktop\\data.txt");
ArrayList<String> readFile = new ArrayList();
if (f.exists() && f.isFile() ) {
Scanner sc = new Scanner(fileData);
while (sc.hasNext()) {
String line = sc.next();
readFile.add(line);
}
sc.close();
}
This should work if you want to read in the file, but you mentioned reading them in as numbers, to do this we must use an arraylist of Integers and we need to parse the read in line to Integers, this can be simply done by replacing ArrayList<String> readFile = new ArrayList();
with ArrayList<Integer> readFile = new ArrayList();
AND readFile.add(line); with readFile.add(Integer.parseInt(line));
I hope this will help you out.

Creating a constructor to read a txt file

I am creating a program that will produces the statistics of a baseball team
i am trying to create a constructor to read the file into the teamName instance variable and the battingAverages array.
the txt file contains the one word name of the team followed by 20 batting averages.
"Tars 0.592 0.427 0.194 0.445 0.127 0.483 0.352 0.190 0.335 0.207 0.116 0.387 0.243 0.225 0.401 0.382 0.556 0.319 0.475 0.279 "
I am struggling to find how to go about this and get it started?
I ran this and this might be close to what you want. Instead of making a confusing constructor, make a private method that the constructor will call to read in the file into the array.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class Baseball {
private File textFile;
private Scanner input;
private String teamName;
//this will only work if you know there will be 20 entries everytime
//otherwise I recommend loading the data into an ArrayList
private double []battingAvgs = new double[20];
public Baseball(String file){
textFile = new File(file);
readInFile(textFile);
}
//private method that reads in the file into an array
private void readInFile(File textFile){
try {
input = new Scanner(textFile);
//read first string into variable teamName
teamName = input.next();
int i=0;
//iterate through rest of file adding it to an ArrayList
while(input.hasNext()){
battingAvgs[i] = input.nextDouble();
i++;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
//print out array
public void printArray(){
for(Double a: battingAvgs){
System.out.println(a);
}
}
}
Well, if these are all on one line in a specific file then what you could do is construct a bufferedreader to read the first line of your file, split the line based on spaces, and then parse the teamName and batting averages out.
BufferedReader br = new BufferedReader(new FileReader("myfile.txt"));
String[] line = br.readLine().split(" ");
br.close();
teamName = line[0];
battingAverages = new int[20];
for(int i = 0; i < 20; i++)
battingAverages[i] = Integer.parseInt(line[i+1]);
These might throw IOExceptions, which you will need to catch. I think Java 7 has a method to automatically handle these kinds of errors (not sure about this), but as I am new to Java 7's added functionality, I would just manually check for those exceptions.
You need to use the BufferedReader, FileInputStream, and InputStreamReader. Your file.txt should have the batting averages on every line, as shown below.
0.592
0.427
0.194
Here is an example of a class that when created, it will read a text file line by line and add each line to the array list:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.*;
public class Class {
ArrayList<Double> averages;
public Class() {
averages = new ArrayList<Double>();
try {
FileInputStream in = new FileInputStream("inputFile.txt"); //your file path/name
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String strLine;
while((strLine = br.readLine())!= null) averages.add(Double.parseDouble(strLine));
}catch(Exception e){
System.out.println(e);
}
}
}
Hope this helps
Try using the Scanner class.
File file=new File("TestFile.txt"); //Create a new file
Scanner scan=new Scanner(file);//Create a Scanner object (Throws FileNotFoundException)
if(scan.hasNext()) //Check to make sure that there is actually something in the file.
{
String line=scan.nextLine(); //Read the line of data
String[] array=line.split(" "); //Split line into the different parts
teamName=array[0]; //The team name is located in the first index of the array
battingAverages=new double[array.length-1];//Create a new array to hold the batting average values
for(int i=0;i<battingAverages.length;i++) //Loop through all of the averages
{
double average=Double.parseDouble(array[i+1]);//Convert the string object into a double
battingAverages[i]=average; //Add the converted average to the array
}
System.out.print(teamName+" "+Arrays.toString(battingAverages)); //[Optional] Print out the resulting values
}

Write CSV file column-by-column

I was searching for an answer for this but I didn't find it. Does anyone have a solution for this kind of problem. I have a set of text variables that I have to write into the .CSV file using Java. I am currently doing a project with JavaScript that calls for Java. This is a function that I have right now that does the job well and writes the text into .CSV line by line.
function writeFile(filename, data)
{
try
{
//write the data
out = new java.io.BufferedWriter(new java.io.FileWriter(filename, true));
out.newLine();
out.write(data);
out.close();
out=null;
}
catch(e) //catch and report any errors
{
alert(""+e);
}
}
But now I have to write parts of text one by one like the example bellow.
first0,second0,third0
first1,second1,third1
first2,second2,third2
.
.
.
first9,second9,third9
So the algorithm goes like this. The function writes first0 with comma then goes to the next line writes first1, goes to next line writes first2 and so one until first9. After that part is done the script goes to the beginning of the file and writes second0 behind the comma, goes to the next line and writes second1 behind the comma and so on. You get the idea.
So now I need java
You might want to consider using Super CSV to write the CSV file. As well as taking care of escaping embedded double-quotes and commas, it offers a range of writing implementations that write from arrays/Lists, Maps or even POJOs, which means you can easily try out your ideas.
If you wanted to keep it really simple, you can assemble your CSV file in a two-dimensional array. This allows to to assemble it column-first, and then write the whole thing to CSV when it's ready.
package example;
import java.io.FileWriter;
import java.io.IOException;
import org.supercsv.io.CsvListWriter;
import org.supercsv.io.ICsvListWriter;
import org.supercsv.prefs.CsvPreference;
public class ColumnFirst {
public static void main(String[] args) {
// you can assemble this 2D array however you want
final String[][] csvMatrix = new String[3][3];
csvMatrix[0][0] = "first0";
csvMatrix[0][1] = "second0";
csvMatrix[0][2] = "third0";
csvMatrix[1][0] = "first1";
csvMatrix[1][1] = "second1";
csvMatrix[1][2] = "third1";
csvMatrix[2][0] = "first2";
csvMatrix[2][1] = "second2";
csvMatrix[2][2] = "third2";
writeCsv(csvMatrix);
}
private static void writeCsv(String[][] csvMatrix) {
ICsvListWriter csvWriter = null;
try {
csvWriter = new CsvListWriter(new FileWriter("out.csv"),
CsvPreference.STANDARD_PREFERENCE);
for (int i = 0; i < csvMatrix.length; i++) {
csvWriter.write(csvMatrix[i]);
}
} catch (IOException e) {
e.printStackTrace(); // TODO handle exception properly
} finally {
try {
csvWriter.close();
} catch (IOException e) {
}
}
}
}
Output:
first0,second0,third0
first1,second1,third1
first2,second2,third2
Here is my solution to the problem. You don't need to keep the whole data in the buffer thanks to the low-level random access file mechanisms. You would still need to load your records one by one:
package file.csv;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.List;
public class CsvColumnWriter {
public static void main(String args[]) throws Exception{
CsvColumnWriter csvWriter = new CsvColumnWriter(new File("d:\\csv.txt"), new File("d:\\csv.work.txt"), 3);
csvWriter.writeNextCol(Arrays.asList(new String[]{"first0", "first1", "first2"}));
csvWriter.writeNextCol(Arrays.asList(new String[]{"second0", "second1", "second2"}));
csvWriter.writeNextCol(Arrays.asList(new String[]{"third0", "third1", "third2"}));
}
public void writeNextCol(List<String> colOfValues) throws IOException{
// we are going to create a new target file so we have to first
// create a duplicated version
copyFile(targetFile, workFile);
this.targetStream = new BufferedOutputStream(new FileOutputStream(targetFile));
int lineNo = 0;
for(String nextColValue: colOfValues){
String nextChunk = nextColValue + ",";
// before we add the next chunk to the current line,
// we must retrieve the line from the duplicated file based on its the ofset and length
int lineOfset = findLineOfset(lineNo);
workRndAccFile.seek(lineOfset);
int bytesToRead = lineInBytes[lineNo];
byte[] curLineBytes = new byte[bytesToRead];
workRndAccFile.read(curLineBytes);
// now, we write the previous version of the line fetched from the
// duplicated file plus the new chunk plus a 'new line' character
targetStream.write(curLineBytes);
targetStream.write(nextChunk.getBytes());
targetStream.write("\n".getBytes());
// update the length of the line
lineInBytes[lineNo] += nextChunk.getBytes().length;
lineNo++;
}
// Though I have not done it myself but obviously some code should be added here to care for the cases where
// less column values have been provided in this method than the total number of lines
targetStream.flush();
workFile.delete();
firstColWritten = true;
}
// finds the byte ofset of the given line in the duplicated file
private int findLineOfset(int lineNo) {
int ofset = 0;
for(int i = 0; i < lineNo; i++)
ofset += lineInBytes[lineNo] +
(firstColWritten? 1:0); // 1 byte is added for '\n' if at least one column has been written
return ofset;
}
// helper method for file copy operation
public static void copyFile( File from, File to ) throws IOException {
FileChannel in = new FileInputStream( from ).getChannel();
FileChannel out = new FileOutputStream( to ).getChannel();
out.transferFrom( in, 0, in.size() );
}
public CsvColumnWriter(File targetFile, File workFile, int lines) throws Exception{
this.targetFile = targetFile;
this.workFile = workFile;
workFile.createNewFile();
this.workRndAccFile = new RandomAccessFile(workFile, "rw");
lineInBytes = new int[lines];
for(int i = 0; i < lines; i++)
lineInBytes[i] = 0;
firstColWritten = false;
}
private File targetFile;
private File workFile;
private int[] lineInBytes;
private OutputStream targetStream;
private RandomAccessFile workRndAccFile;
private boolean firstColWritten;
}
I'm just going ahead and assume that you have some freedom how to fulfill this task. To my knowledge, you can't 'insert' text into a file. You can only do it by reading the file completely, change it in-memory, and then write back the result into the file.
So it would be better if you invert your data structure in-memory and then write it. If your data object is a matrix, just transpose it, so that it is in the format you want to write.
How about this
Scanner input = new Scanner(System.in);
String[] lines = new String[9];
for (int j = 0; j < 2; j++) {
for (int i = 0; i < 9; i++) {
lines[i] += (String) input.nextLine() + ",";
}
}
for (int i = 0; i < 9; i++) {
lines[i] += (String) input.nextLine();
}
Based on your requirements of not losing any data if an error occurs, perhaps you should rethink the design and use an embedded database (there is a discussion of the merits of various embedded databases at Embedded java databases). You would just need a single table in the database.
I suggest this because in your original question it sounds like you are trying to use a CSV file like a database where you can update the columns of any row in any order. In that case, why not just bite the bullet and use a real database.
Anyhow, once you have all the columns and rows of your table filled in, export the database to a CSV file in "text file order" row1-col1, row1-col2 ... row2-col1 etc.
If an error occurs during the building of the database, or the exporting of the CSV file at least you will still have all the data from the previous run and can try again.

Categories

Resources