Writing/Reading from a randomaccesfile - java

I have a project where I am to write data (strings and ints) into a binary random access file, and read the data in a separate class. The problem I have is I'm trying to iterate through the file and read the data in a specific order (int, String, String, int), however the Strings are various byte sizes.
I am getting an EOFException but cannot figure out why.
Here is the class which writes the data. Part of the requirements is to limit the number of bytes for the Strings and catch a user defined exception if they are exceeded.
import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.ArrayList;
import java.io.File;
public class QuestionBank {
private RandomAccessFile file;
private ArrayList <Questions> listQuestions;
public QuestionBank(){
file = null;
listQuestions = new ArrayList<Questions>();
}
public void storeQuestion (Questions ques) throws IOException {
ques = new Questions(ques.getQuesIDNum(), ques.getQuestion(), ques.getAnswer(), ques.getValue());
listQuestions.add(ques);
byte[] quesBytes = ques.getQuestion().getBytes("UTF-8");
byte[] ansBytes = ques.getAnswer().getBytes("UTF-8");
try {
file = new RandomAccessFile(new File("Question.bin"), "rw");
long fileSize = file.length();
file.seek(fileSize);
file.writeInt(ques.getQuesIDNum());
file.writeUTF(ques.getQuestion());
for (int i = 0; i <= 50 - ques.getQuestion().length(); i++){
file.writeByte(50);
}
if (quesBytes.length > 50) {
throw new ByteSizeException("Question has too many bytes");
}
file.writeUTF(ques.getAnswer());
for (int i = 0; i <= 20 - ques.getAnswer().length(); i++){
file.writeByte(20);
}
if (ansBytes.length > 20) {
throw new ByteSizeException("Answer has too many bytes");
}
file.writeInt(ques.getValue());
file.close();
} catch (IOException e) {
System.out.println("I/O Exception Found");
} catch (ByteSizeException eb) {
System.out.println("String has too many bytes");
}
}
Here is the class which reads the file.
import java.util.ArrayList;
import java.util.Random;
import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.File;
public class TriviaGame {
public static final int RECORD = 78;
private ArrayList<Questions> quesList;
private int IDNum;
private String question;
private String answer;
private int points;
public TriviaGame() {
quesList = new ArrayList<Questions>();
IDNum = 0;
question = "";
answer = "";
points = 0;
}
public void read(){
try {
RandomAccessFile file;
file = new RandomAccessFile(new File("Question.bin"), "r");
long fileSize = file.length();
long numRecords = fileSize/RECORD;
file.seek(0);
for (int i = 0; i < numRecords; i++){
IDNum = file.readInt();
question = file.readUTF();
answer = file.readUTF();
points = file.readInt();
System.out.println("ID: " + IDNum + " Question: " + question + " Answer: " + answer + " Points: " + points);
}
file.close();
} catch (IOException e) {
System.out.println(e.getClass());
System.out.println("I/O Exception found");
}
}
}
Thanks

file.writeUTF(ques.getQuestion());
Here you have written the question.
for (int i = 0; i <= 50 - ques.getQuestion().length(); i++){
file.writeByte(50);
}
if (quesBytes.length > 50) {
throw new ByteSizeException("Question has too many bytes");
}
Here for some unknown reason you are padding the question to 50 bytes. Remove. Same with the answer. You are using readUTF() to read both of these, so all you need is writeUTF() to write them. No padding required.
Or, if you insist on this padding, you have to skip over it when reading: after the first readUTF(), you need to skip over the padding.

Related

How to do Spring batch record partition on large file?

How to do Spring batch record partition on large file?
Example say if I have 100 records in file, I need to improve spring batch processing speed creating 1 thread each 10 records. How to do it? Currently I am using MultiResourcePartitioner. But this partitioner creating partition per file. So no performance impact on one large file. How to do it?
Yes I need to write custom partition like https://mkyong.com/spring-batch/spring-batch-partitioning-example/ but nothing working. need help
Thread 1 - Process from 1 to 10
Thread 2 - Process from 11 to 20
Thread 3 - Process from 21 to 30
......
Thread 9 - Process from 81 to 90
Thread 10 - Process from 91 to 100
Hi I resolved this problem myself by splitting File to smaller chunks and use the MultiResourcePartitioner to read chunk files.
This is below is my splitter program
package com.cookmedical.batch.utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FileSplitter {
private static Logger logger = LoggerFactory.getLogger(FileSplitter.class);
public static String NEWLINE = System.getProperty("line.separator");
public static int MAX_FILE_RECORDS = 50;
public void split(File masterFile) throws IOException {
try {
// opens the file in a string buffer
BufferedReader bufferedReader = new BufferedReader(new FileReader(masterFile));
StringBuffer stringBuffer = new StringBuffer();
// performs the splitting
String fileLine;
int fileLineNumber = 0;
int rowCounter = 0;
int partitionCounter = 1;
String fileHeader = "";
String parentFolder = masterFile.getParent();
String fileName = StringUtils.substringBeforeLast(masterFile.getName(), ".csv") + "_";
while ((fileLine = bufferedReader.readLine()) != null) {
if (fileLineNumber == 0) {
fileHeader = fileLine;
}
if (rowCounter >= MAX_FILE_RECORDS) {
saveFilePartition(parentFolder, fileName+partitionCounter+".csv",masterFile.lastModified(),stringBuffer);
rowCounter = 0;
partitionCounter++;
stringBuffer = new StringBuffer();
stringBuffer.append(fileHeader);
stringBuffer.append(NEWLINE);
stringBuffer.append(fileLine);
stringBuffer.append(NEWLINE);
} else {
stringBuffer.append(fileLine);
stringBuffer.append(NEWLINE);
}
rowCounter++;
fileLineNumber++;
}
saveFilePartition(parentFolder, fileName+partitionCounter+".csv",masterFile.lastModified(),stringBuffer);
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void saveFilePartition(String parentFolder, String fileName, long lastModifiedTime, StringBuffer fileContent) throws IOException {
File splitFolder = new File(parentFolder + File.separator + "splitFolder");
splitFolder.mkdir();
FileWriter output = null;
try {
splitFolder = new File(splitFolder + File.separator + fileName);
splitFolder.setLastModified(lastModifiedTime);
output = new FileWriter(splitFolder);
output.write(fileContent.toString());
// System.out.println("file " + file.getAbsolutePath() +
// " written");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
output.close();
} catch (IOException e) {
// do nothing the file wasn't been even opened
}
}
}
}

How to count occurrence of Polish characters in .txt file

I have to prepare a .txt file and count how many times each character of alphabet occurs in the file. I've found a very nice piece of code, but unfortunately, it doesn't work with Polish characters like ą,ę,ć,ó,ż,ź. Even though I put them in the array, for some reason they are not found in the .txt file so the output is 0.
Does anyone know why? Maybe I should count them differently, with "Switch" or something similar.
Before anyone asks - yes, the .txt file is saved with UTF-8 :)
public static void main(String[] args) throws FileNotFoundException {
int ch;
BufferedReader reader;
try {
int counter = 0;
for (char a : "AĄĆĘÓBCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray()) {
reader = new BufferedReader(new FileReader("C:\\Users\\User\\Desktop\\pan.txt"));
char toSearch = a;
counter = 0;
try {
while ((ch = reader.read()) != -1) {
if (a == Character.toUpperCase((char) ch)) {
counter++;
}
}
} catch (IOException e) {
System.out.println("Error");
e.printStackTrace();
}
System.out.println(toSearch + " occurs " + counter);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Looks like your problem related to encoding and default system charset
try to change reader variable to this
InputStreamReader reader = new InputStreamReader(new FileInputStream("C:\\Users\\User\\Desktop\\pan.txt"), "UTF-8");
try this:
I suggest that you use NIO and this code I have written for you using NIO, RandomAccessFile and MappedByteBuffer that is faster:
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.HashMap;
import java.util.Map;
public class FileReadNio
{
public static void main(String[] args) throws IOException
{
Map<Character, Integer> charCountMap = new HashMap<>();
RandomAccessFile rndFile = new RandomAccessFile
("c:\\test123.txt", "r");
FileChannel inChannel = rndFile.getChannel();
MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
buffer.load();
for (int i = 0; i < buffer.limit(); i++)
{
char c = (char) buffer.get();
if (charCountMap.get(c) != null) {
int cnt = charCountMap.get(c);
charCountMap.put(c, ++cnt);
}
else
{
charCountMap.put(c, 1);
}
}
for (Map.Entry<Character,Integer> characterIntegerEntry : charCountMap.entrySet()) {
System.out.printf("char: %s :: count=%d", characterIntegerEntry.getKey(), characterIntegerEntry.getValue());
System.out.println();
}
buffer.clear();
inChannel.close();
rndFile.close();
}
}

Java - .csv file as input

My program stimulates FCFS scheduling algorithm. It takes a .csv file as input and output the average waiting time. I have trouble with inputting the file. This is the error that i get when i ran the code:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at main.FCFS.main(FCFS.java:16)
What am I doing wrong? I cannot seems to figure it out. Please help.
package main;
//programming FCFS scheduling algorithm
import java.util.Scanner;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.File;
import java.io.FileInputStream;
public class FCFS {
public static void main(String[] args) throws FileNotFoundException {
// To Store Name of the file to be opened
String file = args[0];
int i = 0, n;
double AWT = 0, ATT = 0;
int AT[] = new int[100];
int BT[] = new int[100];
int WT[] = new int[100];
int TAT[] = new int[100];
int PID[] = new int[100];
// To open file in read mode
FileInputStream fin = null;
// To read input(file name) from standard input stream
Scanner s = new Scanner(new File("/Users/SLO/ex.csv"));
// To hold each single record obtained from CSV file
String oneRecord = "";
try {
// Open the CSV file for reading
fin = new FileInputStream(file);
// To read from CSV file
s = new Scanner(fin);
// Loop until all the records in CSV file are read
while (s.hasNextLine()) {
oneRecord = s.nextLine();
// Split record into fields using comma as separator
String[] details = oneRecord.split(",");
PID[i] = Integer.parseInt(details[0]);
AT[i] = Integer.parseInt(details[1]);
BT[i] = Integer.parseInt(details[2]);
System.out.printf("Process Id=%d\tArrival Time=%d\tBurst Time=%d\n", PID[i], AT[i], BT[i]);
i++;
}
WT[0] = 0;
for (n = 1; n < i; n++) {
WT[n] = WT[n - 1] + BT[n - 1];
WT[n] = WT[n] - AT[n];
}
for (n = 0; n < i; n++) {
TAT[n] = WT[n] + BT[n];
AWT = AWT + WT[n];
ATT = ATT + TAT[n];
}
System.out.println(" PROCESS BT WT TAT ");
for (n = 0; n < i; n++) {
System.out.println(" " + PID[n] + " " + BT[n] + " " + WT[n] + " " + TAT[n]);
}
System.out.println("Avg waiting time=" + AWT / i);
System.out.println("Avg waiting time=" + ATT / i);
} catch (FileNotFoundException e) {
System.out.printf("There is no CSV file with the name %s", file);
}
finally {
if (fin != null) {
try {
fin.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Well, an ArrayIndexOutOfBoundsException is thrown if there are no arguments, because you access the empty array at a non existing index. Add the following lines to check if the argument is passed correctly:
...
public static void main(String[] args) throws FileNotFoundException {
if (args.length == 0)
throw new IllegalArgumentException("Missing mandatory file name in argument list");
// To Store Name of the file to be opened
String file = args[0];
...
If the missing argument ist the reason for the failure, check out https://docs.oracle.com/javase/tutorial/essential/environment/cmdLineArgs.html to find out how to pass it properly.

JAVA - reading from text file, recognizing new lines

I have a task to read a text file with several lines, after that I need to count every character's UNICODE value, so the sum of "hello" is 532 and for "how are you" is 1059 and so on, every string begins on new line in the .txt document and so far so good.
But for every line I need to print only its own value, and the way my code works, it adds every line's value and I cant get my head around a way to stop it when the end of the lxtine comes so it looks something like:
*read line
*count char values
*add up
*print them
*start over for the next line, and so
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.String;
import java.util.Arrays;
public class SumLines {
public static void main(String[] args) {
String filePath = "/home/lines.txt";
String readLine;
int sum = 0;
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))) {
while ((readLine = bufferedReader.readLine()) != null) {
char[] array = new char[readLine.length()];
System.out.println(readLine);
for (int i = 0; i < readLine.length(); i++) {
Arrays.fill(array, readLine.trim().charAt(i));
sum += (int) array[i];
System.out.print(sum + " ");
}
}
} catch (IOException e) {
System.out.println("Error.\n Invalid or missing file.");
e.printStackTrace();
}
System.out.println("\n*** final " + sum);
}
}
If I understood correctly, for the input:
hello
how are you
You would like to get something like this as output:
hello 532
how are you 1059
*** final 1591
For this, you need to make some modifications to your code:
In addition to calculating the sum of characters values per line, keep another sum of the total of all lines
For each input line, print the line followed by the sum of character values
You don't need an array at all
It's better to trim the input line once, instead of for every character
Like this:
int total = 0;
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))) {
String readLine;
while ((readLine = bufferedReader.readLine()) != null) {
String trimmed = readLine.trim();
int sum = 0;
for (int i = 0; i < trimmed.length(); i++) {
sum += (int) trimmed.charAt(i);
}
System.out.println(readLine + " " + sum);
total += sum;
}
} catch (IOException e) {
System.out.println("Error.\n Invalid or missing file.");
e.printStackTrace();
}
System.out.println("\n*** final " + total);
After your for loop, set sum to 0. If you want to print the total sum, then you need another variable, say t.
Like this:
for (int i = 0; i < readLine.length(); i++) {
Arrays.fill(array, readLine.trim().charAt(i));
sum += (int) array[i];
System.out.print(sum + " ");
}
t=t+sum;
sum=0;
Then print t at the end.
A simple solution would be to limit the scope of the sum variable. That way, values will not persist between runs:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.String;
import java.util.Arrays;
public class SumLines {
public static void main(String[] args) {
String filePath = "/home/lines.txt";
String readLine;
int totalSum = 0;
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))) {
String readLine;
while ((readLine = bufferedReader.readLine()) != null) {
int sum = 0;
for (int i = 0; i < readLine.length(); i++) {
sum += (int) readLine.charAt(i);
}
System.out.println(readLine + ": " + sum);
totalSum += sum;
}
} catch (IOException e) {
System.out.println("Error.\n Invalid or missing file.");
e.printStackTrace();
}
System.out.println("\n*** final " + totalSum);
}
}
Also, you don't have to use such complicated stuff just to get the Unicode value of a char. I made some improvements.
Have two variables, one for final sum and one for line sum.
public class SumLines {
public static void main(String[] args) {
String filePath = "/home/lines.txt";
String readLine;
int totalSum = 0;
int lineSum = 0
try (BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath))) {
while ((readLine = bufferedReader.readLine()) != null) {
char[] array = new char[readLine.length()];
System.out.println(readLine);
for (int i = 0; i < readLine.length(); i++) {
Arrays.fill(array, readLine.trim().charAt(i));
lineSum += (int) array[i];
System.out.print(lineSum + " ");
}
totalSum += lineSum + totalSum;
lineSum = 0;
}
} catch (IOException e) {
System.out.println("Error.\n Invalid or missing file.");
e.printStackTrace();
}
System.out.println("\n*** final " + totalSum);
}
}

Reading from one file using FileInputStream and writing to another file using FileOutputStream

I was trying to read from one file and write the bytes read to another file using the classes specified in the title.I successfully did it but while i was trying to try different things i came across a problem which i do not understand.
Here is the code
import java.io.*;
public class FileInputStreamDemo {
public static void main(String[] args)
throws Exception {
// TODO Auto-generated method stub
int size;
InputStream f = new
FileInputStream("G:/Eclipse Workspace/FileInputStream Demo/src/FileInputStreamDemo.java");
System.out.println("Total available bytes: " + (size = f.available()));
/*int n=size/40;
System.out.println("first " + n + " bytes of file one read() at a time");
for (int i=0;i<n;i++)
{
System.out.print((char) f.read());
}
System.out.println("\n Still available: " + f.available());
System.out.println("reading the next" + n + "with one read(b[])");
byte b[] = new byte[n]; */
/*for(int i=0;i<size;i++)
{
System.out.print((char) f.read());
}*/
OutputStream f1 = new
FileOutputStream("G:/Eclipse Workspace/FileInputStream Demo/test.txt");
for (int count = 0; count < size; count++) {
f1.write(f.read());
}
for (int i = 0; i < size; i++) {
System.out.print(f.read());
}
f.close();
f1.close();
}
}
The problem that i am talking about is that when i first read from the FileInputStream object f i.e f.read() and write it to the f1 i.e FileOutputStream object it goes on to do what it is meant to do ,but when i try to read it again it returns -1. why so ?
Use RandomAccessFile and seek(0) method to come back at the beginning.
RandomAccessFile file = new RandomAccessFile(new File("G:/Eclipse Workspace/FileInputStream Demo/src/FileInputStreamDemo.java"), "r");
Here is sample code:
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
public class FileInputStreamDemo {
public static void main(String[] args) throws Exception {
long size;
File file = new File("D:/Workspace/JavaProject/src/com/test/FileInputStreamDemo.java");
RandomAccessFile f = new RandomAccessFile(file, "r");
System.out.println("Total available bytes: " + (size = file.length()));
OutputStream f1 = new FileOutputStream(new File(
"D:/Workspace/JavaProject/resources/test.txt"));
for (int count = 0; count < size; count++) {
f1.write(f.read());
}
f.seek(0);
for (int i = 0; i < size; i++) {
System.out.print((char)f.read());
}
f.close();
f1.close();
}
}

Categories

Resources