I am supposed to create a program that reads an external file with 3 integers on every line and find the area of a triangle with those three numbers. We haven't learned arrays yet though, so i want to create the program without an array, methods and classes are fine. I just need help reading the file every three numbers by line.
The data is:
7 8 9
9 9 12
6 5 21
24 7 25
13 12 5
50 40 30
10 10 10
82 34 48
4 5 6
Here's what i have so far:
import java.io.*;
import java.util.*;
import java.lang.*;
public class Prog610a
{
public static void main(String[] args) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader("myData.in"));
String currentLine;
int a, b, c;
double s, area;
System.out.println("A" + "\t B" + "\t C" + "\t Area");
try
{
while((currentLine = reader.readLine()) != null)
{
Scanner scanner = new Scanner(currentLine);
s = ((scanner.nextInt() + scanner.nextInt() + scanner.nextInt()) / 2);
area = Math.sqrt(s * (s - scanner.nextInt()) * (s - scanner.nextInt()) * (s - scanner.nextInt()) );
if(s < 0)
{
System.out.println(scanner.nextInt() + " \t" + scanner.nextInt() +
" \t" + scanner.nextInt() + "\t This is not a triangle");
}
else
{
System.out.println(scanner.nextInt() + " \t" + scanner.nextInt() +
" \t" + scanner.nextInt() + " \t" + area);
}
}
}
finally
{
reader.close();
}
}
}
You have made a good start by using the Scanner. I would suggest that just using that may be insufficient, as you may end up with some malformed lines. To handle them you may wish to split the processing into two parts: get a line, and then get the individual values from that line.
That allows you to catch lines that do not have enough values, or have too many values. If you do not do this then you may become mis-aligned with the lines, reading some values from one line, and some from the following line.
The BufferedReader will allow you to read lines which you can then scan. Since you don't want to use arrays you must extract the numbers individually:
BufferedReader reader = new BufferedReader(new FileReader("myData.in"));
String currentLine;
try {
while ((currentLine = reader.readLine()) != null) {
Scanner scanner = new Scanner(currentLine);
try {
calculateTriangleArea(
scanner.nextInt(), scanner.nextInt(), scanner.nextInt()
);
}
catch (NoSuchElementException e) {
// invalid line
}
}
}
finally {
reader.close();
}
Also it may help you to understand the Java string interpolation. You have horizontalTab throughout your code. You can express that in a string by just using \t. For example:
"\tThis is indented by one tab"
"This is not"
You can find the complete list of string escape characters here.
The exception handling (or lack of) in my code may surprise you. In your code you catch the Exception that could be thrown. However you discard it and then proceed to execute the rest of the code on a Scanner that is known to be broken. In such a situation it is better to fail immediately rather than conceal the error and attempt to proceed.
The one bit of exception handling that does occur in my code is the finally block. This ensures that the reader is closed no matter what happens when reading from it. It wraps the code that is executed after the reader has been opened, and as such it is known that the reader is not null and should be closed after use.
Related
I am currently stuck with a problem. I am supposed to write a programm that is able to search for a string in a .txt file given as argument. The programm must return the row and the column of the found string.
I am struggling to find a way to achieve that and have no idea how to go on. I would be very happy to hear from you.
Here is my attempt in tackling with my task:
- I thought about saving the content of a file via a buffered reader in a string array, but that does not seem to work since I cannot define the length of the array from the beginning
- I also thought about saving the content of the file via a buffered reader in a string and then split this string in characters. However I am not sure how I will be able to retreieve the rows in the original file then.
This is the non-functional code that I have at the moment:
public class StringSearch{
public static void main(String[] args){
if(args.length > 0){
BufferedReader br = null;
String text = null;
try{
br = new BufferedReader(new FileReader(args[0]));
// attempt of saving the content of the "argument" file in a string array and then in a string
String[] lines = new String[]; // I know this does not work like this
for( int i = 0; i < lines.length; i++){
lines[i] = br.readLine;
text = text + lines[i];
i++;
}
text.split("\r\n");
} catch (IOException ioe){
ioe.printStackTrace();
} finally{
if (br != null) {
try{
br.close();
}catch (IOException ioe){
ioe.printStackTrace();
}
}
}
}
}
}
You can do it as follows:
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
if (args.length != 2) {
System.out.println("The correct syntax to use this program is: java Main <filename.txt> <text-to-search>");
return;
}
Scanner scanner;
File file = new File(args[0]);
int rowCount = 1, index;
String line;
// Map to collect row and col info of the search string
Map<String, String> lineColMap = new HashMap<String, String>();
if (!file.exists()) {
System.out.println("The file, " + args[0] + " does not exist");
return;
}
try {
scanner = new Scanner(file);
while (scanner.hasNextLine()) {// Loop until the last line in the file
line = scanner.nextLine();// Read a line from the file
index = line.indexOf(args[1]);// Find if the string exists in the line
if (index != -1) {// If the string exists
// Put the row and col info of the search string into the map
lineColMap.put("Row: " + rowCount, "Column: " + index);
}
rowCount++;// Increase the row count
}
} catch (Exception e) {
System.out.println("Error occured while processing the file");
e.printStackTrace();
}
if (lineColMap.entrySet().size() > 0) {// If there is at least one entry collected into the map
System.out.println("'" + args[1] + "' exists in " + args[0] + " as follows:");
for (Map.Entry<String, String> entry : lineColMap.entrySet()) {
System.out.println(entry.getKey() + ", " + entry.getValue());
}
} else {
System.out.println("'" + args[1] + "' does not exist in " + args[0]);
}
}
}
A sample run: java Main input.txt of
'of' exists in input.txt as follows:
Row: 1, Column: 51
Row: 2, Column: 50
Row: 3, Column: 50
Row: 5, Column: 71
The content of input.txt is as follows:
Stack Overflow is a question and answer site for professional and enthusiast programmers.
It is a privately held website, the flagship site of the Stack Exchange Network, created in 2008 by Jeff Atwood and Joel Spolsky.
It features questions and answers on a wide range of topics in computer programming.
It was created to be a more open alternative to earlier question and answer sites such as Experts-Exchange.
The name for the website was chosen by voting in April 2008 by readers of Coding Horror, Atwood's popular programming blog.
The logic in the code is straight forward and I believe, you should be able to understand it in the first reading. Feel free to comment in case of any doubt.
Here's one approach -
Let's consider a counter which holds a counter for all the
readLine() method invocations - representing the "row" in the .txt
file. So, increment the counter after every readLine call in the
while loop.
Next, split the line on " " (space) to get an array of each word in the
line. Then, you could iterate over this array and match the word to
the search string. The position of array index at the time the match
was found will represent the "column".
I worte a small java function that calls another Java program and displays its input.
private static void call() throws Exception
{
int line;
///Other stuff here
Process p2= Runtime.getRuntime().exec("java SelfModifying");
InputStream is = p2.getInputStream();
//p.waitFor();
while ((line = is.read()) != -1) {
System.out.println("result: " + line);
}
Runtime.getRuntime().exit(0);
}
The prorgam that gests called is supposed to return a single int value: '10'.
Instead, I get 4 lines:
result: 49
result: 48
result: 13
result: 10
Where do the three other values come from? They are deterministic but seem to come from the input. When I run the program on its own it does not return these 3 lines.
You're reading individual bytes from the stream:
49 is ASCII '1';
48 is ASCII '0';
13 is ASCII '\r';
10 is ASCII '\n'.
So the contents of the file is 10\r\n (10, followed by a windows newline).
You should wrap is in a scanner:
Scanner scanner = new Scanner(is, "UTF-8");
System.out.println(scanner.nextInt());
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
I want to implementing a Java program that searches a phrase example “red or green, blue car, red and blue” in a text file, and returns a match even if it is not a complete match for the phrase, and if there is no even half match the program should return no match.
if I am searching "red car" and the the string line in the text file contains "red and blue" I want the program to return red which is half a match of what I was searching.
Any help is very much appreciated
This is what I have done so far, all this does is find the exact words
public class StringSearch
{
public static void main(String[] args)
{
String key = "red yellow";
String strLine;
try
{
FileInputStream fstream = new FileInputStream("C:\\textfile.txt");
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));
while ((strLine = br.readLine()) != null) {
if(key.equals(strLine))
{
System.out.println(" Match For " + strLine );
}
else
{
System.out.println( "No Match For " + key);
}
// Print the content on the console
}
//Close the input stream
in.close();
}catch (Exception e){//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
}
But what I want to find is if I am searching "red" and the first line of the string in the text file I am searching contains "red car was stollen" and the second line contains just "red". I want to return two matches the first one being 100% match the socond being 50% match.
First you need to define your problem better, and to do that think about how what you'd do if you were telling someone else, who interpreted things very literally, how to do it. How much of the input should they examine at one time? Should what they examine span lines? What precisely is a "half match"? What is the sequence of steps they should take?
This code might help You
import java.io.*;
public class searchfile {
public static void main(String args[]) {
try {
// Open the file c:\test.txt as a buffered reader
BufferedReader bf = new BufferedReader(new FileReader("c:\\test.txt"));
// Start a line count and declare a string to hold our current line.
int linecount = 0;
String line;
// Let the user know what we are searching for
System.out.println("Searching for " + args[0] + " in file...");
// Loop through each line, stashing the line into our line variable.
while (( line = bf.readLine()) != null)
{
// Increment the count and find the index of the word
linecount++;
int indexfound = line.indexOf(args[0]);
// If greater than -1, means we found the word
if (indexfound > -1) {
System.out.println("Word was found at position " + indexfound + " on line " + linecount);
}
}
// Close the file after done searching
bf.close();
}
catch (IOException e) {
System.out.println("IO Error Occurred: " + e.toString());
}
}
}
and run it as
c:\>java searchfile "bluecar"
Ok, say I have a text file called "people.txt", and it contains the following information:
1 adam 20 M
2 betty 49 F
3 charles 9 M
4 david 22 M
5 ethan 41 M
6 faith 23 F
7 greg 22 M
8 heidi 63 F
Basically, the first number is the ID of the person, then comes the person's name, age and gender. Say I want to replace line 2, or the person with ID number 2 with different values. Now, I know I cant use RandomAccessFile for this because the names are not always the same number of bytes, neither are the ages. While searching random Java forums, I found that StringBuilder or StringBuffer should suffice for my needs, but I'm not sure how to implement either. Can they be used to directly write to the text file? I want this to work directly from user input.
Just created an example for you
public static void main(String args[]) {
try {
// Open the file that is the first
// command line parameter
FileInputStream fstream = new FileInputStream("d:/new6.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
String strLine;
StringBuilder fileContent = new StringBuilder();
//Read File Line By Line
while ((strLine = br.readLine()) != null) {
// Print the content on the console
System.out.println(strLine);
String tokens[] = strLine.split(" ");
if (tokens.length > 0) {
// Here tokens[0] will have value of ID
if (tokens[0].equals("2")) {
tokens[1] = "betty-updated";
tokens[2] = "499";
String newLine = tokens[0] + " " + tokens[1] + " " + tokens[2] + " " + tokens[3];
fileContent.append(newLine);
fileContent.append("\n");
} else {
// update content as it is
fileContent.append(strLine);
fileContent.append("\n");
}
}
}
// Now fileContent will have updated content , which you can override into file
FileWriter fstreamWrite = new FileWriter("d:/new6.txt");
BufferedWriter out = new BufferedWriter(fstreamWrite);
out.write(fileContent.toString());
out.close();
//Close the input stream
in.close();
} catch (Exception e) {//Catch exception if any
System.err.println("Error: " + e.getMessage());
}
}
One solution could be to read in the file, line-by-line, manipulate the lines you need (performing some parsing/tokenization to get the ID/name/etc.), then write all the lines into the file (overwriting its current content). This solution depends on the size of the file you are working with: too large a file will consume a lot of memory as you are holding all its contents in memory at once
Another approach (to cut down on memory requirements) is to process the file lin-by-line, but instead of holding all lines in memory, you write the current line to a temporary file after processing of each line, then move the temporary file to the location of the input file (overwriting that file).
The classes FileReader and FileWriter should help you with reading/writing to the file. You might want to wrap them in a BufferedReader/BufferedWriter to improve performance.
Also, don't forget to close the reader (also, the writer) when done reading (writing) the file, so consequent accesses to the file are not blocked due to the file still being open