Reading new data from a constantly updating file in Java
I have a log file which is constantly updated with new lines of data. I need to get new added data in java as soon as it's written. For now my solution is:
public static void readNonStop(String filename, boolean goToEnd, FileReadCallback readCallback) {
if(readCallback == null) {
return;
}
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
String line = br.readLine();
int lineNumber = 0;
if(goToEnd) {
while(br.readLine() != null) {}
}
while (true) {
if(line != null) {
readCallback.onRead(lineNumber++, line);
} else {
Thread.sleep(1);
}
line = br.readLine();
}
} finally {
br.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
But I have a feeling that there should be a better way. I don't like the idea of a constant running loop with a "sleep" inside and would prefer some sort of an event driven approach.
If I rely on FileSystem events to reopen the file each time it is modified, it introduces a delay.
What is the correct way of doing it for this situation?
java file io stream
New contributor
|
show 3 more comments
I have a log file which is constantly updated with new lines of data. I need to get new added data in java as soon as it's written. For now my solution is:
public static void readNonStop(String filename, boolean goToEnd, FileReadCallback readCallback) {
if(readCallback == null) {
return;
}
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
String line = br.readLine();
int lineNumber = 0;
if(goToEnd) {
while(br.readLine() != null) {}
}
while (true) {
if(line != null) {
readCallback.onRead(lineNumber++, line);
} else {
Thread.sleep(1);
}
line = br.readLine();
}
} finally {
br.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
But I have a feeling that there should be a better way. I don't like the idea of a constant running loop with a "sleep" inside and would prefer some sort of an event driven approach.
If I rely on FileSystem events to reopen the file each time it is modified, it introduces a delay.
What is the correct way of doing it for this situation?
java file io stream
New contributor
1
Consider Tailer class from Apache Commons.
– vnp
Dec 27 '18 at 20:30
Welcome to Code Review. I hope you get some good reviews, and I hope to see more of your contributions here in future!
– Zeta
Dec 27 '18 at 20:33
@vnp, wow, looks like what I need. While a bit more robust,Tailer
uses the same logic as my code, it reads in a loop with aThread.sleep
delay. But it feels good to confirm that I had the right idea, thanks! @Zeta, thank you!
– Arthur
Dec 27 '18 at 20:43
1
Maybe there is a "native" solution too: dzone.com/articles/how-watch-file-system-changes or docs.oracle.com/javase/tutorial/essential/io/notification.html
– Timothy Truckle
Dec 27 '18 at 20:45
1
WatcherService
introduces a delay up to 6 seconds in my tests, so unfortunately it is not an option. Looks like I will go with a looped read.
– Arthur
Dec 27 '18 at 20:48
|
show 3 more comments
I have a log file which is constantly updated with new lines of data. I need to get new added data in java as soon as it's written. For now my solution is:
public static void readNonStop(String filename, boolean goToEnd, FileReadCallback readCallback) {
if(readCallback == null) {
return;
}
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
String line = br.readLine();
int lineNumber = 0;
if(goToEnd) {
while(br.readLine() != null) {}
}
while (true) {
if(line != null) {
readCallback.onRead(lineNumber++, line);
} else {
Thread.sleep(1);
}
line = br.readLine();
}
} finally {
br.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
But I have a feeling that there should be a better way. I don't like the idea of a constant running loop with a "sleep" inside and would prefer some sort of an event driven approach.
If I rely on FileSystem events to reopen the file each time it is modified, it introduces a delay.
What is the correct way of doing it for this situation?
java file io stream
New contributor
I have a log file which is constantly updated with new lines of data. I need to get new added data in java as soon as it's written. For now my solution is:
public static void readNonStop(String filename, boolean goToEnd, FileReadCallback readCallback) {
if(readCallback == null) {
return;
}
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
String line = br.readLine();
int lineNumber = 0;
if(goToEnd) {
while(br.readLine() != null) {}
}
while (true) {
if(line != null) {
readCallback.onRead(lineNumber++, line);
} else {
Thread.sleep(1);
}
line = br.readLine();
}
} finally {
br.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
But I have a feeling that there should be a better way. I don't like the idea of a constant running loop with a "sleep" inside and would prefer some sort of an event driven approach.
If I rely on FileSystem events to reopen the file each time it is modified, it introduces a delay.
What is the correct way of doing it for this situation?
java file io stream
java file io stream
New contributor
New contributor
edited Dec 28 '18 at 19:20
Zeta
15.1k23474
15.1k23474
New contributor
asked Dec 27 '18 at 18:56
Arthur
1063
1063
New contributor
New contributor
1
Consider Tailer class from Apache Commons.
– vnp
Dec 27 '18 at 20:30
Welcome to Code Review. I hope you get some good reviews, and I hope to see more of your contributions here in future!
– Zeta
Dec 27 '18 at 20:33
@vnp, wow, looks like what I need. While a bit more robust,Tailer
uses the same logic as my code, it reads in a loop with aThread.sleep
delay. But it feels good to confirm that I had the right idea, thanks! @Zeta, thank you!
– Arthur
Dec 27 '18 at 20:43
1
Maybe there is a "native" solution too: dzone.com/articles/how-watch-file-system-changes or docs.oracle.com/javase/tutorial/essential/io/notification.html
– Timothy Truckle
Dec 27 '18 at 20:45
1
WatcherService
introduces a delay up to 6 seconds in my tests, so unfortunately it is not an option. Looks like I will go with a looped read.
– Arthur
Dec 27 '18 at 20:48
|
show 3 more comments
1
Consider Tailer class from Apache Commons.
– vnp
Dec 27 '18 at 20:30
Welcome to Code Review. I hope you get some good reviews, and I hope to see more of your contributions here in future!
– Zeta
Dec 27 '18 at 20:33
@vnp, wow, looks like what I need. While a bit more robust,Tailer
uses the same logic as my code, it reads in a loop with aThread.sleep
delay. But it feels good to confirm that I had the right idea, thanks! @Zeta, thank you!
– Arthur
Dec 27 '18 at 20:43
1
Maybe there is a "native" solution too: dzone.com/articles/how-watch-file-system-changes or docs.oracle.com/javase/tutorial/essential/io/notification.html
– Timothy Truckle
Dec 27 '18 at 20:45
1
WatcherService
introduces a delay up to 6 seconds in my tests, so unfortunately it is not an option. Looks like I will go with a looped read.
– Arthur
Dec 27 '18 at 20:48
1
1
Consider Tailer class from Apache Commons.
– vnp
Dec 27 '18 at 20:30
Consider Tailer class from Apache Commons.
– vnp
Dec 27 '18 at 20:30
Welcome to Code Review. I hope you get some good reviews, and I hope to see more of your contributions here in future!
– Zeta
Dec 27 '18 at 20:33
Welcome to Code Review. I hope you get some good reviews, and I hope to see more of your contributions here in future!
– Zeta
Dec 27 '18 at 20:33
@vnp, wow, looks like what I need. While a bit more robust,
Tailer
uses the same logic as my code, it reads in a loop with a Thread.sleep
delay. But it feels good to confirm that I had the right idea, thanks! @Zeta, thank you!– Arthur
Dec 27 '18 at 20:43
@vnp, wow, looks like what I need. While a bit more robust,
Tailer
uses the same logic as my code, it reads in a loop with a Thread.sleep
delay. But it feels good to confirm that I had the right idea, thanks! @Zeta, thank you!– Arthur
Dec 27 '18 at 20:43
1
1
Maybe there is a "native" solution too: dzone.com/articles/how-watch-file-system-changes or docs.oracle.com/javase/tutorial/essential/io/notification.html
– Timothy Truckle
Dec 27 '18 at 20:45
Maybe there is a "native" solution too: dzone.com/articles/how-watch-file-system-changes or docs.oracle.com/javase/tutorial/essential/io/notification.html
– Timothy Truckle
Dec 27 '18 at 20:45
1
1
WatcherService
introduces a delay up to 6 seconds in my tests, so unfortunately it is not an option. Looks like I will go with a looped read.– Arthur
Dec 27 '18 at 20:48
WatcherService
introduces a delay up to 6 seconds in my tests, so unfortunately it is not an option. Looks like I will go with a looped read.– Arthur
Dec 27 '18 at 20:48
|
show 3 more comments
2 Answers
2
active
oldest
votes
You can use the Java WatchService
as described here. You said that WatchService
is too slow for you. There are other people who have had that problem and resolved it https://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-elsein this thread.
On a side note, consider using ScheduledThreadPoolExecutor
rather than Thread.sleep
. The former will recreate threads if they are killed by an exception, has the potential to reuse threads in a pool, and has other potential advantages.
New contributor
add a comment |
try
-with-resources
BufferedReader
implements AutoCloseable
, so instead of
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
You can say
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
and then get rid of your finally
block.
} finally {
br.close();
}
Also, this should allow you to merge the two try
statements into one, as the resource declaration is inside the scope of the try
if it throws an exception.
Odd behavior
String line = br.readLine();
int lineNumber = 0;
So you read the first line of the file. Then, if a Boolean is true, you skip all the other lines of the file without counting them (even though you just declared a variable to count them). Then you process the first line of the file. Why not
if (goToEnd) {
while (br.readLine() != null) {}
}
// we only want to count lines past the current end of file
int lineNumber = 0;
while (true) {
String line = br.readline();
while (line == null) {
Thread.sleep(1);
line = br.readLine();
}
readCallback.onRead(lineNumber++, line);
}
Now it's clearer that lineNumber
has nothing to do with the part before the end of the current file. And we don't process the first line of the file and then a much later line. Each line
lasts only one iteration of the loop.
If the condition is false, a while
acts just like an if
. But if the condition is true, we can stay in the loop.
If this is not the behavior that you want, please add comments to your code explaining why. E.g. "We always need to read the first line of the file as line number 0, even if we skip the rest of the existing lines. This is because the first line has the column headers."
Thanks for your answer, though lineNumber is not relevant anymore.
– Arthur
Dec 28 '18 at 9:55
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Arthur is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210444%2freading-new-data-from-a-constantly-updating-file-in-java%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can use the Java WatchService
as described here. You said that WatchService
is too slow for you. There are other people who have had that problem and resolved it https://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-elsein this thread.
On a side note, consider using ScheduledThreadPoolExecutor
rather than Thread.sleep
. The former will recreate threads if they are killed by an exception, has the potential to reuse threads in a pool, and has other potential advantages.
New contributor
add a comment |
You can use the Java WatchService
as described here. You said that WatchService
is too slow for you. There are other people who have had that problem and resolved it https://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-elsein this thread.
On a side note, consider using ScheduledThreadPoolExecutor
rather than Thread.sleep
. The former will recreate threads if they are killed by an exception, has the potential to reuse threads in a pool, and has other potential advantages.
New contributor
add a comment |
You can use the Java WatchService
as described here. You said that WatchService
is too slow for you. There are other people who have had that problem and resolved it https://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-elsein this thread.
On a side note, consider using ScheduledThreadPoolExecutor
rather than Thread.sleep
. The former will recreate threads if they are killed by an exception, has the potential to reuse threads in a pool, and has other potential advantages.
New contributor
You can use the Java WatchService
as described here. You said that WatchService
is too slow for you. There are other people who have had that problem and resolved it https://stackoverflow.com/questions/9588737/is-java-7-watchservice-slow-for-anyone-elsein this thread.
On a side note, consider using ScheduledThreadPoolExecutor
rather than Thread.sleep
. The former will recreate threads if they are killed by an exception, has the potential to reuse threads in a pool, and has other potential advantages.
New contributor
New contributor
answered Dec 28 '18 at 15:49
Max
1212
1212
New contributor
New contributor
add a comment |
add a comment |
try
-with-resources
BufferedReader
implements AutoCloseable
, so instead of
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
You can say
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
and then get rid of your finally
block.
} finally {
br.close();
}
Also, this should allow you to merge the two try
statements into one, as the resource declaration is inside the scope of the try
if it throws an exception.
Odd behavior
String line = br.readLine();
int lineNumber = 0;
So you read the first line of the file. Then, if a Boolean is true, you skip all the other lines of the file without counting them (even though you just declared a variable to count them). Then you process the first line of the file. Why not
if (goToEnd) {
while (br.readLine() != null) {}
}
// we only want to count lines past the current end of file
int lineNumber = 0;
while (true) {
String line = br.readline();
while (line == null) {
Thread.sleep(1);
line = br.readLine();
}
readCallback.onRead(lineNumber++, line);
}
Now it's clearer that lineNumber
has nothing to do with the part before the end of the current file. And we don't process the first line of the file and then a much later line. Each line
lasts only one iteration of the loop.
If the condition is false, a while
acts just like an if
. But if the condition is true, we can stay in the loop.
If this is not the behavior that you want, please add comments to your code explaining why. E.g. "We always need to read the first line of the file as line number 0, even if we skip the rest of the existing lines. This is because the first line has the column headers."
Thanks for your answer, though lineNumber is not relevant anymore.
– Arthur
Dec 28 '18 at 9:55
add a comment |
try
-with-resources
BufferedReader
implements AutoCloseable
, so instead of
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
You can say
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
and then get rid of your finally
block.
} finally {
br.close();
}
Also, this should allow you to merge the two try
statements into one, as the resource declaration is inside the scope of the try
if it throws an exception.
Odd behavior
String line = br.readLine();
int lineNumber = 0;
So you read the first line of the file. Then, if a Boolean is true, you skip all the other lines of the file without counting them (even though you just declared a variable to count them). Then you process the first line of the file. Why not
if (goToEnd) {
while (br.readLine() != null) {}
}
// we only want to count lines past the current end of file
int lineNumber = 0;
while (true) {
String line = br.readline();
while (line == null) {
Thread.sleep(1);
line = br.readLine();
}
readCallback.onRead(lineNumber++, line);
}
Now it's clearer that lineNumber
has nothing to do with the part before the end of the current file. And we don't process the first line of the file and then a much later line. Each line
lasts only one iteration of the loop.
If the condition is false, a while
acts just like an if
. But if the condition is true, we can stay in the loop.
If this is not the behavior that you want, please add comments to your code explaining why. E.g. "We always need to read the first line of the file as line number 0, even if we skip the rest of the existing lines. This is because the first line has the column headers."
Thanks for your answer, though lineNumber is not relevant anymore.
– Arthur
Dec 28 '18 at 9:55
add a comment |
try
-with-resources
BufferedReader
implements AutoCloseable
, so instead of
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
You can say
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
and then get rid of your finally
block.
} finally {
br.close();
}
Also, this should allow you to merge the two try
statements into one, as the resource declaration is inside the scope of the try
if it throws an exception.
Odd behavior
String line = br.readLine();
int lineNumber = 0;
So you read the first line of the file. Then, if a Boolean is true, you skip all the other lines of the file without counting them (even though you just declared a variable to count them). Then you process the first line of the file. Why not
if (goToEnd) {
while (br.readLine() != null) {}
}
// we only want to count lines past the current end of file
int lineNumber = 0;
while (true) {
String line = br.readline();
while (line == null) {
Thread.sleep(1);
line = br.readLine();
}
readCallback.onRead(lineNumber++, line);
}
Now it's clearer that lineNumber
has nothing to do with the part before the end of the current file. And we don't process the first line of the file and then a much later line. Each line
lasts only one iteration of the loop.
If the condition is false, a while
acts just like an if
. But if the condition is true, we can stay in the loop.
If this is not the behavior that you want, please add comments to your code explaining why. E.g. "We always need to read the first line of the file as line number 0, even if we skip the rest of the existing lines. This is because the first line has the column headers."
try
-with-resources
BufferedReader
implements AutoCloseable
, so instead of
try {
BufferedReader br = new BufferedReader(new FileReader(filename));
try {
You can say
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
and then get rid of your finally
block.
} finally {
br.close();
}
Also, this should allow you to merge the two try
statements into one, as the resource declaration is inside the scope of the try
if it throws an exception.
Odd behavior
String line = br.readLine();
int lineNumber = 0;
So you read the first line of the file. Then, if a Boolean is true, you skip all the other lines of the file without counting them (even though you just declared a variable to count them). Then you process the first line of the file. Why not
if (goToEnd) {
while (br.readLine() != null) {}
}
// we only want to count lines past the current end of file
int lineNumber = 0;
while (true) {
String line = br.readline();
while (line == null) {
Thread.sleep(1);
line = br.readLine();
}
readCallback.onRead(lineNumber++, line);
}
Now it's clearer that lineNumber
has nothing to do with the part before the end of the current file. And we don't process the first line of the file and then a much later line. Each line
lasts only one iteration of the loop.
If the condition is false, a while
acts just like an if
. But if the condition is true, we can stay in the loop.
If this is not the behavior that you want, please add comments to your code explaining why. E.g. "We always need to read the first line of the file as line number 0, even if we skip the rest of the existing lines. This is because the first line has the column headers."
answered Dec 28 '18 at 2:10
mdfst13
17.4k52156
17.4k52156
Thanks for your answer, though lineNumber is not relevant anymore.
– Arthur
Dec 28 '18 at 9:55
add a comment |
Thanks for your answer, though lineNumber is not relevant anymore.
– Arthur
Dec 28 '18 at 9:55
Thanks for your answer, though lineNumber is not relevant anymore.
– Arthur
Dec 28 '18 at 9:55
Thanks for your answer, though lineNumber is not relevant anymore.
– Arthur
Dec 28 '18 at 9:55
add a comment |
Arthur is a new contributor. Be nice, and check out our Code of Conduct.
Arthur is a new contributor. Be nice, and check out our Code of Conduct.
Arthur is a new contributor. Be nice, and check out our Code of Conduct.
Arthur is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210444%2freading-new-data-from-a-constantly-updating-file-in-java%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Consider Tailer class from Apache Commons.
– vnp
Dec 27 '18 at 20:30
Welcome to Code Review. I hope you get some good reviews, and I hope to see more of your contributions here in future!
– Zeta
Dec 27 '18 at 20:33
@vnp, wow, looks like what I need. While a bit more robust,
Tailer
uses the same logic as my code, it reads in a loop with aThread.sleep
delay. But it feels good to confirm that I had the right idea, thanks! @Zeta, thank you!– Arthur
Dec 27 '18 at 20:43
1
Maybe there is a "native" solution too: dzone.com/articles/how-watch-file-system-changes or docs.oracle.com/javase/tutorial/essential/io/notification.html
– Timothy Truckle
Dec 27 '18 at 20:45
1
WatcherService
introduces a delay up to 6 seconds in my tests, so unfortunately it is not an option. Looks like I will go with a looped read.– Arthur
Dec 27 '18 at 20:48