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 ?
Related
Is there in Java some sort of equivalent to BufferedReader.skip(), that would take number of lines as parameter instead of number of characters?
I want to jump to a specific line in a text file and start reading from that point without the need going thru all the lines of the file and checking against the line number (tens of thousands of them - model obj file).
All the examples I saw were dealing with the checking of line number which is not what I want.
So, the solution is to use FileInputStream.skip().
UPDATE: manually adding system-specific new line separator bytes length to line bytes length at each line iteration solved the problem of erroneous bytes skipping, so now it finally works as expected!
Define some Long variable where you will store the number of bytes to skip. I did that in my main application class (App.class):
public static long lineByteOffset = 0;
Then, in your method/function where you read your lines with BufferedReder make it like this (all my files that I read from are encoded as UTF-8):
File objFile = new File(PATH_TO_YOUR_FILE_HERE);
FileInputStream fir = null;
try {
fir = new FileInputStream(objFile);
} catch (FileNotFoundException e) {
System.err.println("File not found!");
}
fir.skip(App.lineByteOffset);//<--- 1ST IMPORTANT PART: SET HOW MANY BYTES TO SKIP, YOU START WITH 0 FOR THE 1ST TIME
BufferedReader reader = new BufferedReader(new InputStreamReader(fir, "UTF-8"));
int nls = System.getProperty("line.separator").getBytes().length;
String line;
try {
while ((line = reader.readLine()) != null) {
App.lineByteOffset += (long) (line.getBytes().length + nls);//<--- 2ND IMPORTANT PART: INCREASE NUMBER OF BYTES TO SKIP FOR NEXT TIME
/*
DO YOUR STUFF HERE...
IN MY CASE IT RETURNS SPECIFIC BLOCK
WHICH IN EFFECT EXIT THE WHILE LOOP AS NEEDED
SO THAT THE NEXT TIME IT CONTINUE WHERE WE LEFT IT
WITHOUT NEED TO READ THE WHOLE FILE FROM THE START ONCE AGAIN
*/
}
reader.close();
} catch (IOException e) {
System.err.println("Error reading the file");
}
I tried to archive that a multiline file will be read from an BufferedReader. But this BufferedReader reads just one line and exiting his while(). Before he can read this, another method of the same class should've been written in this file (not at the same time), mostly more than one line. The file contains different types of variables, such as int[], int, double[], String. At the end of one object, or nearly just the data that I've to collect that I can re-calculate the whole object, the ObjectOutputStream pastes "\n". I just write parsed Strings in this file.
In my case, it's a workaround for the ObjectInputStream, cause this stream throws an EOFException every time. For those who don't know the EOFException: it will be thrown if the reader reaches end of file while reading.
I tried to:
set the input string for the BufferedReader to another line
.close() the Reader and make it new
set while(1)
write other Datatypes, such as the whole Object
but all without any changes. The BufferedReader reads just one line and the ObjectInputStream throws EOFException.
LinkedList<SomeAnotherSelfMadeClass> list;
File file = new File(fullPath) // fullPath = absolute path to the file
FileInputStream fileInputStream;
BufferedReader bufferedReader;
public static LinkedList<SomeAnotherSelfMadeClass> readFile()
{
list = new LinkedList<SomeAnotherSelfMadeClass>();
fileInputStream = new FileInputStream(file); // could be FileReader
bufferedReader = new BufferedReader(fileInputStream);
String helper, anotherHelper;
while ((helper = bufferedReader.readLine()) != null)
{
while ((anotherHelper = scanner.hasNext()) != null)
// here's some code with scanner-things, it shouldn't be necessary to
// know. In fact the scanner help to gather the data from the file and
// create an object of SomeAnotherSelfMadeCLass and put it into the list
}
bufferedReader.close();
fileInputStream.close();
return list;
}
What can I do that I can read all lines of the file and re-calcuate my objects that are pasted in there?
I don't know either; it is better to work with the ObjectInputStream or with the BufferedReader? What can I do that the ObjectInputStream don't throws the EOFException (every time I worked with the ObjectInputStream I wrote the whole Object via ObjectOutputStream)?
P.S.: I don't have internet atm at home, so it could take a while that I'm able to answer.
Try with this structure of code..
BufferedReader objReader = null;
public static LinkedList<SomeAnotherSelfMadeClass> readFile()
{
list = new LinkedList<SomeAnotherSelfMadeClass>();
try {
objReader = new BufferedReader(new FileReader(fullPath));
while ((helper= objReader.readLine()) != null) {
...........
System.out.println(helper);//just for checking
while ((anotherHelper = scanner.hasNextLine()) != null){
.....
....
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (objReader != null)
objReader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
I'm a little idiot, you have to know.
The second while() had the condition (anotherHelper = scanner.next()) != null, not that what I stated before.
But I managed to get another outputs, even I tried this before (it seems that I'd misstyped at any point);
I set the first while() to true, test helper to break out of the while() and deleted the second while:
while(true)
{
helper = bufferedReader.readLine();
if (helper.equals(null))
break;
// making things with the scanner
}
It seems that the compiler had a problem with this double-while. And optimized it wrong; I think he made
while (((helper = bufferedReader.readLine() != null) && (helper = scanner.nextLine()) != null)
out of this peace of code. That would explain why it only run once and returns true if I test it with System.out.println(scanner.hasNext(); and System.out.println(scanner.hasNextLine(); BEFORE the second while, but in it he returns not even false.
For the record, I know that reading the text file to a string does not ALWAYS result in an empty string, but in my situation, I can't get it to do anything else.
I'm currently trying to write a program that reads text from a .txt file, manipulates it based on certain arguments, and then saves the text back into the document. No matter how many different ways I've tried, I can't seem to actually get text from .txt file. The string just returns as an empty string.
For example, I pass in the arguments "-c 3 file1.txt" and parse the arguments for the file (the file is always passed in last). I get the file with:
File inputFile = new File(args[args.length - 1]);
When I debug the code, it seems to recognize the file as file1.txt and if I pass in the name of a different file, which doesn't exist, and error is thrown. So it is correctly recognizing this file. From here I have attempted every type of file text parsing I can find online, from old Java version techniques up to Java 8 techniques. None have worked. A few I've tried are:
String fileText = "";
try {
Scanner input = new Scanner(inputFile);
while (input.hasNextLine()) {
fileText = input.nextLine();
System.out.println(fileText);
}
input.close();
} catch (FileNotFoundException e) {
usage();
}
or
String fileText = null;
try {
fileText = new String(Files.readAllBytes(Paths.get(filename)), StandardCharsets.UTF_8);
} catch (IOException e) {
e.printStackTrace();
}
I've tried others too. Buffered readers, scanners, etc. I've tried recompiling the project, I've tried 3rd party libraries. Still just getting an empty string. I'm thinking it must be some sort of configuration issue, but I am stumped.
For anyone wondering, the file seems to be in the correct place, when I reference the wrong location an exception is thrown. And the file DOES in fact have text in it. I've quadruple checked.
Even though your first code snippet might read the file, it does in fact not store the contents of the file in your fileText variable but only the file's last line.
With
fileText = input.nextLine();
you set fileText to the contents of the current line thereby overwriting the previous value of fileText. You need to store all the lines from your file. E.g. try
static String read( String path ) throws IOException {
StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
for (String line = br.readLine(); line != null; line = br.readLine()) {
sb.append(line).append('\n');
}
}
return sb.toString();
}
My suggestion would be to create a method for reading the file into a string which throws an exception with a descriptive message whenever an unexpected state is found. Here is a possible implementation of this idea:
public static String readFile(Path path) {
String fileText;
try {
if(Files.size(path) == 0) {
throw new RuntimeException("File has zero bytes");
}
fileText = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
if(fileText.trim().isEmpty()) {
throw new RuntimeException("File contains only whitespace");
}
return fileText;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
This method checks 3 anomalies:
File not found
File empty
File contains only spaces
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I am trying to make a change log and so I need a single line between some sentences.
All I have is this but it doesn't seem to work. Can anyone help me please?
#Test
public void addLine() {
File temp;
try {
temp = File.createTempFile("app.log", ".tmp", new File("."));
File appLog = new File("app.log");
try (BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
BufferedReader br = new BufferedReader(new FileReader(
appLog))) {
String line;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
if ("2 A".equals(line)) {
bw.write("New Line!");
bw.newLine();
}
}
appLog.delete();
temp.renameTo(appLog);
}
} catch (IOException e) {
e.printStackTrace();
}
}
The problem that you might be encountering might be because of the "line separator" used by the BufferedWriter (it gets set when you create said class). I think it would be best to use instead:
System.getProperty("line.separator");
This way you use the System's line separator rather than a hard coded one.
So that your code would look like this:
public void addLine() {
String lineseparator=System.getProperty("line.separator");
// I'd suggest putting this as a class variable, so that it only gets called once rather
// than
// everytime you call the addLine() method
try {
FileWriter stream = new FileWriter(this.log, true);
//If you don't add true as the second parameter, then your file gets rewritten
// instead of appended to
BufferedWriter out = new BufferedWriter(stream);
out.write(lineseparator); //This substitutes your out.newline(); call
out.close();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
##############################################################################.
I will try to be as brief and clear as possible.
I assume that you are opening a file that in my code I call "test.txt" and it's got about a paragraph or so. And that you want that outputted to another file, but with "empty lines" at some points.
Because File() is read line by line, it is much easier to open your main file read a line, and then write it to your log file, then analyse if an empty line is necessary and place it.
Let's see some code then.
// Assume you have a private class variable called
private String lineseparator=System.getProperty("line.separator");
// This method is in charge of calling the method that actually carries out the
// reading and writing. I separate them both because I find it is much cleaner
// to have the try{}catch{} blocks in different methods. Though sometimes for
// logging purposes this is not the best choice
public void addLines() {
try {
readAndWrite();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// This method is in charge of reading one file and output to another.
public void readAndWrite() throws IOException {
File test = new File("test.txt");
FileWriter writer = writer = new FileWriter(new File("log.txt"), true);
//This FileWriter is in charge of writing to your log file
String line;
boolean conditionToWriteNewLine=true;
//Obviously this needs to be changed to suit your situation
// I just added it for show
BufferedReader reader = new BufferedReader( new FileReader (test));
BufferedWriter out = new BufferedWriter(writer);
//It is in this while loop that you read a line
// Analyze whether it needs to have a new line or not
// and then write it out to log file
while( ( line = reader.readLine() ) != null ) {
out.write(line);
if(conditionToWriteNewLine){
out.write(this.lineseparator);
out.write(this.lineseparator);
//You need to write it twice for an EMPTY LINE
}
}
reader.close();
out.close();
}
One of the big differences from this code is that I only open the files once, while in your code you open the log file every time you want to add a new file. You should read the documentation, so you'll know that every time you open the file, your cursor is pointing to the first line, so anything you add will be added to first line.
I hope this helped you understand some more.
I'm not totally sure what you are asking for, but have you tried setting the "append" flag on true, so the FileWriter will not start a new file, but append content to it at the end? This is done by calling the FileWriter(File, boolean) constructor:
public void addLine() {
try {
FileWriter stream = new FileWriter(this.log, true); // Here!
BufferedWriter out = new BufferedWriter(stream);
out.write("New Extra Line Here");
out.newLine();
out.close();
stream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I need a single line between some sentences
I guess you mean a new line between other lines of the same file.
To do so you have to read the whole file, locate the place where you want to insert a line, insert the line then write the new content to the file.
This should work fine for small files but if you have large files you might get in trouble.
So you need a more scaleable way of doing it: Read line by line, and write write to a temp file. if you indentify the location where a new line should be inserted, write that line. Continue with the rest of the file. After you are done delete the original file and rename the temp file with the original name.
Pseudocode:
Open actual file
Open temp file
while not end of actual file
Read one line from actual file
Check if new line has to inserted now
Yes: write new line to temp
write line from actual to temp
Close actual file
Close temp file
Delete actual
Rename temp to actual
Code example: (unlike the pseudo code, the new line is inserted after)
Here the line "New Line!" is inserted after each line which is equal to "2 A".
#Test
public void insertNewLineIntoFile() throws IOException {
File temp = File.createTempFile("app.log", ".tmp", new File("."));
File appLog = new File("app.log");
try (BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
BufferedReader br = new BufferedReader(new FileReader(appLog))) {
String line;
while((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
if("2 A".equals(line)) {
bw.write("New Line!");
bw.newLine();
}
}
appLog.delete();
temp.renameTo(appLog);
}
}
Note that File#delete() and File#renameTo both return a boolean value that is true onyl if the operation was successfull. You absolutely need to check those retuned values and handle accordingly.
out.println("\n");
(instead of out.newLine();)
\n in java declares a new line. If you dont add any text before it then it should just print a blank line like you want.
This will work Correctly.
Suggestion:
out.close(); and stream.close(); should write inside finally block ie they should close even if some exceptions occured.
I am writing a program in Java that requires me to compare the data in 2 files. I have to check each line from file 1 against each line of file 2 and if I find a match write them to a third file. After I read to the end of file 2, how do I reset the pointer to the beginning of the file?
public class FiFo {
public static void main(String[] args)
{
FileReader file1=new FileReader("d:\\testfiles\\FILE1.txt");
FileReader file2=new FileReader("d:\\testfiles\\FILE2.txt");
try{
String s1,s2;
while((s1=file1.data.readLine())!=null){
System.out.println("s1: "+s1);
while((s2=file2.data.readLine())!=null){
System.out.println("s2: "+s2);
}
}
file1.closeFile();
file2.closeFile();
}catch (IOException e) {
e.printStackTrace();
}
}
}
class FileReader {
BufferedReader data;
DataInputStream in;
public FileReader(String fileName)
{
try{
FileInputStream fstream = new FileInputStream(fileName);
data = new BufferedReader(new InputStreamReader(fstream));
}
catch (IOException e) {
e.printStackTrace();
}
}
public void closeFile()
{
try{
in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
I believe RandomAccessFile is what you need. It contains: RandomAccessFile#seek and RandomAccessFile#getFilePointer.
rewind() is seek(0)
I think the best thing to do would be to put each line from file 1 into a HashMap; then you could check each line of file 2 for membership in your HashMap rather than reading through the entire file once for each line of file 1.
But to answer your question of how to go back to the beginning of the file, the easiest thing to do is to open another InputStream/Reader.
Obviously you could just close and reopen the file like this:
while((s1=file1.data.readLine())!=null){
System.out.println("s1: "+s1);
FileReader file2=new FileReader("d:\\testfiles\\FILE2.txt");
while((s2=file2.data.readLine())!=null){
System.out.println("s2: "+s2);
//compare s1 and s2;
}
file2.closeFile()
}
But you really don't want to do it that way, since this algorithm's running time is O(n2). if there were 1000 lines in file A, and 10000 lines in file B, your inner loop would run 1,000,000 times.
What you should do is read each line and store it in a collection that allows quick checks to see if an item is already contained(probably a HashSet).
If you only need to check to see that every line in file 2 is in file 1, then you just add each line in file one to a HashSet, and then check to see that every line in file 2 is in that set.
If you need to do a cross comparison where you find every string that's in one but not the other, then you'll need two hash sets, one for each file. (Although there's a trick you could do to use just one)
If the files are so large that you don't have enough memory, then your original n2 method would never have worked anyway.
well, Gennady S. answer is what I would use to solve your problem.
I am writing a program in Java that requires me to compare the data in 2 files
however, I would rather not code this up again.. I would rather use something like http://code.google.com/p/java-diff-utils/
As others have suggested, you should consider other approaches to the problem. For the specific question of returning to a previous point in a file, java.io.FileReader would appear to inherit mark() and reset() methods that address this goal. Unfortunately, markSupported() returns false.
Alternatively, BufferedReader does support mark(). The program below prints true, illustrating the effect.
package cli;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class FileReaderTest {
public static void main(String[] args) {
try {
BufferedReader in = new BufferedReader(new InputStreamReader(
new FileInputStream("src/cli/FileReaderTest.java")));
in.mark(1);
int i1 = in.read(); in.read(); in.read();
in.reset();
int i2 = in.read();
System.out.println(i1 == i2);
} catch (IOException e) {
e.printStackTrace(System.err);
}
}
}
As noted, there are better algorithms - investigate these
aside:
FileReader doesn't implement mark and reset, so trashgod's comments are inaccurate.
You'd either have to implement a version of this (using RandomAccessFile or what not) or wrap in a BufferedReader. However, the latter will load the whole thing in memory if you mark it
Just a quick Question. can't you keep one object pointed at the start of the file and traverse through the file with another object? Then when you get to the end just point it to the object at the beginning of the file(stream). I believe C++ has such mechanisms with file I/O ( or is it stream I/O)
I believe that you could just re-initialize the file 2 file reader and that should reset it.
If you can clearly indentify the dimension of your file you can use mark(int readAheadLimit) and reset() from the class BufferedReader.
The method mark(int readAhedLimit) add a marker to the current position of your BufferedReader and you can go back to the marker using reset().
Using them you have to be careful to the number of characters to read until the reset(), you have to specify them as the argument of the function mark(int readAhedLimit).
Assuming a limit of 100 characters your code should look like:
class MyFileReader {
BufferedReader data;
int maxNumberOfCharacters = 100;
public MyFileReader(String fileName)
{
try{
FileInputStream fstream = new FileInputStream(fileName);
data = new BufferedReader(new InputStreamReader(fstream));
//mark the current position, in this case the beginning of the file
data.mark(maxNumberOfCharacters);
}
catch (IOException e) {
e.printStackTrace();
}
}
public void resetFile(){
data.reset();
}
public void closeFile()
{
try{
in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
If you just want to reset the file pointer to the top of the file, reinitialize your buffer reader. I assume that you are also using the try and catch block to check for end of the file.
`//To read from a file.
BufferedReader read_data_file = new BufferedReader(new FileReader("Datafile.dat"));'
Let's say this is how you have your buffer reader defined. Now, this is how you can check for end of file=null.
boolean has_data= true;
while(has_data)
{
try
{
record = read_data_file.readLine();
delimit = new StringTokenizer(record, ",");
//Reading the input in STRING format.
cus_ID = delimit.nextToken();
cus_name = delimit.nextToken();'
//And keep grabbing the data and save it in appropriate fields.
}
catch (NullPointerException e)
{
System.out.println("\nEnd of Data File... Total "+ num_of_records
+ " records were printed. \n \n");
has_data = false; //To exit the loop.
/*
------> This point is the trouble maker. Your file pointer is pointing at the end of the line.
-->If you want to again read all the data FROM THE TOP WITHOUT RECOMPILING:
Do this--> Reset the buffer reader to the top of the file.
*/
read_data_file = new BufferedReader(new FileReader(new File("datafile.dat")));
}
By reinitializing the buffer reader you will reset the file reader mark/pointer to the top of the file and you won't have to recompile the file to set the file reader marker/pointer to beginning/top of the file.
You need to reinitialize the buffer reader only if you don't want to recompile and pull off the same stunt in the same run. But if you wish to just run loop one time then you don't have to all this, by simply recompiling the file, the file reader marker will be set to the top/beginning of the file.