Print last couple of lines in text file [duplicate] - java

This question already has answers here:
Java IO implementation of unix/linux "tail -f"
(9 answers)
Closed 8 years ago.
I have a text file that I first want to print the last 6 lines of, and then to detect when a new line has been added so that it will keep updating the screen with recent activity. The idea is that I'm trying to display six recent transactions made in my program.
The problem I am currently encountering is that it keeps printing the first (not last) six lines in the text file, when I want it to be the other way around.
Here is my sample code:
BufferedReader in = new BufferedReader(new FileReader("transaction-list.txt"));
System.out.println();
System.out.println("SIX MOST RECENT TRANSACTIONS:");
System.out.println();
String line;
for (int i=0; i<6;i++){
line=in.readLine();
System.out.println(line);
}
in.close();
}catch (IOException e){
e.printStackTrace();
}
break;

You have to save the lines into String Array. and after reading whole file just print Array. just remember where to start the reading of saved array..
BufferedReader in = new BufferedReader(new FileReader("transaction-list.txt"));
System.out.println();
System.out.println("SIX MOST RECENT TRANSACTIONS:");
System.out.println();
String[] last6 = new String[6];
int count=0;
while(in.ready()){
last6[count++%6]=in.readLine();
}
for (int i=0; i<6;i++){
System.out.println(last6[(i+count)%6]);
}
in.close();

Your currently logic only reads the first 6 lines and print it, basically you can read all lines into a list and remove those lines you don't need. Check following post:
How to read last 5 lines of a .txt file into java

While there are 4 other answers, I don't think any address both your points: (1) to print the last 6 lines and (2) then keep monitoring the file and printing new lines.
I also think you should keep it simple to better convey your code's intent and remove bug risk:
just use a BufferedReader rather than RandomAccessFile - this is what BufferedReader is for
instead of using an array just use a FIFO Queue like ArrayDeque<String> - this is a perfect use case for it and the "ringbuffer" implementation is fully encapsulated inside ArrayDeque
A barebones implementation which does all this would be something like:
public static void MonitorFile(String filePath)
throws FileNotFoundException, IOException, InterruptedException
{
// Used for demo only: count lines after init to exit function after n new lines
int newLineCount = 0;
// constants
final int INITIAL_LINE_LIMIT = 6;
final int POLLING_INTERVAL = 1000;
// file readers
FileReader file = new FileReader(filePath);
BufferedReader fr = new BufferedReader(file);
// read-and-monitor loop
boolean initialising = true;
Queue<String> lineBuffer = new ArrayDeque<String>(INITIAL_LINE_LIMIT);
int lineCount = 0;
while (true) {
String line= fr.readLine();
if (line != null)
{
if (initialising) { // buffer
lineBuffer.add(line);
if (++lineCount > INITIAL_LINE_LIMIT) lineBuffer.remove();
}
else { // print
System.out.printf("%d %s%n", ++lineCount, line);
newLineCount++;
}
}
else
{
// No more lines, so dump buffer and/or start monitoring
if (initialising)
{
initialising = false;
// reset the line numbers for printing
lineCount = Math.max(0, lineCount - INITIAL_LINE_LIMIT);
// print out the buffered lines
while((line = lineBuffer.poll()) != null)
System.out.printf("%d %s%n", ++lineCount, line);
System.out.println("finished pre-loading file: now monitoring changes");
}
// Wait and try and read again.
if (newLineCount > 2) break; // demo only: terminate after 2 new lines
else Thread.sleep(POLLING_INTERVAL);
}
}
}
Points to consider:
For what it's worth, I would pass the BufferedReader in as a parameter so this becomes more generalised,
This needs some kind of cancellation so it doesn't monitor forever.
Rather than polling and sleeping your thread you could also use file change monitoring, but that code would be more complex than is suitable for this answer.
The above code gives the following output
2 test line b
3 test line c
4 test line d
5 test line e
6 test line f
7 test line g
finished pre-loading file: now monitoring changes
8 test line h
9 test line i
10 test line j
11 test line k

Related

java collections framework - reading input and outputting lines floor(n/2),...,n-1

So I'm trying to learn java and I've been given some code and a task of questions to complete by editing the given code. I'm stumped about one question in particular because I don't understand at all what it's asking me to do. I was wondering if I could get some help or a push in the right direction. Any links to resources that would help me would also be really appreciated.
Read the input one line at a time until you have read all n lines and imagine these lines are numbered 0,...,n-1. Next output lines floor(n/2),...,n-1 followed by lines 0,..,.floor(n/2)-1.
This is the main part of the code I'm given but the rest of it can be found here: https://pastebin.com/4ZatEat8
public static void main(String[] args) {
try {
BufferedReader r;
PrintWriter w;
if (args.length == 0) {
r = new BufferedReader(new InputStreamReader(System.in));
w = new PrintWriter(System.out);
} else if (args.length == 1) {
r = new BufferedReader(new FileReader(args[0]));
w = new PrintWriter(System.out);
} else {
r = new BufferedReader(new FileReader(args[0]));
w = new PrintWriter(new FileWriter(args[1]));
}
long start = System.nanoTime();
doIt(r, w);
w.flush();
long stop = System.nanoTime();
System.out.println("Execution time: " + 10e-9 * (stop-start));
} catch (IOException e) {
System.err.println(e);
System.exit(-1);
}
}
}
I guess it wants you to read a whole file first and then print the lines in specific asked order.
Let's take an example, Suppose you have a temp.txt file with 5 lines like below:
A
B
C
D
E
Now, you need to read all the lines of this temp.txt. You can create an ArrayList object of lines. Since a list starts from 0, It will automatically satisfy the condition that line should be number from 0. Then it wants you to print the lines in a specific order.
For our example, n=5
First, they want output line no with floor(n/2),...,n-1
So your output would be like below,
C
D
E
The reason is that floor(n/2) = floor(5/2) = 2. So start from line 2 to n-1 which is 4 (5-1) . Same way, next it wants you to print 0,..,.floor(n/2)-1. So line no 0 to 1.
So,
A
B
The final output would be like,
C
D
E
A
B
If you want to learn more about the collection and file IO operation you can refer to this.

Is it possible to put a string array into buffered Reader?

I'm working on a project at the moment which requires me to set up a distributed network simulator, I had it working with taking output from a file and parsing through each line with a buffered reader as you can see below but I want to now use a predefined array and make my bufferedReader take input from that instead I've looked up a few solutions online to help me put this array into the buffered Reader but non seem to have worked.
I'm getting no errors when running and terminating the code but just seems to be stuck in an endless loop at some point and I presume it's the new buffered reader segment using the array instead. The idea behind this was to make the process simpler than re-writing many segments to fit around the array parsing and instead find a simpler way by having the array in the buffered Reader but as this is proving difficult I may have to resort to changing. I have tested if the array is being initialised correctly and that's not the problem so it's one less thing to take into consideration.
**Previous code:**
private void parseFile(String fileName) throws IOException {
System.out.println("Parsing Array");
Path path = Paths.get(fileName);
try (BufferedReader br = Files.newBufferedReader(path)) {
String line = null;
line = br.readLine(); // Skip first line
while ((line = br.readLine()) != null) {
parseLine(line);
}
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
}
}
The recommendation online was to use an input stream with the buffered reader for it but that didn't seem to work at all as it over wrote the array, any recommendations on what I can use for the buffered reader segment would be grand.
The Array method above is just a void creating the array which is called before the method so the array should be initialised I presume, If anyone can look over and potentially let me know where I'm going wrong and problems that would be amazing if not I appreciate your time to read this anyway, Thanks for your time.
New Code Attempt:
//Creating array to parse.
private void createArray(){
myStringArray[0] = "Node_id Neighbours";
myStringArray[1] = "1 2 10";
myStringArray[2] = "2 3 1";
myStringArray[3] = "3 4 2";
myStringArray[4] = "4 5 3";
myStringArray[5] = "5 6 4";
myStringArray[6] = "6 7 5";
myStringArray[7] = "7 8 6";
myStringArray[8] = "8 9 7";
myStringArray[9] = "9 10 8";
myStringArray[10] = "10 1 9";
myStringArray[11] = "ELECT 1 2 3 4 5 6 7 8 9";
}
private void parseArray() throws IOException {
//InputStreamReader isr = new InputStreamReader(System.in);
System.out.println("Parsing Array");
// try (BufferedReader br = Files.newBufferedReader(path))
try (BufferedReader br = new BufferedReader(isr)) {
for(int i=0;i<12;i++)
{
String line = null;
line = br.readLine(); // Skip first line
while ((myStringArray[i] = br.readLine()) != null) {
parseLine(line);
}
}
} catch (IOException x) {
System.err.format("IOException: %s%n", x);
}
}
Answer: You cannot do this with buffered reader. I fixed it like this if this is any use to anyone. Thanks a lot to #L.Spillner for the explanation and answer.
code fix:
private void parseArray() throws IOException {
System.out.println("Parsing Array");
for(int i=1;i<12;i++) //First row ignored.
{
String line = null;
line = myStringArray[i];
//Begin parsing process of each entity.
parseLine(line);
}
}
Let's kick it off with a precise answer to the Question.
You cannot put anything into a BufferedReader directly. Especially when it's some kind of data structure like an array.
The BufferedReader's purpose is to handle I/O Operations, input operations to be more precise. According to the javadoc the BufferedReader takes a Reader as an argument. Reader is an abstract class which contains 'tools' to handle character InputStreams.
The way the BufferedReader's readLine() method works is: Any character arriving on the InputStream gets stored in a buffer until a \n (new line/linefeed) or \r (carriage retun) arrives. When one of these two special characters show up the buffer gets interpreted as a String and is returned to the call.
Answer is you can't. Thanks for the feedback though guys and got it working through just looping through the array and assigning each item to line.

Returning the number of lines in a .txt file

This is my debut question here, so I will try to be as clear as I can.
I have a sentences.txt file like this:
Galatasaray beat Juventus 1-0 last night.
I'm going to go wherever you never can find me.
Papaya is such a delicious thing to eat!
Damn lecturer never gives more than 70.
What's in your mind?
As obvious there are 5 sentences, and my objective is to write a listSize method that returns the number of sentences listed here.
public int listSize()
{
// the code is supposed to be here.
return sentence_total;}
All help is appreciated.
To read a file and count its lines, use a java.io.LineNumberReader, plugged on top of a FileReader. Call readLine() on it until it returns null, then getLineNumber() to know the last line number, and you're done !
Alternatively (Java 7+), you can use the NIO2 Files class to fully read the file at once into a List<String>, then return the size of that list.
BTW, I don't understand why your method takes that int as a parameter, it it's supposed to be the value to compute and return ?
Using LineNumberReader:
LineNumberReader reader = new LineNumberReader(new FileReader(new File("sentences.txt")));
reader.skip(Long.MAX_VALUE);
System.out.println(reader.getLineNumber() + 1); // +1 because line index starts at 0
reader.close();
use the following code to get number of lines in that file..
try {
File file = new File("filePath");
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
int totalLines = 0;
while((line = reader.readLine()) != null) {
totalLines++;
}
reader.close();
System.out.println(totalLines);
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
You could do:
Path file = Paths.getPath("route/to/myFile.txt");
int numLines = Files.readAllLlines(file).size();
If you want to limit them or process them lazily:
Path file = Paths.getPath("route/to/myFile.txt");
int numLines = Files.llines(file).limit(maxLines).collect(Collectors.counting...);

how to split a large text file into smaller chunks using java multithread

I'm trying to develop a multithreaded java program for split a large text file into smaller text files. The smaller files created must have a prefixed number of lines.
For example:
if the number of lines of input file is 100 and the input number is 10, the result of my program is to split the input file into 10 files.
I've already developed a singlethreaded version of my program:
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class TextFileSingleThreaded {
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("Invalid Input!");
}
//first argument is the file path
File file = new File(args[0]);
//second argument is the number of lines per chunk
//In particular the smaller files will have numLinesPerChunk lines
int numLinesPerChunk = Integer.parseInt(args[1]);
BufferedReader reader = null;
PrintWriter writer = null;
try {
reader = new BufferedReader(new FileReader(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
String line;
long start = System.currentTimeMillis();
try {
line = reader.readLine();
for (int i = 1; line != null; i++) {
writer = new PrintWriter(new FileWriter(args[0] + "_part" + i + ".txt"));
for (int j = 0; j < numLinesPerChunk && line != null; j++) {
writer.println(line);
line = reader.readLine();
}
writer.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
writer.close();
long end = System.currentTimeMillis();
System.out.println("Taken time[sec]:");
System.out.println((end - start) / 1000);
}
}
I want to write a multithreaded version of this program but I don't know how to read a file beginning from a specified line. Help me please. :(
I want to write a multithreaded version of this program but I don't know how to read a file beginning from a specified line. Help me please. :(
I would not, as this implied, have each thread read from the beginning of the file ignoring lines until they come to their portion of the input file. This is highly inefficient. As you imply, the reader has to read all of the prior lines if the file is going to be divided up into chunks by lines. This means a whole bunch of duplicate read IO which will result in a much slower application.
You could instead have 1 reader and N writers. The reader will be adding the lines to be written to some sort of BlockingQueue per writer. The problem with this is that chances are you won't get any concurrency. Only one writer will most likely be working at one time while the rest of the writers wait for the reader to reach their part of the input file. Also, if the reader is faster than the writer (which is likely) then you could easily run out of memory queueing up all of the lines in memory if the file to be divided is large. You could use a size limited blocking queue which means the reader may block waiting for the writers but again, multiple writers will most likely not be running at the same time.
As mentioned in the comments, the most efficient way of doing this is single threaded because of these restrictions. If you are doing this as an exercise then it sounds like you will need to read the file through one time, note the start and end positions in the file for each of the output files and then fork the threads with those locations so they can re-read the file and write it into their separate output files in parallel without a lot of line buffering.
You only need to read your file one time, and store it into a List :
BufferedReader br = new BufferedReader(new FileReader(new File("yourfile")));
List<String> list = new ArrayList<String>();
String line;
//for each line of your file
while((line = br.readLine()) != null){
list.add(line);
}
br.close();
//then you can split your list into differents parts
List<List<String>> parts = new ArrayList<ArrayList<String>>();
for(int i = 0; i < 10; i++){
parts.add(new ArrayList<String>());
for(int j =0; j < 10; j++){
parts.get(i).add(list.get(i*10+j));
}
}
//now you have 10 lists which each contain 10 lines
//you still need to to create a thread pool, where each thread put a list into a file
for more informations about thread pools, read this.

Reading Integer values from a file (Java)

I'm working on a simple level editor for my Android game. I've written the GUI (which draws a grid) using swing. You click on the squares where you want to position a tile and it changes colour. Once you're done, you write everything to a file.
My file consists of something like the following (this is just an example):
I use the asterisks to determine the level number being read and the hyphen to tell the reader to stop reading.
My file reading code is below, Selecting which part to read works OK - for example. if I pass in 2 by doing the following:
readFile(2);
Then it prints all of the characters in the 2nd section
What I can't figure out is, once I've got to the 'start' point, how do I actually read the numbers as integers and not individual characters?
Code
public void readFile(int level){
try {
//What ever the file path is.
File levelFile = new File("C:/Temp/levels.txt");
FileInputStream fis = new FileInputStream(levelFile);
InputStreamReader isr = new InputStreamReader(fis);
Reader r = new BufferedReader(isr);
int charTest;
//Position the reader to the relevant level (Levels are separated by asterisks)
for (int x =0;x<level;x++){
//Get to the relevant asterisk
while ((charTest = fis.read()) != 42){
}
}
//Now we are at the correct read position, keep reading until we hit a '-' char
//Which indicates 'end of level information'
while ((charTest = fis.read()) != 45){
System.out.print((char)charTest);
}
//All done - so close the file
r.close();
} catch (IOException e) {
System.err.println("Problem reading the file levels.txt");
}
}
Scanner's a good answer. To remain closer to what you have, use the BufferedReader to read whole lines (instead of reading one character at a time) and Integer.parseInt to convert from String to Integer:
// get to starting position
BufferedReader r = new BufferedReader(isr);
...
String line = null;
while (!(line = reader.readLine()).equals("-"))
{
int number = Integer.parseInt(line);
}
If you use the BufferedReader and not the Reader interface, you can call r.readLine(). Then you can simply use Integer.valueOf(String) or Integer.parseInt(String).
Perhaps you should consider using readLine which gets all the chars up the the end of line.
This part:
for (int x =0;x<level;x++){
//Get to the relevant asterisk
while ((charTest = fis.read()) != 42){
}
}
Can change to this:
for (int x =0;x<level;x++){
//Get to the relevant asterisk
while ((strTest = fis.readLine()) != null) {
if (strTest.startsWith('*')) {
break;
}
}
}
Then, to read the values another loop:
for (;;) {
strTest = fls.readLine();
if (strTest != null && !strTest.startsWith('-')) {
int value = Integer.parseInt(strTest);
// ... you have to store it somewhere
} else {
break;
}
}
You also need some code in there to handle errors including a premature end of file.
I think you should have look at the Scanner API in Java.
You can have a look at their tutorial

Categories