I have a question about something I've done in the past, but never really thought if it was the most efficient method to use.
Let's say I have a text file, where each line contains something important and let's then say I have multiple sets of these lines, each corresponding to a unique environment...so for example:
1
String that I need to parse for specific tokens..
2
String that I need to parse for specific tokens..
String that I need to parse for specific tokens..
3
String that I need to parse for specific tokens..
String that I need to parse for specific tokens..
String that I need to parse for specific tokens..
So given the above input file, my past way of solving this would be something similar to the following (semi-pseudocode!):
BufferedReader inputFile = new BufferedReader(new FileReader("file.txt"));
while(inputFile.hasNextLine())
{
Scanner line = new Scanner(inputFile.nextLine());
//parse the line looking for tokens
}
inputFile.close();
My issue with this is it seems incredibly inefficient to create a new Scanner object for every line I have in my BufferedReader.
Is there a better way to achieve this functionality?
One suggestion may be to scan the whole document by tokens, but my issue with that is I won't be able to keep track of how many strings are apart of the subset (indicated by the integer); or at least I can't think of another solution to that other than to decrement a counter every time I look at a new line.
Thanks in advance!
check out with this;
public static void main(String[] args) throws IOException {
BufferedReader bf = new BufferedReader(new FileReader(new File("d:/sample.txt")));
LineNumberReader lr = new LineNumberReader(bf);
String line = "";
while ((line = lr.readLine()) != null) {
System.out.println("Line Number " + lr.getLineNumber() +
": " + line);
}
}
Related
I am reading text from a file and I have been having trouble trying to read List 1 and List 2 into 2 different String . The * indicates where the first list ends. I have tried using arrays but the array only stores the last * symbol.
List 1
Name: Greg
Hobby 1: Swimming
Hobby 2: Football
*
List 2
Name: Bob
Hobby 1: Skydiving
*
Here's what I tried so far:
String s = "";
try{
Scanner scanner = new Scanner(new File("file.txt"));
while(scanner.hasnextLine()){
s = scanner.nextLine();
}
}catch(Exception e){
e.printStackTrace}
String [] array = s.split("*");
String x = array[0];
String y = array[1];
Your code has multiple issues like #Henry said that your string contains only the last line of the file and also you misunderstood the split() because it takes a RegularExpression as a parameter.
I would recommend you to use the following example because it works and is a lot faster than your approach.
Kick-Off example:
// create a buffered reader that reads from the file
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt")));
// create a new array to save the lists
ArrayList<String> lists = new ArrayList<>();
String list = ""; // initialize new empty list
String line; // initialize line variable
// read all lines until one becomes null (the end of the file)
while ((line = reader.readLine()) != null) {
// checks if the line only contains one *
if (line.matches("\\s*\\*\\s*")) {
// add the list to the array of lists
lists.add(list);
} else {
// add the current line to the list
list += line + "\r\n"; // add the line to the list plus a new line
}
}
Explanation
I'm going to explain special lines that are hard to understand again.
Looking at the first line:
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt")));
This line creates a BufferedReader that is nearly the same like a Scanner but it's a lot faster and hasn't as much methods as a Scanner. For this usage the BufferedReader is more than enough.
Then it takes an InputStreamReader as a parameter in the constructor. This is only to convert the following FileInputStream to a Reader.
Why should one do that? That's because an InputStream ≠ Reader. An InputStream returns the raw values and a Reader converts it to human readable characters. See the difference between InputStream and Reader.
Looking at the next line:
ArrayList<String> lists = new ArrayList<>();
Creates a variable array that has methods like add() and get(index). See the difference of arrays and lists.
And the last one:
list += line + "\r\n";
This line adds the line to the current list and adds a new line to it.
"\r\n" Are special characters. \r ends the current line and \n creates a new line.
You could also only use \n but adding \r in front of it is better because this supports more Os's like Linux can have problems with it when \r misses.
Related
Using BufferedReader to read Text File
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.
I am trying to write a Java program that simulates a record store shopping cart. The first step is to open up the inventory.txt file and read the contents which is basically what the "store has to offer". Then I need to read every line individually and process the id record and price.
The current method outputs a result that is very close to what I need, however, it picks up on the item id of the next line, as you can see below.
I was wondering if someone can assist me in figuring out how to process every line in the text document individually and store every piece of data in its own variable without picking up the id of the next item?
public void openFile(){
try{
x = new Scanner(new File("inventory.txt"));
x.useDelimiter(",");
}
catch(Exception e){
System.out.println("Could not find file");
}
}
public void readFile(){
while(x.hasNext()){
String id = x.next();
String record = x.next();
String price = x.next();
System.out.println(id + " " + record + " " + price);
break;
}
}
.txt document:
11111, "Hush Hush... - Pussycat Dolls", 12.95
22222, "Animal - Ke$ha", 9.95
33333, "Hanging By A Moment - Lifehouse - Single, 4.95
44444, "Have A Nice Day - Bon Jovi", 9.99
55555, "Day & Age - Killers", 10.99
66666, "She Wolf - Shakira", 15.99
77777, "Dark Horse - Nickelback", 12.99
88888, "The E.N.D. - Black Eyed Peas", 10.95
actual output
11111 "Hush Hush... - Pussycat Dolls" 12.95
22222
expected result
11111 "Hush Hush... - Pussycat Dolls" 12.95
So the problem here specifically is that you are breaking on commas, and you should be breaking on commas and newlines. But there are tons of other corner cases (for example, if your column is "abc,,,abc" you shouldn't break on those commas). Apache Commons comes with a CSVParser that handles all of these corner cases, you should use it:
http://commons.apache.org/csv/apidocs/org/apache/commons/csv/CSVParser.html
You can use a Pattern as the argument to Scanner.useDelimiter. Use this to provide alernates for the delimiter: either comma, or the line separator.
x.useDelimiter(",|" + System.getProperty("line.separator"));
Depending on what your input file uses as the line separator, you may need to change the second option.
The advice in other answers to use an existing CSV library is good: parsing CSV isn't as simple as breaking up the input around commas.
There are multiple ways to achieve this but going with your own way, you could use Scanner to first read lines (use Java's "line.separator" as delimiter) and then use Scanner class again with comma as delimiter.
The problem you're going to be facing is the CSV is more then just splitting a String on a comma. There are considerations to take into account with "escaped" commas (commas you don't want to delimante against).
I suggest you save your self a lot of time and head aches and use an existing API.
The Apache Commons has already been mentioned. I recently used OpenCSV and found it to be extremely simple to use and powerful
IMHO
An easy way to read in the entire file into a list of Strings (lines)...
public class Scanner {
public static List<String> readLines(String filename) throws IOException {
FileReader fileReader = new FileReader(filename);
BufferedReader bufferedReader = new BufferedReader(fileReader);
List<String> lines = new ArrayList<String>();
String line = null;
while ((line = bufferedReader.readLine()) != null) {
lines.add(line);
}
bufferedReader.close();
return lines;
}
}
Then you can process the individual lines as before, as each line is it's own String object. That is, if you don't use a CSVParser.
I have managed to split a CSV file based on the commas. I did this by placing a dummy String where ever there was a ',' and then splitting based on the dummy String.
However, the CSV file contains things such as:
something, something, something
something, something, something
Therefore, where there is a new line, the last and first values of each line get merged into their own string. How can I solve this? I've tried placing my dummy string where \n is found to split it based on that but to no success.
Help?!
I would strongly recommend you not reinventing the wheel :). Go with one of the already available libraries for handling CSV files, eg: OpenCSV
I don't see why you need a dummy string. Why not split on comma?
BufferedReader in = new BufferedReader(new FileReader("file.csv"));
String line;
while ((line = in.readLine()) != null) {
String[] fields = line.split(",");
}
As per the dummy strings you mentioned, it could be easily processed with the help of an existing library. I would like to recommand the open source library uniVocity-parsers, which procides simplfied API, significent performance and flexibility.
Just refer to few lines of code to read csv data into memory with array:
private static void parseCSV() throws FileNotFoundException {
CsvParser parser = new CsvParser(new CsvParserSettings());
List<String[]> parsedData = parser.parseAll(new FileReader("/examples/example.csv"));
for (String[] row : parsedData) {
StringBuilder strBuilder = new StringBuilder();
for (String col : row) {
strBuilder.append(col).append("\t");
}
System.out.println(strBuilder);
}
}
use the followin it will split lines
String[] a=scanner.next().split(" ");
public static void main(String args[])
{
try
{
File file = new File("input.txt");
BufferedReader reader = new BufferedReader(new FileReader(file));
String line = "000000", oldtext = "414141";
while((line = reader.readLine()) != null)
{
oldtext += line + "\r\n";
}
reader.close();
// replace a word in a file
//String newtext = oldtext.replaceAll("drink", "Love");
//To replace a line in a file
String newtext = oldtext.replaceAll("This is test string 20000", "blah blah blah");
FileWriter writer = new FileWriter("input.txt");
writer.write(newtext);writer.close();
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
}
A couple suggestions on your sample code:
Have the user pass in old and new on the command line (i.e., args[0] and args1).
If it's sufficient to do this a line at a time, it's going to be much more efficient to read a line, replace old -> new, then stream it out.
Also check out StringUtils and IOUtils, which may make your life easier in this case.
Easiest is the String.replace(oldstring, newstring), or String.replaceAll(regex, newString) function, you can just read the one file and write the replacement into a new file (or do it line by line if you're concerned about file size).
After reading your last comment - that's a totally different story... the preferred solution would be to parse the css file into an object model (like DOM), apply the changes there and serialize the model to css afterwards. It's much easier to find all color attributes in DOM and change them compared to doing the same with search and replace.
I've found some CSS parser in the wild wild web, but none of them looked like being capable of writing CSS files.
If you wanted to replace the color names with search and replace, you'd search for 'color:<colorname>' and replace it with 'color:<youHexColorValue>'. You may have to do the same for 'color:"<colorname>"', because the color name can be set in double quotes (another argument for using a CSS parser..)
String.replaceAll() is the easiest way to do it. Just read the complete CSS file into one String, replace all as suggested above and write the new String to the same (or a temporary) file (first).