Java: creating file every number of seconds - java

I'm using ScheduledThreadPoolExecutor to create a file every fileIntervalInSeconds seconds:
executorService = new ScheduledThreadPoolExecutor(1);
executorService.scheduleAtFixedRate(new Runnable()
{
#Override
public void run()
{
File file = new File(fileName);
if (file.exists())
{
Log.debug("creating new file");
openFileWriter(file);
}
}
}, fileIntervalInSeconds, fileIntervalInSeconds, TimeUnit.SECONDS);
}
private void openFileWriter() throws FileSystemNotificationException
{
// 1 - close exist writer
writer.close();
// 2 - rename to backup file name
...
// 3 - create new file
FileWriter writerFile = new FileWriter(fileName, true);
writer = new PrintWriter(writerFile);
}
And i'm writing alert Messages to the file all the time:
private synchronized void writeLine(String line) throws InterruptedException
{
writer.println(line);
}
My problem is:
how can i ensure that i'm using writer when it is not closed? (writer.close())
How can i wait to the ScheduledThreadPoolExecutor to finish creating the file before start writing

How about checking the file exists before you write to it. No need for a backrgound thread or synchronization
private synchronized void writeLine(String line) {
if (!file.exists())
reopenWritingFile();
writer.println(line);
}

You could simply create the new file every hour within your write method. You would have some slight overhead for the time check but that should be negligible. The example below will create a new log file every hour with the time in milliseconds added to the front of the file name. You can format the time however suits you.
public class LogWriter {
private long lastCreationTime;
PrintWriter writer;
String logFileName;
public LogWriter(String logFileName) {
this.logFileName = logFileName;
createLogFile(logFileName);
}
private void createLogFile(String fileName) {
if(writer != null) {
writer.close();
}
lastCreationTime = System.currentTimeMillis();
FileWriter writerFile;
try {
writerFile = new FileWriter(lastCreationTime + "_" + fileName, true);
writer = new PrintWriter(writerFile);
} catch (IOException e) {
e.printStackTrace();
}
}
private synchronized void writeLine(String line) {
if(lastCreationTime < System.currentTimeMillis() - 3600000) {
createLogFile(logFileName);
}
writer.write(line);
}
}

You have two alternatives:
Create the new writer before closing the old one.
Establish a lock before closing the writer which you check when writing.
Examples:
volatile PrintWriter writer;
ReadWriteLock lock = new ReentrantReadWriteLock();
Lock writeLock = lock.writeLock();
Lock readLock = lock.readLock();
private void openFileWriterWithLock() throws IOException {
if (writeLock.tryLock()) {
try {
// 1 - close exist writer
writer.close();
// 2 - rename to backup file name
//...
// 3 - create new file
FileWriter writerFile = new FileWriter(fileName, true);
writer = new PrintWriter(writerFile);
} finally {
writeLock.unlock();
}
}
}
private synchronized void writeLineWithLock(String line) throws InterruptedException {
readLock.lock();
try {
writer.println(line);
} finally {
readLock.unlock();
}
}
private void openFileWriterWithoutLock() throws IOException {
// 0. Note old file.
PrintWriter oldWriter = writer;
// 1. Create new file.
FileWriter writerFile = new FileWriter(fileName, true);
// 2. Swap the new one in.
writer = new PrintWriter(writerFile);
// 3 - close old writer
oldWriter.close();
}
private synchronized void writeLineWithoutLock(String line) throws InterruptedException {
writer.println(line);
}

How about having a separate thread that handles the logging instead of that rather complicated construct?
public class Logger extends Thread {
private final LinkedBlockingQueue<String> linesToWrite = new LinkedBlockingQueue<>();
private final String filename;
private Logger(String filename) {
super("Logging thread");
this.filename = filename;
this.setDaemon(true);
this.setPriority(Thread.MIN_PRIORITY);
}
#Override
public void run() {
try (BufferedWriter out = new BufferedWriter(new FileWriter(filename, true))) {
String line;
while (this.isInterrupted() == false) {
line = linesToWrite.take();
out.write(line);
out.newLine();
out.flush();
}
} catch (InterruptedException e) {
} catch (IOException ex) {
System.out.println("Failed to access log file: " + ex);
}
}
public void log(final String line) {
this.linesToWrite.add(line);
}
Then initialize the logger once:
final Logger logger = new Logger("test.log");
logger.start();
And then you can use it from anywhere in a thread-safe way like this:
logger.log("Test message");
You don't need to stop the logger, because Java will ensure with the try construct that the file is properly closed. However if you want, you can stop it like this:
logger.interrupt();
Now you can do all file manipulation in a single-threaded way, because there is only one thread accessing the log files ever at any time.

Related

How to ask user for input to console (BufferedReader) and display countdown? Need to do it in two threads

Once user entered data timer stops and BuferredReader closed.
If 10 seconds passed and no input - BuferredReader closed and user unable to make input. Below code works, but not 100% correct.
Please suggest any solution.
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
NewThread nt = new NewThread(br);
Thread newThread = new Thread(nt);
newThread.start();
System.out.print("Please enter data: ");
System.out.println("");
String value = br.readLine();
System.out.println(value);
nt.shutdown();
}
}
class NewThread implements Runnable {
volatile BufferedReader br;
volatile boolean running ;
public NewThread(BufferedReader br) throws IOException {
this.br = br;
this.running = br.ready();
}
#Override
public void run() {
int count = 10;
try {
while (!running) {
System.out.print("("+count +")"+ '\r');
Thread.sleep(1000);
count--;
if (count <0){
shutdown();
}
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
}
}
public void shutdown () throws IOException {
running=true;
br.close();
}
}
So, firsty you calling method:
br.readLine()
BufferedReader implementation of this method uses synchornized block when waiting for user input. Below I put part of code this method:
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
...}
Nextly, when you call method shutdown from NewThread(after time out) on your reader, which call close method on buffer - execution of this metod uses synchronized mechanism too:
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
so it means that close method will be executed after finished readLine method (exactly after execution synchronized block in readLine method), which is finished when you pass parameter to console.
I suppose that is not possible to close this reader after calling readLine method by standard java mechanism when you use System.in.

Java threads:Comminucation between 3 java threads

So I have 3 threads,
A thread which downloads audio and the audio schedule object from the internet.
A thread which plays the audio according to the audio schedule.
And a web socket "notification" listener that listens for messages that say we have to download new audio and schedule as our current one is outdated.
The program flow is as follows:
On application startup: The ScheduleDownloader starts,downloads audio and schedule file.Once completed it needs to tell the audio player "hey the files are ready and here is the schedule" and it doesnt need to do anything for now
The audio player starts and continuously loops with no exit condition.
The web socket listener starts,when it gets a message.It should tell the schedule downloader "You need to start again as there is new files you need to download",it doesnt need to send any data to the schedule downloaded,just start it up again.The music should remain playing.Once it is done it should now restart the audio player thread with the new schedule.
Here is what I have so far,I am not sure how to get ScheduleDownloader to tell AudioPlayer "the files are ready and you need to start,here is the schedule" or "you need to restart with the new schedule,here it is" or how to get the listener to say "ScheduleDownloader you need to start again"
public class ScheduleDownloader extends Thread {
private Thread t;
private String threadName;
String username;
String password;
public ScheduleDownloader(String username,String password,String threadName){
this.username = username;
this.password = password;
this.threadName= threadName;
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}}
public void run() {
try {
Schedule schedule= null;
while(schedule == null){
System.out.println("Searching for schedule");
schedule= getTodaysSchedule();
}
System.out.println("Schedule Found");
boolean result = false;
while(result == false){
result = downloadFiles(schedule);
}
System.out.println("Files Downloaded");
} catch (IOException e) {
e.printStackTrace();
}
}
public Schedule getTodaysSchedule() throws IOException {
Schedule schedule = null;
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials
= new UsernamePasswordCredentials(username,password);
provider.setCredentials(AuthScope.ANY, credentials);
String url = "http://localhost:5000/api/schedule/today";
HttpClient httpClient = HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build(); //Use this instead
HttpGet request = new HttpGet(url);
HttpResponse response = httpClient.execute(request);
//read content response body
if (response.getStatusLine().getStatusCode() != 200) {
System.out.println("sorry error:" + response.getStatusLine().getStatusCode());
} else {
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
//change json response to java objects
Gson gson = new Gson();
schedule = gson.fromJson(String.valueOf(result),Schedule.class);
}
return schedule;
}
public static boolean downloadFiles(Schedule schedule) {
//get the music
for(int i =0;i<schedule.getMusicScheduleItems().size();i++){
downloadOneFile("shoutloudaudio","music/" +
schedule.getMusicScheduleItems().get(i).getMusic().getId()+
"-music.wav");
}
//get the advertisements
for(int i =0;i<schedule.getAdvertisementScheduleItems().size();i++){
downloadOneFile("shoutloudaudio","advertisements/" +
schedule.getAdvertisementScheduleItems().get(i).getAdvertisement().getId()+
"-advertisement.wav");
}
return true;
}
public static boolean downloadOneFile(String bucketName,String key) {
if( new File(key.split("/")[1]).isFile()){
//check if we have it already and dont need to download it
System.out.println(key + " alraeady exits");
return true;
}
AWSCredentials awsCredentials = new BasicAWSCredentials(
"removed",
"removed"
);
AmazonS3 s3client = AmazonS3ClientBuilder
.standard()
.withCredentials(new AWSStaticCredentialsProvider(awsCredentials))
.withRegion(Regions.EU_WEST_1)
.build();
S3Object s3object = s3client.getObject(bucketName, key);
S3ObjectInputStream inputStream = s3object.getObjectContent();
InputStream reader = new BufferedInputStream(
inputStream);
File file = new File(key.split("/")[1]);//save the file as whats after the / in key
OutputStream writer = null;
try {
writer = new BufferedOutputStream(new FileOutputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
}
int read = -1;
try {
while ((read = reader.read()) != -1) {
writer.write(read);
}
writer.flush();
writer.close();
}catch(IOException e){
e.printStackTrace();
return false;
}
return true;
}
}
AudioPlayer
public class AudioPlayer extends Thread {
Long currentFrameMusic;
Long currentFrameAdvertisement;
Clip clipMusic;
Clip clipAdvertisement;
private Thread t;
// current status of clip
String statusMusic;
String statusAdvertisement;
static AudioInputStream musicInputStream;
static AudioInputStream advertisementInputStream;
static String filePath;
Schedule schedule;
// constructor to initialize streams and clip
public AudioPlayer(Schedule schedule)
throws UnsupportedAudioFileException,
IOException, LineUnavailableException
{
//setup audio stream for music first
// create AudioInputStream object
this.schedule = schedule;
appendMusicFiles(schedule);
// create clip reference
clipMusic = AudioSystem.getClip();
// open audioInputStream to the clip
clipMusic.open(musicInputStream);
clipMusic.loop(Clip.LOOP_CONTINUOUSLY);
}
public void run(){
playMusic();
try {
checkShouldWePlayAnAdvertisement();
} catch (IOException e) {
e.printStackTrace();
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start(){
t = new Thread (this, "AudioPlayerThread");
t.start ();
}
public void start2() throws IOException, UnsupportedAudioFileException, LineUnavailableException, InterruptedException {
playMusic();
checkShouldWePlayAnAdvertisement();
}
public void playMusic()
{
//start the clip
clipMusic.start();
statusMusic = "play";
}
// Method to pause the audio
public void pauseMusic()
{
if (statusMusic.equals("paused"))
{
System.out.println("audio is already paused");
return;
}
this.currentFrameMusic =
this.clipMusic.getMicrosecondPosition();
clipMusic.stop();
statusMusic = "paused";
System.out.println("pausing music");
}
// Method to resume the audio
public void resumeAudioMusic() throws UnsupportedAudioFileException,
IOException, LineUnavailableException
{
if (statusMusic.equals("play"))
{
System.out.println("Audio is already "+
"being played");
return;
}
clipMusic.close();
resetAudioStreamMusic();
clipMusic.setMicrosecondPosition(currentFrameMusic);
System.out.println("resuming music");
this.playMusic();
}
// Method to restart the audio
public void restartMusic() throws IOException, LineUnavailableException,
UnsupportedAudioFileException
{
clipMusic.stop();
clipMusic.close();
resetAudioStreamMusic();
currentFrameMusic = 0L;
clipMusic.setMicrosecondPosition(0);
this.playMusic();
}
// Method to stop the audio
public void stopMusic() throws UnsupportedAudioFileException,
IOException, LineUnavailableException
{
currentFrameMusic = 0L;
clipMusic.stop();
clipMusic.close();
}
public void resetAudioStreamMusic() throws UnsupportedAudioFileException, IOException,
LineUnavailableException
{
clipMusic = AudioSystem.getClip();
appendMusicFiles(schedule);
// open audioInputStream to the clip
clipMusic.open(musicInputStream);
clipMusic.loop(Clip.LOOP_CONTINUOUSLY);
}
public static void appendMusicFiles(Schedule schedule) throws IOException, UnsupportedAudioFileException {
//add the first audio file to stream
AudioInputStream appendedFiles = AudioSystem.getAudioInputStream(
new File(schedule.getMusicScheduleItems().get(0).getMusic()
.getId() + "-music.wav"));
//loop through an combine
for(int i =1;i<schedule.getMusicScheduleItems().size();i++){
File file= new File(schedule.getMusicScheduleItems().get(i).getMusic()
.getId() + "-music.wav");
AudioInputStream toBeAppended = AudioSystem.getAudioInputStream(file);
//append them
appendedFiles =
new AudioInputStream(
new SequenceInputStream(appendedFiles, toBeAppended),
appendedFiles.getFormat(),
appendedFiles.getFrameLength() + toBeAppended.getFrameLength());
}
musicInputStream = appendedFiles;
}
//advertisement methods
public void playAdvertisements() throws LineUnavailableException, IOException, InterruptedException {
clipAdvertisement = AudioSystem.getClip();
// open audioInputStream to the clip
clipAdvertisement.open(advertisementInputStream);
System.out.println(clipAdvertisement.getMicrosecondLength());
//start the clip
clipAdvertisement.start();
Thread.sleep(clipAdvertisement.getMicrosecondLength() / 1000);
statusAdvertisement = "play";
System.out.println("playing advertisements");
}
// Method to pause the audio
public void pauseAdvertisements()
{
if (statusAdvertisement.equals("paused"))
{
System.out.println("audio is already paused");
return;
}
this.currentFrameAdvertisement =
this.clipAdvertisement.getMicrosecondPosition();
clipAdvertisement.stop();
statusAdvertisement = "paused";
}
// Method to resume the audio
public void resumeAudioAdvertisement() throws UnsupportedAudioFileException,
IOException, LineUnavailableException, InterruptedException {
if (statusAdvertisement.equals("play"))
{
System.out.println("Audio is already "+
"being played");
return;
}
clipAdvertisement.close();
resetAudioStreamAdvertisement();
clipAdvertisement.setMicrosecondPosition(currentFrameMusic);
this.playAdvertisements();
}
// Method to restart the audio
public void restartAdvertisement() throws IOException, LineUnavailableException,
UnsupportedAudioFileException, InterruptedException {
clipAdvertisement.stop();
clipAdvertisement.close();
resetAudioStreamAdvertisement();
currentFrameAdvertisement = 0L;
clipAdvertisement.setMicrosecondPosition(0);
this.playAdvertisements();
}
// Method to stop the audio
public void stopAdvertisement() throws UnsupportedAudioFileException,
IOException, LineUnavailableException, InterruptedException {
currentFrameAdvertisement = 0L;
clipAdvertisement.stop();
clipAdvertisement.close();
System.out.println("stopping advertisement");
}
public void resetAudioStreamAdvertisement() throws UnsupportedAudioFileException, IOException,
LineUnavailableException
{
advertisementInputStream = AudioSystem.getAudioInputStream(
new File(filePath).getAbsoluteFile());
clipAdvertisement.open(musicInputStream);
clipAdvertisement.loop(Clip.LOOP_CONTINUOUSLY);
}
public static void appendAdvertisementFiles(List<Advertisement> advertisementItems) throws IOException, UnsupportedAudioFileException {
//add the first audio file to stream
AudioInputStream appendedFiles = AudioSystem.getAudioInputStream(
new File(advertisementItems.get(0)
.getId() + "-advertisement.wav"));
//loop through an combine
for(int i =1;i<advertisementItems.size();i++){
File file= new File(advertisementItems.get(i)
.getId() + "-advertisement.wav");
AudioInputStream toBeAppended = AudioSystem.getAudioInputStream(file);
//append them
appendedFiles =
new AudioInputStream(
new SequenceInputStream(appendedFiles, toBeAppended),
appendedFiles.getFormat(),
appendedFiles.getFrameLength() + toBeAppended.getFrameLength());
}
advertisementInputStream = appendedFiles;
}
public void checkShouldWePlayAnAdvertisement() throws IOException, UnsupportedAudioFileException, LineUnavailableException, InterruptedException {
ArrayList<String> playedAtTimes = new ArrayList<>();
ArrayList<Advertisement> advertisementsToBePlayed = new ArrayList<>();
boolean found;
//played at times is used to keep track of what time we played advertisements
//so when the loop reruns and the time hasnt changed it doesnt play it again
while(true){
found = false;
ZonedDateTime zdt = ZonedDateTime.now();
String timeHHMM =zdt.toString().substring(11,16);
for(int i =0;i<schedule.getAdvertisementScheduleItems().size();i++)
{
if(schedule.getAdvertisementScheduleItems().get(i).getTimes()
.contains(timeHHMM))
{
//this item should be played now
if(playedAtTimes.contains(timeHHMM)){
//we already played this,but the time hasnt changed when the loop ran again
}else{
advertisementsToBePlayed.add(schedule.getAdvertisementScheduleItems().get(i).getAdvertisement());
found = true;
}
}
}
if(found== true){
playedAtTimes.add(timeHHMM);
appendAdvertisementFiles(advertisementsToBePlayed);
pauseMusic();
playAdvertisements();
stopAdvertisement();
resumeAudioMusic();
}
}
}
}
IotClient(part of listener)
public class IotClient extends Thread {
Thread t;
String username;
public IotClient(String username) {
this.username = username;
}
public void run(){
String clientEndpoint = "removve"; // replace <prefix> and <region> with your own
String clientId = "1"; // replace with your own client ID. Use unique client IDs for concurrent connections.
// AWS IAM credentials could be retrieved from AWS Cognito, STS, or other secure sources
AWSIotMqttClient client = new AWSIotMqttClient(clientEndpoint, clientId, "remove", "remove");
// optional parameters can be set before connect()
try {
client.connect();
} catch (AWSIotException e) {
e.printStackTrace();
}
AWSIotQos qos = AWSIotQos.QOS0;
AWSIotTopic topic = new MyTopic("schedule/"+ username, qos);
try {
client.subscribe(topic, true);
} catch (AWSIotException e) {
e.printStackTrace();
}
while(true){
}
}
public void start(){
if (t == null) {
t = new Thread (this, "IotClientThread");
t.start ();
}
}
MyTopic(part of listener)
public class MyTopic extends AWSIotTopic {
public MyTopic(String topic, AWSIotQos qos) {
super(topic, qos);
}
#Override
public void onMessage(AWSIotMessage message) {
System.out.println("Message recieved from topic: "+ message.getStringPayload());
}
}
Threads communicate via shared references to messages 'containers' objects in memory. That could be as simple as mere mutable field of a shared instance of some class, or more typical collection like list, map, but especially queues.
ArrayBlockingQueue is a good shared reference. There would be a queue for each message direction from one thread to another. If you had 3 threads that could truly talks to each other, you would have 3 pairs, thus 6 queues (2 for each pair). However, it is often the case that messages flow only in one direction, so you might save a few.
Now, the core of these communications is a mechanism to wait for some message (reader/consumer), and notify when a message is pushed (writer/producer).
Of course, you can learn (penty of tutorials out there) from the bottom going up, from the primitive wait/notify, or you can jump into classes like ArrayBlockingQueue which abstract the wait/notify of messages into take()/put(). I recommend starting from the bottom as things will make sense more rapidly when you meet other classes in java.util.concurrent.*
I cannot give you code, it would be largely not understandable at your level without having learned the basic of ITC (inter-thread communications).
Good learning!
PS: there are many pitfalls on the way, like thread safety, atomicity of writes, lock free algorithms, deadlocks, livelocks, starvation. Just the multi queue example above can lead to circular dependencies on message arrival, particularly when queue get full and block. This is a science!

How can I make the WebView in JavaFx wait an arbitrary amount of time without hanging the app?

Can someone please explain to me what I am doing wrong with the below code?
I am using the executeJavascript method to send a series of commands to the Webview, I want to loop through each command and then wait an arbitrary amount of time before the next command is executed.
What actually happens when I run this is that the application will hang every-time I pause in the loop, then once the loop is complete all my javascript actions happen at once. I thought by wrapping my executeJavascript into the Runlater class that it would all be synced nicely with the Application thread...
I seem to be going round in circles so help/direction would be appreciated, thanks.
I have set up three classes, A: Main.class that contains the following:
...scene.setOnKeyPressed(event -> {
switch (event.getCode()) {
case SPACE:
scriptRunner.run();
case SHIFT:
B: ScriptRunner.class that contains the following:
public class ScriptRunner extends Task<Void> {
#Override
protected Void call() throws Exception {
printOut("Running Test");
try (InputStream fileInputStream = new FileInputStream("test.txt");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, Charset.forName("UTF-8"));
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {
String getCurrentLine;
StepRunner stepRunner = new StepRunner();
while ((getCurrentLine = bufferedReader.readLine()) != null) {
final String currentLine = getCurrentLine;
Platform.runLater(new Runnable() {
#Override
public void run() {
stepRunner.runStep(currentLine);
}
});
Thread.sleep(3000);
}
printOut("Test finished");
bufferedReader.close();
} catch (
IOException e) {
e.printStackTrace();
}
return null;
}
C: StepRunner.class that contains the following:
public class StepRunner extends Task<Void> {
private String currentCommand;
public StepRunner (String currentCommand){
this.currentCommand = currentCommand;
}
#Override
protected Void call() throws Exception {
printOut("Got Here with " + currentCommand);
WebEngine.executeJavascript(currentCommand);
return null;
}
}
Try to extend your ScriptRunner class in Thread
public class ScriptRunner extends Thread {
#Override
public void run() {
printOut("Running Test");
try (InputStream fileInputStream = new FileInputStream("test.txt");
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, Charset.forName("UTF-8"));
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);) {
String getCurrentLine;
StepRunner stepRunner = new StepRunner();
while ((getCurrentLine = bufferedReader.readLine()) != null) {
final String currentLine = getCurrentLine;
Platform.runLater(new Runnable() {
#Override
public void run() {
stepRunner.runStep(currentLine);
}
});
Thread.sleep(3000);
}
printOut("Test finished");
bufferedReader.close();
} catch (
IOException e) {
e.printStackTrace();
}
}
}
then to call
Thread scriptRunner = new Thread(new ScriptRunner());
scriptRunner.run();
I think the problem is Thread.sleep(3000); that cause the app to hang. The process should be run on Thread.

Java reading and writing to same file

I'm using the following code to search specific files in my computer and write the absolute path in a text file. My problem is that every time I run this code it add duplicate lines into text file, i want to add only those lines(file path) which are not written in the text file at that time (no duplicates).. Thank you
public static void walkin(File dir) {
String pattern = ".mp4";
try {
PrintWriter out = new PrintWriter(new BufferedWriter(
new FileWriter("D:\\nawaaaaaa.txt", true)));
File listFile[] = dir.listFiles();
if (listFile != null) {
for (int i = 0; i < listFile.length; i++) {
if (listFile[i].isDirectory()) {
walkin(listFile[i]);
} else if (listFile[i].getName().endsWith(pattern)
&& listFile[i].isFile()) {
System.out.println(listFile[i].getPath());
out.write(listFile[i].toString());
out.write("\r\n");
// out.close();
} else {
walkin(listFile[i]);
}
}
}
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Your code works for me, no idea what is the problem on your side, how you are calling it; but you can optimize your code a bit, something as follows (just very quick code, code be made nicer, but to give you an idea):
public class SomeTest {
private static HashSet<String> filez = new HashSet<String> ();
public static void walkin(File dir, PrintWriter out) {
String pattern = ".mp4";
File listFile[] = dir.listFiles();
if (listFile != null) {
for (int i = 0; i < listFile.length; i++) {
if (listFile[i].getName().endsWith(pattern) && listFile[i].isFile()) {
//System.out.println(listFile[i].getPath());
if (filez.add(listFile[i].getPath())) {
out.write(listFile[i].toString());
out.write("\r\n");
}
} else {
walkin(listFile[i], out);
}
}
}
}
public static void main(String[] args) {
try {
File dir = new File("C:\\mydir");
PrintWriter out = new PrintWriter(new BufferedWriter(
new FileWriter("D:\\nawaaaaaa.txt", true)));
walkin(dir, out);
out.close();
} catch (IOException e) {
//
}
}
}
You can use the filez hashset to print stuff, or write your file at the end of the parsing process as well.. your choice.
If you don't want duplicates in the file, you will need to keep track of the file names you have already written. A HashSet<String> is going for this. But I'm surprised the above code works at all given that you keep opening the file at the top of walkin() and walkin() itself is recursive. You need to rethink your code a bit. Possibly passing the PrintWriter into walkin() as a parameter.
Since you are running the code multiple times ("every time I run this code it add duplicate lines into text file"), so once you finish writing to the file, you read each line and store it in a HashSet<String>. And use another writer to write it to the file.
BufferedWriter writer = new BufferedWriter(new FileWriter("filename"));
for (String eachUniqueLine: `Your hash set`) {
writer.write(eachUniqueLine);
writer.newLine();
}
(It is costly as in you have to do more i/o operation)
You need to expand your method into a class that perform this kind of tasks.
You have two main problem you open a writer for each directory and you call the walkin, for things that do not apply to your logic (and open writer again).
You should try to design a class that will be able to create an index for you.
public static void main(String[] args) throws IOException {
File createTempFile = File.createTempFile("mp4", ".idx");
FileIndexer fi = new FileIndexer(createTempFile.getAbsolutePath());
fi.index("C:\\", "mp4");
System.out.println(createTempFile);
}
public static class FileIndexer {
private static final String END_OF_LINE = "\r\n";
private final String outputPath;
private final Set<String> index = new HashSet<String>();
public FileIndexer(String outputPath) {
this.outputPath = outputPath;
}
private boolean isValidPath(String path) {
return outputPath != null && outputPath.trim().length() > 0;
}
private boolean isValidIndexFile(File file) {
return file.isFile() && file.canRead() && file.canWrite();
}
private void createIndexFile(File file) throws IOException {
if(file.createNewFile() == false) {
throw new IOException("Could not create index file");
}
this.index.clear();
}
private void readIndexFile(File file) throws IOException {
isValidIndexFile(file);
index.clear();
BufferedReader bufferedReader = null;
try {
bufferedReader = new BufferedReader(new FileReader(file));
String line;
while((line = bufferedReader.readLine()) != null) {
addToIndex(line);
}
} finally {
if(bufferedReader != null) {
bufferedReader.close();
}
}
}
private void addToIndex(String line) {
index.add(line);
}
private PrintWriter openIndex() throws IOException {
if(isValidPath(outputPath) == false) {
throw new IOException(String.format("The outputPath is not valid: [%s]",outputPath));
}
File indexFile = new File(outputPath);
if(indexFile.exists()) {
readIndexFile(indexFile);
} else {
createIndexFile(indexFile);
}
return new PrintWriter(new BufferedWriter(new FileWriter(this.outputPath, true)));
}
public synchronized void index(String pathToIndex, String pattern) throws IOException {
isValidPath(pathToIndex);
PrintWriter out = openIndex();
try {
File elementToIndex = new File(pathToIndex);
index(elementToIndex,pathToIndex, out);
} finally {
if(out != null) {
out.close();
}
}
}
private void index(File elementToIndex, String pattern, PrintWriter out) {
if(elementToIndex == null) {
return;
}
if(elementToIndex.isDirectory()) {
for(File file : elementToIndex.listFiles()) {
index(file,pattern, out);
}
}
if(elementToIndex.isFile() && elementToIndex.getAbsolutePath().endsWith(pattern)) {
writeToIndex(elementToIndex, out);
}
}
private void writeToIndex(File elementToIndex, PrintWriter out) {
out.write(elementToIndex.getAbsolutePath());
out.write(END_OF_LINE);
}
}
Problem Solved (BTW i'm not sure if it is most efficient solution or not ).......
public static void main(String[] args) {
try {
File dir = new File("D:\\To Do");
BufferedWriter out = new BufferedWriter(new FileWriter(
"D:\\path.txt", true));
walkin(dir, out);
out.close();
readfile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // Replace this with a suitable directory
// walkin(new File("D:/to Do"));
}
public static void walkin(File dir, BufferedWriter out) throws IOException {
String pattern = ".mp4";
// BufferedWriter out = new BufferedWriter(
// new FileWriter("D:\\path.txt",true));
File listFile[] = dir.listFiles();
if (listFile != null) {
for (int i = 0; i < listFile.length; i++) {
if (listFile[i].getName().endsWith(pattern)
&& listFile[i].isFile()) {
if (filez.add(listFile[i].getPath())) {
// System.out.println(listFile[i].getPath());
out.write(listFile[i].toString());
out.write("\r\n");
// System.out.println(filez);
}
} else {
walkin(listFile[i], out);
}
}
}
}
public static void readfile() {
BufferedReader br = null;
String str;
try {
BufferedWriter out = new BufferedWriter(new FileWriter(
"D:\\duplicate_free.txt"));
br = new BufferedReader(new FileReader("D:\\path.txt"));
while ((str = br.readLine()) != null) {
if (files.contains(str)) {
} else {
files.add(str);
}
}
for (String uniq : files) {
out.write(uniq);
System.out.println(uniq);
}
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

How could I read Java Console Output into a String buffer

I have a Java program that outputs some text into console. It uses print, println, and some other methods to do this.
At the end of the program , I want to read all the text in console and copy it into a String buffer. How could I do this in Java ? I need to read stdout and stderr separately.
Ok, this was a fun problem. Dosen't seem to be an elegant way of solving it for all PrintStream methods at once. (Unfortunately there is no FilterPrintStream.)
I did write up an ugly reflection-based workaround though (not to be used in production code I suppose :)
class LoggedPrintStream extends PrintStream {
final StringBuilder buf;
final PrintStream underlying;
LoggedPrintStream(StringBuilder sb, OutputStream os, PrintStream ul) {
super(os);
this.buf = sb;
this.underlying = ul;
}
public static LoggedPrintStream create(PrintStream toLog) {
try {
final StringBuilder sb = new StringBuilder();
Field f = FilterOutputStream.class.getDeclaredField("out");
f.setAccessible(true);
OutputStream psout = (OutputStream) f.get(toLog);
return new LoggedPrintStream(sb, new FilterOutputStream(psout) {
public void write(int b) throws IOException {
super.write(b);
sb.append((char) b);
}
}, toLog);
} catch (NoSuchFieldException shouldNotHappen) {
} catch (IllegalArgumentException shouldNotHappen) {
} catch (IllegalAccessException shouldNotHappen) {
}
return null;
}
}
...that can be used like this:
public class Test {
public static void main(String[] args) {
// Create logged PrintStreams
LoggedPrintStream lpsOut = LoggedPrintStream.create(System.out);
LoggedPrintStream lpsErr = LoggedPrintStream.create(System.err);
// Set them to stdout / stderr
System.setOut(lpsOut);
System.setErr(lpsErr);
// Print some stuff
System.out.print("hello ");
System.out.println(5);
System.out.flush();
System.err.println("Some error");
System.err.flush();
// Restore System.out / System.err
System.setOut(lpsOut.underlying);
System.setErr(lpsErr.underlying);
// Print the logged output
System.out.println("----- Log for System.out: -----\n" + lpsOut.buf);
System.out.println("----- Log for System.err: -----\n" + lpsErr.buf);
}
}
Resulting output:
hello 5
Some error
----- Log for System.out: -----
hello 5
----- Log for System.err: -----
Some error
(Note though, that the out field in FilterOutputStream is protected and documented, so it is part of the API :-)
You can't do that once the program is finished running. You need to do it before the program starts to write output.
See this article(archive.org) for details on how to replace stdout and stderr. The core calls are System.setOut() and System.setErr().
You can use PipedInputStream and PipedOutputStream.
//create pairs of Piped input and output streasm for std out and std err
final PipedInputStream outPipedInputStream = new PipedInputStream();
final PrintStream outPrintStream = new PrintStream(new PipedOutputStream(
outPipedInputStream));
final BufferedReader outReader = new BufferedReader(
new InputStreamReader(outPipedInputStream));
final PipedInputStream errPipedInputStream = new PipedInputStream();
final PrintStream errPrintStream = new PrintStream(new PipedOutputStream(
errPipedInputStream));
final BufferedReader errReader = new BufferedReader(
new InputStreamReader(errPipedInputStream));
final PrintStream originalOutStream = System.out;
final PrintStream originalErrStream = System.err;
final Thread writingThread = new Thread(new Runnable() {
#Override
public void run() {
try {
System.setOut(outPrintStream);
System.setErr(errPrintStream);
// You could also set the System.in here using a
// PipedInputStream
DoSomething();
// Even better would be to refactor DoSomething to accept
// PrintStream objects as parameters to replace all uses of
// System.out and System.err. DoSomething could also have
// an overload with DoSomething() calling:
DoSomething(outPrintStream, errPrintStream);
} finally {
// may also want to add a catch for exceptions but it is
// essential to restore the original System output and error
// streams since it can be very confusing to not be able to
// find System.out output on your console
System.setOut(originalOutStream);
System.setErr(originalErrStream);
//You must close the streams which will auto flush them
outPrintStream.close();
errPrintStream.close();
}
} // end run()
}); // end writing thread
//Start the code that will write into streams
writingThread.start();
String line;
final List<String> completeOutputStreamContent = new ArrayList<String>();
while ((line = outReader.readLine()) != null) {
completeOutputStreamContent.add(line);
} // end reading output stream
final List<String> completeErrorStreamContent = new ArrayList<String>();
while ((line = errReader.readLine()) != null) {
completeErrorStreamContent.add(line);
} // end reading output stream
Here is a utility Class named ConsoleOutputCapturer. It allows the output to go to the existing console however behind the scene keeps capturing the output text. You can control what to capture with the start/stop methods. In other words call start to start capturing the console output and once you are done capturing you can call the stop method which returns a String value holding the console output for the time window between start-stop calls. This class is not thread-safe though.
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
public class ConsoleOutputCapturer {
private ByteArrayOutputStream baos;
private PrintStream previous;
private boolean capturing;
public void start() {
if (capturing) {
return;
}
capturing = true;
previous = System.out;
baos = new ByteArrayOutputStream();
OutputStream outputStreamCombiner =
new OutputStreamCombiner(Arrays.asList(previous, baos));
PrintStream custom = new PrintStream(outputStreamCombiner);
System.setOut(custom);
}
public String stop() {
if (!capturing) {
return "";
}
System.setOut(previous);
String capturedValue = baos.toString();
baos = null;
previous = null;
capturing = false;
return capturedValue;
}
private static class OutputStreamCombiner extends OutputStream {
private List<OutputStream> outputStreams;
public OutputStreamCombiner(List<OutputStream> outputStreams) {
this.outputStreams = outputStreams;
}
public void write(int b) throws IOException {
for (OutputStream os : outputStreams) {
os.write(b);
}
}
public void flush() throws IOException {
for (OutputStream os : outputStreams) {
os.flush();
}
}
public void close() throws IOException {
for (OutputStream os : outputStreams) {
os.close();
}
}
}
}
Don't do it afterwards, create two StringBuilder objects before the first System.out.print() gets called and just append every string you want to save to the appropriate StringBuilder.
These two line of code will put your output in a text file or u can change the destination as u require.
// Create a file:
System.setOut(new PrintStream( new FileOutputStream("D:/MyOutputFile.txt")));
// Redirect the output to the file:
System.out.println("Hello to custom output stream!");
hope its help u .. :)

Categories