I'm trying to make this work, I don't understand why it doesn't work since it makes sense to me, but it doesn't make sense to java it seems.
As you read the code, what I expect is _NAME to be replaced by TEST while maintaining the same structure of the text (keeping \n) to save it later(not done yet)
I also stored it using ArrayList, but the replace never took off either, so I'm clueless
try {
BufferedReader reader = new BufferedReader (new InputStreamReader (
new FileInputStream (temp), "utf-8"));
String line = reader.readLine();
StringBuffer text = new StringBuffer();
while(line != null) {
line.replace("[_NAME]", "TEST");
Logger.info(line);
line = reader.readLine();
}
reader.close();
} catch(FileNotFoundException ex) {
} catch(UnsupportedEncodingException ex) {
} catch(IOException ex ) {}
The correct line is
line = line.replace("_NAME", "TEST");
If you use brackets, you are specifying the characters as individual matches (_, N, A, M and E), and you want to replace the whole match.
Second, the replace method return a new String that contains the modified String. Remember that Strings in Java are immutable, so no method that modifies a String would modify the input object, they will always return a new object.
One possible problem is the fact that you have [] around _NAME but I'm going to go with the "you forgot that replace returns the new string instead of changing it in-situ" option. See here.
In other words, it should changed from:
line.replace ( ...
to:
line = line.replace ( ...
Related
Hopefully my explanation does me some justice. I am pretty new to java. I have a text file that looks like this
Java
The Java Tutorials
http://docs.oracle.com/javase/tutorial/
Python
Tutorialspoint Java tutorials
http://www.tutorialspoint.com/python/
Perl
Tutorialspoint Perl tutorials
http://www.tutorialspoint.com/perl/
I have properties for language name, website description, and website url. Right now, I just want to list the information from the text file exactly how it looks, but I need to assign those properties to them.
The problem I am getting is "index 1 is out of bounds for length 1"
try {
BufferedReader in = new BufferedReader(new FileReader("Tutorials.txt"));
while (in.readLine() != null) {
TutorialWebsite tw = new TutorialWebsite();
str = in.readLine();
String[] fields = str.split("\\r?\\n");
tw.setProgramLanguage(fields[0]);
tw.setWebDescription(fields[1]);
tw.setWebURL(fields[2]);
System.out.println(tw);
}
} catch (IOException e) {
e.printStackTrace();
}
I wanted to test something so i removed the new lines and put commas instead and made it str.split(",") which printed it out just fine, but im sure i would get points taken off it i changed the format.
readline returns a "string containing the contents of the line, not including any line-termination characters", so why are you trying to split each line on "\\r?\\n"?
Where is str declared? Why are you reading two lines for each iteration of the loop, and ignoring the first one?
I suggest you start from
String str;
while ((str = in.readLine()) != null) {
System.out.println(str);
}
and work from there.
The first readline gets the language, the second gets the description, and the third gets the url, and then the pattern repeats. There is nothing to stop you using readline three times for each iteration of the while loop.
you can read all the file in a String like this
// try with resources, to make sure BufferedReader is closed safely
try (BufferedReader in = new BufferedReader(new FileReader("Tutorials.txt"))) {
//str will hold all the file contents
StringBuilder str = new StringBuilder();
String line;
while ((line = in.readLine()) != null) {
str.append(line);
str.append("\n");
} catch (IOException e) {
e.printStackTrace();
}
Later you can split the string with
String[] fields = str.toString().split("[\\n\\r]+");
Why not try it like this.
allocate a List to hold the TutorialWebsite instances.
use try with resources to open the file, read the lines, and trim any white space.
put the lines in an array
then iterate over the array, filling in the class instance
the print the list.
The loop ensures the array length is a multiple of nFields, discarding any remainder. So if your total lines are not divisible by nFields you will not read the remainder of the file. You would still have to adjust the setters if additional fields were added.
int nFields = 3;
List<TutorialWebsite> list = new ArrayList<>();
try (BufferedReader in = new BufferedReader(new FileReader("tutorials.txt"))) {
String[] lines = in.lines().map(String::trim).toArray(String[]::new);
for (int i = 0; i < (lines.length/nFields)*nFields; i+=nFields) {
TutorialWebsite tw = new TutorialWebsite();
tw.setProgramLanguage(lines[i]);
tw.setWebDescription(lines[i+1]);
tw.setWebURL(lines[i+2]);
list.add(tw);
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
list.forEach(System.out::println);
A improvement would be to use a constructor and pass the strings to that when each instance is created.
And remember the file name as specified is relative to the directory in which the program is run.
I have this file: "Test.txt" -> 1,cont,details,950.5,asd
My Class is Auto, the constructor is int, string, string, double, string.
How can I read from this file and then initialize my object with the correct data conversion?
I think I need to use a comma splitter too.
FileReader inFile2=null;
BufferedReader outBuffer2=null;
inFile2=new FileReader("Test.txt");
outBuffer2 = new BufferedReader(inFile2);
List<String> lines = new ArrayList<String>();
String line="";
while((line = outBuffer2.readLine()) != null) {
lines.add(line);
System.out.println(lines);
}
outBuffer2.close();
inFile2.close();
//
String[] splitTranzactie = lines.toArray(new String[]{});
Auto t = new Auto(Int32(splitTranzactie[0]), splitTranzactie[1], splitTranzactie[2],
ToDouble(splitTranzactie[3]), splitTranzactie[4]);
There are a few issues here. First of all:
String[] splitTranzactie = lines.toArray(new String[]{});
is going to just turn your list of lines into an array of lines. To split each line into its constituent parts you can use something like String.split(","). This will return an array of Strings. Note that if you expect any of the last values to be empty, i.e. ending in one or more commas then the returned array will be as long as the last value position it finds. i.e. if the line is 1,cont,details,, you split will return an array of length 3 not 5. You should code defensively against this.
To convert a String to an int or double you can use Integer.parseInt() and Double.parseInt() respectively. Again you may want to consider coding defensively if the values may be anything other than numeric values as those two methods will throw an exception if they can't parse the input.
You should also place your close() methods in a finally block to ensure they are called, however as they are AutoCloseable you can avoid this altogether by using the try-with-resources syntax which will close the reader automatically.
try(Reader in = new Reader()) {
}
A working example with all of the above (but without any defensive code) following your example may look something like the following:
List<Auto> autos = new ArrayList<>();
try (BufferedReader in = new BufferedReader(new FileReader("Test.txt"))) {
String line = null;
while((line = in.readLine()) != null) {
String[] values = line.split(",");
autos.add(new Auto(
Integer.parseInt(values[0]),
values[1],
values[2],
Double.parseDouble(values[3]),
values[4]));
}
}
you can create stream from the lines then you can apply the Function(ArrayList< String >,ArrayList< Auto >) interface to get data by defining custom behaviour through lambda function. To convert data to integer from String use Integer.parse(String) and for double data use Double.parse(string)
Using Java 8 stream:
try (Stream<String> fileStream = Files.lines(Paths.get("Test.txt"))) {
fileStream.map(line -> line.split(",")).forEach(array -> {
Auto auto = new Auto(Integer.parseInt(array[0]), array[1], array[2], Double.parseDouble(array[3]), array[4]);
});
}
You can collect the auto to list by:
List<Auto> autoList;
try (Stream<String> fileStream = Files.lines(Paths.get("Test.txt"))) {
autoList = fileStream.map(line -> {
String[] array = line.split(",");
return new Auto(Integer.parseInt(array[0]), array[1], array[2], Double.parseDouble(array[3]), array[4]);
}).collect(Collectors.toList());
}
Following your current scheme, here one way I might carry out the task. The code also validates the data and places defaults if those validations fail.
public List<Auto> getAutoListFromFile(String filePath) {
List<Auto> list = new ArrayList<>(); // Declare a List Interface
Auto auto; // Declare Auto
// Open a file reader. Try With Resourses is used here so as to auto close reader.
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line = "";
// Iterate through the file lines
while((line = reader.readLine()) != null) {
line = line.trim(); // Trim lines of any unwanted leading or trailing whitespaces, tabs, etc.
// Skip blank lines.
if (line.equals("")) {
continue;
}
System.out.println(line); // Display file line to console (remove if desired).
/* Split the current comma delimited file line into specific components.
A regex is used here to cover all comma/space scenarios (if any). */
String[] lineParts = line.split("\\s{0,},\\s{0,}");
// Establish the first Auto memeber value for the Auto class constructor.
int id = -1; // default
// Make sure it is an unsigned Integer value. RegEx is used here again.
if (lineParts[0].matches("\\d+")) {
id = Integer.parseInt(lineParts[0]);
}
// Establish the second Auto memeber value for the Auto class constructor.
String cont = !lineParts[1].equals("") ? lineParts[1] : "N/A"; //Ternary Used
// Establish the third Auto memeber value for the Auto class constructor.
String details = !lineParts[2].equals("") ? lineParts[2] : "N/A"; //Ternary Used
// Establish the fourth Auto memeber value for the Auto class constructor.
double price = 0.0d; //default
// Make sure it is a signed or unsigned Integer or double value. RegEx is used here again.
if (lineParts[3].matches("-?\\d+(\\.\\d+)?")) {
price = Double.parseDouble(lineParts[3]);
}
// Establish the fifth Auto memeber value for the Auto class constructor.
String asd = !lineParts[4].equals("") ? lineParts[4] : "N/A"; //Ternary Used
auto = new Auto(id, cont, details, price, asd); // Create an instance of Auto
list.add(auto); // Add Auto instance to List.
// Go and read next line if one exists
}
}
// Handle Exceptions.
catch (FileNotFoundException ex) {
Logger.getLogger("getAutoListFromFile() Method Error!").log(Level.SEVERE, null, ex);
}
catch (IOException ex) {
Logger.getLogger("getAutoListFromFile() Method Error!").log(Level.SEVERE, null, ex);
}
return list; // Return the filled list.
}
And to use this method you might do:
List<Auto> list = getAutoListFromFile("Test.txt");
For int you can use
int a = Integer.parseInt(string);
Almost the same for the double
double b = Double.parseDouble(string);
But be aware that both can throw NumberFormatException if the string is not what it is meant to be.
I'm working on a program that needs to update a line that depends its value on the result of a line that goes read after. I thought that I could use two BufferedReaders in Java to position the reader on the line to update while the other one goes for the line that fixes the value (it can be an unknown number of lines ahead). The problem here is that I'm using two BufferedReaders on the same file and even if I think I'm doing right with the indexes the result in debug doesn't seem to be reliable.
Here's the code:
String outFinal
FileName=fileOut;
File fileDest=new File(outFinalFileName);
try {
fout = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(fileDest)));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
FileReader inputFile=null;
try {
inputFile = new FileReader(inFileName);
} catch (FileNotFoundException e2) {
e2.printStackTrace();
}
BufferedReader fin = new BufferedReader(inputFile);
BufferedReader finChecker = new BufferedReader(inputFile); //Checks the file and matches record to change
String line="";
String lineC="";
int lineNumber=0;
String recordType="";
String statusCode="";
try {
while ((lineC = finChecker.readLine()) != null) {
lineNumber++;
if (lineNumber==1)
line=fin.readLine();
recordType=lineC.substring(0,3);//Gets current Record Type
if (recordType.equals("35")){
while(!line.equals(lineC)){
line=fin.readLine();
if (line==null)
break;
fout.write(line);
}
}else if (recordType.equals("32")){
statusCode=lineC.substring(4,7);
if(statusCode.equals("XX")){
updateRecordLine(line,fout);
}
}
}
returnVal=true;
} catch (IOException e) {
e.printStackTrace();
}
Thanks in advance.
Well, the BufferedReader only reads stuff, it doesn't have the ability to write data back out. So, what you would need is a BufferedReader to get stuff in, and a BufferedWriter that takes all the input from the BufferedReader, and outputs it to a temp file, with the corrected/appended data.
Then, when you're done (i.e. both BufferedReader and BufferedWriter streams are closed), you need to either discard the original file, or rename the temp file to the name of the original file.
You are basically copying the original file to a temp file, modifying the line in question in the temp file's output, and then copying/renaming the temp file over the original.
ok, i see some problem in your code exactly on these lines-->
recordType=lineC.substring(0,3);//Gets current Record Type
if (recordType.equals("35")){
if you see on the first line, you are getting the substring of recordType into recordType. Now recordType length is 3. If at all the recordType has only 2 characters, then substring throws arrayIndexOutOfBoundsException. So when no runtime exceptions, its length is 3 and on the next line you are calling the equals method that has a string with 2 characters.
Will this if block ever run ?
I'm reading numbers from a txt file using BufferedReader for analysis. The way I'm going about this now is- reading a line using .readline, splitting this string into an array of strings using .split
public InputFile () {
fileIn = null;
//stuff here
fileIn = new FileReader((filename + ".txt"));
buffIn = new BufferedReader(fileIn);
return;
//stuff here
}
public String ReadBigStringIn() {
String line = null;
try { line = buffIn.readLine(); }
catch(IOException e){};
return line;
}
public ProcessMain() {
initComponents();
String[] stringArray;
String line;
try {
InputFile stringIn = new InputFile();
line = stringIn.ReadBigStringIn();
stringArray = line.split("[^0-9.+Ee-]+");
// analysis etc.
}
}
This works fine, but what if the txt file has multiple lines of text? Is there a way to output a single long string, or perhaps another way of doing it? Maybe use while(buffIn.readline != null) {}? Not sure how to implement this.
Ideas appreciated,
thanks.
You are right, a loop would be needed here.
The usual idiom (using only plain Java) is something like this:
public String ReadBigStringIn(BufferedReader buffIn) throws IOException {
StringBuilder everything = new StringBuilder();
String line;
while( (line = buffIn.readLine()) != null) {
everything.append(line);
}
return everything.toString();
}
This removes the line breaks - if you want to retain them, don't use the readLine() method, but simply read into a char[] instead (and append this to your StringBuilder).
Please note that this loop will run until the stream ends (and will block if it doesn't end), so if you need a different condition to finish the loop, implement it in there.
I would strongly advice using library here but since Java 8 you can do this also using streams.
try (InputStreamReader in = new InputStreamReader(System.in);
BufferedReader buffer = new BufferedReader(in)) {
final String fileAsText = buffer.lines().collect(Collectors.joining());
System.out.println(fileAsText);
} catch (Exception e) {
e.printStackTrace();
}
You can notice also that it is pretty effective as joining is using StringBuilder internally.
If you just want to read the entirety of a file into a string, I suggest you use Guava's Files class:
String text = Files.toString("filename.txt", Charsets.UTF_8);
Of course, that's assuming you want to maintain the linebreaks. If you want to remove the linebreaks, you could either load it that way and then use String.replace, or you could use Guava again:
List<String> lines = Files.readLines(new File("filename.txt"), Charsets.UTF_8);
String joined = Joiner.on("").join(lines);
Sounds like you want Apache IO FileUtils
String text = FileUtils.readStringFromFile(new File(filename + ".txt"));
String[] stringArray = text.split("[^0-9.+Ee-]+");
If you create a StringBuilder, then you can append every line to it, and return the String using toString() at the end.
You can replace your ReadBigStringIn() with
public String ReadBigStringIn() {
StringBuilder b = new StringBuilder();
try {
String line = buffIn.readLine();
while (line != null) {
b.append(line);
line = buffIn.readLine();
}
}
catch(IOException e){};
return b.toString();
}
You have a file containing doubles. Looks like you have more than one number per line, and may have multiple lines.
Simplest thing to do is read lines in a while loop.
You could return null from your ReadBigStringIn method when last line is reached and terminate your loop there.
But more normal would be to create and use the reader in one method. Perhaps you could change to a method which reads the file and returns an array or list of doubles.
BTW, could you simply split your strings by whitespace?
Reading a whole file into a single String may suit your particular case, but be aware that it could cause a memory explosion if your file was very large. Streaming approach is generally safer for such i/o.
This creates a long string, every line is seprateted from string " " (one space):
public String ReadBigStringIn() {
StringBuffer line = new StringBuffer();
try {
while(buffIn.ready()) {
line.append(" " + buffIn.readLine());
} catch(IOException e){
e.printStackTrace();
}
return line.toString();
}
A file name will be passed in from standard in. I want to open it, read it, and create some information based off the text in the file.
For example, if this is a line in the file:
Hristo 3
... then I want to create a Member() named Hristo with a value of 3. So I want to pull out a String for the name and an int for the value. The name and the value are separated by some unknown number of tabs and spaces which I need to ignore. Could I just read the line, use .trim() to get rid of whitespace, and the last character would be the value?
I have not shown the class Member() for simplicity's sake. This is what I have so far:
public static void main(String[] args) {
int numMembers = 0;
ArrayList<Member> veteranMembers = new ArrayList<Member>();
File file = new File(args[0]);
FileReader fr;
BufferedReader br;
// attempt to open and read file
try {
fr = new FileReader(file);
br = new BufferedReader(fr);
String line;
// read file
while ((line = br.readLine()) != null) {
// extract name and value from line
... ? ...
// create member
// initialize name and value
Member member = new Member();
veteranMembers.add(member);
}
br.close();
} catch (FileNotFoundException e1) {
// Unable to find file.
e1.printStackTrace();
} catch (IOException e) {
// Unable to read line.
e.printStackTrace();
}
}
How would I parse that line of text?
Thanks in advance for your help.
I would use the split function.
You can give it a regular expression as the argument
i.e.
line.split(" |\t");
will return array of the words ( {list[0] = Hristo, list[1] = 3} in your example)
Hope it helps.
Use split("\\s+"), this regex ignore any space, tab, etc from the String.
A more robust way might be to use regular expressions; if you received malformed input (e.g., "Ted One"), parseInt() would throw a NumberFormatException.
import java.util.regex.*;
...
Pattern p = Pattern.compile("^(.*)\\s+(\\d+)$"); // Create a regex Pattern that only matches (text - white space - integer)
Matcher m = p.matcher(line); // Create a Matcher to test the input line
if(m.find()){
// If there's a match, ..
String name = m.group(1); // Set "name" to the first parenthesized group
String value = m.group(2); // Set "value" to the second parenthesized group
}
else{
// Bad Input
}
Looks like a home work. You came really close doing it. Use StringTokenizer to tokenize the line. Then create a new member object and and call setters for both the attributes with tokens as params. If your second attribute is an int use parseInt to convert and assign it.