My question is this: how can reading a huge (many millions of lines) file keep a thread alive, even after it finished doing the file stuff
The problem is that I have a Thread started from the javafx application thread, which then (the new thread) performs some read/write actions on a text file, won't exit naturally when faced with HUGE files to parse through, 17-million lines large, specifically.
I'm assuming this is due to the thread holding on to some resource that I'm missing, however, since I'm using the try-with-resource model, I'm not sure how that's even possible really.
Here's the javafx controller class (using fxml) that sparks off the thread:
MainController.java:
/**
* This method handles what happens when the calculate button is clicked.
* The main thing this does is disable/enable a few Nodes, as well as sparks
* off the background thread.
*
* @param event
*/
@FXML
private void convert_button_action(ActionEvent event) {
closing_label.setVisible(true);
convert_button.setDisable(true);
input_text = input_NCLocation_field.getText();
output_text = output_Location_Field.getText();
indicator_node.setVisible(true);
if (!toggleSwitch.isSelected()) {
(new Thread(new FileWriter(input_text, output_text, indicator_node))).start();
} else {
DateWriter temp = new DateWriter(input_text, output_text, indicator_node, yr_mn_dy.isSelected());
(new Thread(temp)).start();
}
}
nothing too fancy in there, simply some making things visible/not visible and the starting of the appropriate thread based on the input of the user. next is the entire Thread class since it's not too huge. All it does really is either turn a line that looks like: yearmonthday into year,month,day or it separates the year month and day columns into separate files if the user clicked the check box that asked for it. Simply a handy tool for the use case.
Please note the println statement at the end of the run()
method. I see this println every single time, but after it happens, nothing happens. The program doesn't exit, the thread doesn't stop, nothing.
package File_Conversion;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import javafx.application.Platform;
import javafx.scene.control.ProgressIndicator;
/**
* This class is the background 'worker' thread that does all of the heavy duty
* file IO for splitting up the NC file. It periodically sends reports back to
* the main application thread to update the progress indicator.
*
* @author William
*/
public class DateWriter implements Runnable {
private final ProgressIndicator myIndicator;
private static File ncFile;
private final String outputLocationFile;
private float zmax, zmin, xmax, xmin, ymax, ymin;
private ArrayList<Float> xList, yList, zList;
private final DecimalFormat numberFormat = new DecimalFormat("#.000000");
private final DecimalFormat numberFormatMinMax = new DecimalFormat("#.00000");
private final boolean yr_mon_day;
/**
* This is the main constructor, it needs a valid NC file to continue.
*
* @param inputNCFile
* @param outputLocation
* @param myIndicator
* @param yr_mon_day
*/
public DateWriter(String inputNCFile, String outputLocation, ProgressIndicator myIndicator, boolean yr_mon_day) {
this.yr_mon_day = yr_mon_day;
this.myIndicator = myIndicator;
ncFile = new File(inputNCFile);
outputLocationFile = outputLocation;
}
/**
* The primary run() method, starts the thread.
*/
@Override
public void run() {
convertDate();
Platform.runLater(new Runnable() {
@Override
public void run() {
File_Conversion.stage_returner().close();
}
});
System.out.println("I'm at the end of the run...??");
}
public boolean convertDate() {
BufferedReader br = null;
java.io.FileWriter yearWriter = null, MonthWriter = null, DayWriter = null
,fWriter = null;
BufferedWriter yearBuf = null, monthBuf = null, dayBuf = null, writer = null;
try {
br = new BufferedReader(new FileReader(ncFile));
if (yr_mon_day) {
yearWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_year.csv", false);
yearBuf = new BufferedWriter(yearWriter);
MonthWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_month.csv", false);
monthBuf = new BufferedWriter(MonthWriter);
DayWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName().substring(0, ncFile.getName().lastIndexOf(".")) + "_modified_day.csv", false);
dayBuf = new BufferedWriter(DayWriter);
String input;
String temp;
String temp2;
String temp3;
while ((input = br.readLine()) != null) {
temp = input.substring(0, 4);
temp2 = input.substring(4, 6);
temp3 = input.substring(6);
Platform.runLater(new Runnable() {
@Override
public void run() {
myIndicator.setProgress(-1);
}
});
yearBuf.write(temp + "\n");
monthBuf.write(temp2 + "\n");
dayBuf.write(temp3 + "\n");
}
} else {
fWriter = new java.io.FileWriter(outputLocationFile + "\\" + ncFile.getName() + "_modified.csv", false);
writer = new BufferedWriter(fWriter);
String input;
String temp;
while ((input = br.readLine()) != null) {
temp = input.substring(0, 4) + "," + input.substring(4, 6) + "," + input.substring(6);
Platform.runLater(new Runnable() {
@Override
public void run() {
myIndicator.setProgress(-1);
}
});
writer.write(temp + "\n");
}
}
} catch (IOException e) {
e.printStackTrace(System.out);
}finally{
try{
if (br!=null) br.close();
if (yearBuf !=null) yearBuf.close();
if (monthBuf != null)monthBuf.close();
if (dayBuf != null)dayBuf.close();
if (yearWriter != null)yearWriter.close();
if (MonthWriter != null)MonthWriter.close();
if (DayWriter != null)DayWriter.close();
if (fWriter != null) fWriter.close();
if (writer != null) writer.close();
}catch(IOException e){
e.printStackTrace(System.out);
}
}
return true;
}
}
again, nothing fancy, some buffered streams and writers, and that's it! It's worth noting that this works perfectly for files that are small/not gigantic. It was only when faced with a multi-million line file am I seeing this behaviour.
Any help you can give would be much appreciated, thanks!
Edit 1
Just to help clarify, the reason part of the if/else is in try-with-resource madness, and the other is in the more traditional fashion, is simply to exemplify the fact that it has been tried both ways, the identical symptoms come out the thread running through either of the logical blocks, so I'm fairly certain the way I'm closing the resources has nothing to do with it.