It's a good practice to call File methods(like read a text file) within JFrame class or what should I do if not? Thanks for reply.
This is my code:
private void filechooserButtonActionPerformed(java.awt.event.ActionEvent evt) {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(new FileNameExtensionFilter("Text files", "txt", "text"));
fileChooser.setAcceptAllFileFilterUsed(false);
int returnVal = fileChooser.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
resultTextArea.setText(null);
filePathTextField.setText(fileChooser.getSelectedFile().getAbsolutePath());
try (BufferedReader buffReader = new BufferedReader(new FileReader(new File(fileChooser.getSelectedFile().getAbsolutePath())))) {
String line;
while ((line = buffReader.readLine()) != null) {
resultTextArea.append(line + "\n");
}
} catch (Exception exc) {
JOptionPane.showMessageDialog(MainGUI.this, "Error: " + exc, "Error", JOptionPane.ERROR_MESSAGE);
}
}
}
UPDATE : I edited my code to use SwingWorker, so I hope it's better than was:
private class textFileReader extends SwingWorker<Void, Void> {
#Override
protected Void doInBackground() throws Exception {
JFileChooser fileChooser = new JFileChooser();
fileChooser.setFileFilter(new FileNameExtensionFilter("Text files", "txt", "text"));
fileChooser.setAcceptAllFileFilterUsed(false);
int returnVal = fileChooser.showOpenDialog(null);
if (returnVal == JFileChooser.APPROVE_OPTION) {
resultTextArea.setText(null);
filePathTextField.setText(fileChooser.getSelectedFile().getAbsolutePath());
try (BufferedReader buffReader = new BufferedReader(new FileReader(new File(fileChooser.getSelectedFile().getAbsolutePath())))) {
String line;
while ((line = buffReader.readLine()) != null) {
resultTextArea.append(line + "\n");
}
} catch (Exception exc) {
JOptionPane.showMessageDialog(MainGUI.this, "Error: " + exc, "Error", JOptionPane.ERROR_MESSAGE);
}
}
return null;
}
}
Taking your question literally, there's nothing wrong with it. Since you can define your own methods, and code structure is somewhat up to the developer, there's nothing technically wrong with doing file handling inside a class that also happens to extend JFrame.
That said, what I think you're actually asking is "Is it a good practice to do file IO from within Swing methods, such as filechooserButtonActionPerformed()?" And the answer to that question is unequivocally no - never do this.
These methods are called by Swing on the UI thread, also known as the Event Dispatch Thread, and while the UI thread is waiting for these methods to return, your application is frozen. It cannot repaint, it cannot respond to user input, nothing. Therefore instead you want to offload IO and other long-running work to other threads. There's a good tutorial in the Swing documentation: Lesson: Concurrency in Swing.
See also: Java Event-Dispatching Thread explanation
Related
I'm writing a thread code that opens a server socket and that when reached by a connection asks the user to choose a directory.
I've tried using the InvokeLater() and it works, but i have no control on when to retrieve the selected file directory, so InvokeAndWait looked like the right alternative. Except it doesn't actually do anything, i've even tried givin it a println and it simply does not seem to execute anything.
How do i fix it? I'm running out of ideas.
Thanks!
public class FileTransfListener implements Runnable {
protected JFileChooser dirChooser;
public FileTransfListener(JFileChooser f){
dirChooser=f;
}
#Override
public void run() {
ServerSocket serverSocket = null;
Socket socket = null;
BufferedReader in = null;
BufferedWriter out = null;
try {
serverSocket = new ServerSocket(60905);
} catch (IOException e1) {
return;
}
while(true){
try {
socket = serverSocket.accept();
String dir=null;
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
dirChooser.showOpenDialog(null);
}
});
try{
dir= dirChooser.getSelectedFile().getAbsolutePath();
}
catch(NullPointerException e){
dir=null;
}
System.out.println(dir);
}
catch (IOException ex) {
ex.printStackTrace();
try {
serverSocket.close();
}
catch (IOException e) {
e.printStackTrace();
}
} catch (InvocationTargetException |InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
Its a deadlock
dirChooser.showOpenDialog(null); is a blocking method and you should use it directly not trough SwingUtilities
What happens here is:
SwingUtilities.invokeAndWait submits task to EDT - blocks until it is completed
dirChooser.showOpenDialog(null); schedules dialog draw to EDT - awaits unitl dialog is closed - but its never drawn....
Since invokaAndWait awaits for completion on EDT - event queue is not emptied and task awaits for itself to complete - deadlock
What you should do is to call directly without EDT queue.
Documentation has simple exmaple of this:
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"JPG & GIF Images", "jpg", "gif");
chooser.setFileFilter(filter);
int returnVal = chooser.showOpenDialog(parent);
if(returnVal == JFileChooser.APPROVE_OPTION) {
System.out.println("You chose to open this file: " +
chooser.getSelectedFile().getName());
}
I'm trying to save and load .txt files on my program. I've got methods to read and write the files, but I want the user to be able to choose which name and where the files will be saved using the open/save forms. I've done this so far.
JButton btnLoad = new JButton("Carregar");
btnCarregar.addActionListener(new ActionListener() {
private Component modalToComponent;
public void actionPerformed(ActionEvent e) {
JFileChooser fileChooser = new JFileChooser();
if (fileChooser.showOpenDialog(modalToComponent) == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
}
}
});
Right, this actually opens the form, but after that, I don't know where and how use my methods to load the text. I guess, I should use file since it's the selected file, but when I send this file to my methods, it just doesnt work. Any example would be appreciated. Thanks before hand!
You can call a method from the point where the user has selected a file to open (in the if part of the actionPerformed method). So if your reading method is called openFile and accepts a File parameter, you can call 'openFile(file)` as the second statement in your if block:
if (fileChooser.showOpenDialog(modalToComponent) == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
openFile(file);
}
A simple example of an openFile method to handle opening a file (in this case by only printing the contents) could look like this:
private void openFile(final File inputFile) {
try (final BufferedReader reader = new BufferedReader(new FileReader(inputFile))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println("line: " + line);
// todo: handle line.
}
} catch (final IOException e) {
e.printStackTrace();
// todo: handle exception.
}
}
With the code below, I'm trying to simulate the command shell, I even created a command and called it (Showerrlog) to help the user seeing his invalid commands that he entered during his current work session, as you can see, I did that using filehandler, which will save the wrong commands in a log file. But as you know filehandler will start a new file for each new working session, and the new file will be named as (file.log, file.log.1, file.log.2, etc) and so on, the question is: how to make the program to avoid opening a new file everytime, in other words isn't there any other way that the program will just format the previous work session and add the new one instead?
Or at least how to make the program open the last log file which belongs to the current work session ?
public class WithEyul implements Runnable {
String command;
public WithEyul(String command) {
this.command = command;
}
#Override
public void run() {
List<String> input = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(command);
while (tokenizer.hasMoreTokens()) {
input.add(tokenizer.nextToken());
}
ProcessBuilder pb = new ProcessBuilder(input);
// ProcessBuilder creates a process corresponding to the input command
// now start the process
BufferedReader br = null;
try {
Process proc = pb.start();
// obtain the input and output streams
InputStream is = proc.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
br = new BufferedReader(isr);
// read what the process returned
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
} catch (java.io.IOException ioe) {
try {
System.err.println("Error");
Logger logger = Logger.getLogger("Testing");
FileHandler fh = new FileHandler("E:/MyLogFile.log");
logger.addHandler(fh);
SimpleFormatter formatter = new SimpleFormatter();
fh.setFormatter(formatter);
logger.info(command);
} catch (SecurityException e) {
printStackTrace();
} catch (IOException ex) {
Logger.getLogger(WithEyul.class.getName()).log(Level.SEVERE, null, ex);
}
} finally {
if (br != null) {
try {
br.close();
} catch (IOException ex) {
Logger.getLogger(WithEyul.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
and here is the main method class
public class TestProcessBuilder {
static void createProcess(String command) throws java.io.IOException {
Thread t = new Thread(new WithEyul(command));
t.start();
}
public static void main(String[] args) throws java.io.IOException {
String commandLine;
File wd;
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
System.out.println("\n\n***** Welcome to the Java Command Shell *****");
System.out.println("If you want to exit the shell, type END and press RETURN.\n");
// we break out with ‘END’
while (true) {
// show the Java shell prompt and read what command they entered
System.out.print("jsh>");
commandLine = console.readLine();
// if user entered a return, just loop again
if (commandLine.equals("")) {
continue;
}
if (commandLine.equalsIgnoreCase("Showerrlog")) {
try {
// Runtime.getRuntime().exec("E:\\MyLogFile.log");
if (Desktop.isDesktopSupported()) {
Desktop.getDesktop().open(new File("E:\\MyLogFile.log"));
}
} catch (IOException ex) {
Logger.getLogger(WithEyul.class.getName()).log(Level.SEVERE, null, ex);
}
}
if (commandLine.toLowerCase().equals("end")) { //User wants to end shell
System.out.println("\n***** Command Shell Terminated. See you next time. BYE for now. *****\n");
System.exit(0);
}
createProcess(commandLine);
}
}
}
You could use the FileHandler constructor that allows you to specify the rotation, limit, and append options.
new FileHandler("E:/MyLogFile.log", 0, 1, true);
The FileHandler can rotate for a number of reasons that are out of your control. If you don't want to deal with file rotation you could open a FileOutputStream and wrap that with a StreamHandler. However, you will have to handle file locking conflicts.
You should also avoid creating and adding a handler that points to the same target file everytime an error is generated. You should install the handler on startup and store a string reference to your logger.
I want to read a file using jFileChooser. jFileChooser will come up after press of a button (say jbutton1ChooseFile) and select the required file. After the selection is complete, another button (say jbutton2) will be used to read the contents of the file which has just been selected by the user. So on clicking on jbutton2, selected file will be read.
I am posting few lines of code so that it would be easy to understand what I mean to say:
private void jButton1ChooseFileChooseFileActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
JFileChooser loadFile= new JFileChooser();
loadFile.setApproveButtonText("Select File");
loadFile.setAcceptAllFileFilterUsed(false);
FileNameExtensionFilter f1 = new FileNameExtensionFilter("Text Files", "txt", "text","rtf","doc","docx");
loadFile.setFileFilter(f1);
switch (loadFile.showOpenDialog(EncDecApp.this))
{
case JFileChooser.APPROVE_OPTION:
JOptionPane.showMessageDialog(EncDecApp.this, "Selection Successfull!",
"Attention!",
JOptionPane.OK_OPTION);
jButton1ChooseFile.setText("File Chosen");
jLabelChooseFile.setText(String.valueOf(loadFile.getSelectedFile()).substring(0,30)+"...");
fileSelect=true;
break;
case JFileChooser.CANCEL_OPTION:
JOptionPane.showMessageDialog(EncDecApp.this, "No file chosen",
"Attention!",
JOptionPane.OK_OPTION);
loadFile.setSelectedFile(null);
jButton1ChooseFile.setText("Browse..");
jLabelChooseFile.setText("Choose file to encrypt");
break;
case JFileChooser.ERROR_OPTION:
JOptionPane.showMessageDialog(EncDecApp.this, "Error",
"Choosing File",
JOptionPane.OK_OPTION);
loadFile.setSelectedFile(null);
jButton1ChooseFile.setText("Browse..");
jLabelChooseFile.setText("Choose file to encrypt");
}
loadFile.setVisible(true);
}
Upto this it's working perfectly.
Now, the code for jButton2 is as follows:
private void jButton2EncryptEncryptActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
//Charset charset=Charset.forName("UTF-8");
int returnVal=loadFile.showOpenDialog(jLabel1);
if(returnVal==loadFile.APPROVE_OPTION)
{
File filePath = loadFile.getSelectedFile();
try{
BufferedReader in = new BufferedReader(new FileReader(filePath));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
jTextArea1.append(line + "\n");
}
in.close();
}
catch(IOException ex)
{
System.err.println("Open plaintext error: "+ex);
}
}
}
Any help will be highly appreciated.
At first glance the problem appears to be that you are using a local variable for the JFileChooser. That is to say, you have the line:
JFileChooser loadFile= new JFileChooser();
In your jButton1ChooseFileChooseFileActionPerformed function, and yet also try to refer to loadFile in your jButton2EncryptEncryptActionPerformed function.
In order to have the loadFile object available to both you need to have said loadFile object be a member of the class to which both functions belong.
I had posted a question in regards to this code. I found that JTextArea does not support the binary type data that is loaded.
So my new question is how can I go about detecting the 'bad' file and canceling the file I/O and telling the user that they need to select a new file?
class Open extends SwingWorker<Void, String>
{
File file;
JTextArea jta;
Open(File file, JTextArea jta)
{
this.file = file;
this.jta = jta;
}
#Override
protected Void doInBackground() throws Exception
{
BufferedReader br = null;
try
{
br = new BufferedReader(new FileReader(file));
String line = br.readLine();
while(line != null)
{
publish(line);
line = br.readLine();
}
}
finally
{
try
{
br.close();
} catch (IOException e) { }
}
return null;
}
#Override
protected void process(List<String> chunks)
{
for(String s : chunks)
jta.append(s + "\n");
}
}
You could cover the most by sniffing the mime type based on the file extension or, even better, the actual file content. You can do that with help of among others jMimeMagic (Maven coords here). If the mime type does not start with "text", then it's certainly not a text file.
String mimeType = Magic.getMagicMatch(file, false).getMimeType();
boolean text = mimeType.startsWith("text");
I found that MIME types can really help with this!
JAF
For those who read this and are curious as to what I have done to fix the File reading problem.... I have instead implemented a FileReader and have experienced no problems on Windows. I have however noticed on Linux that there are some problems which tends to lead to a crash. Also I noticed when running through an IDE such as Netbeans I receive various runtime errors when trying to load a binary file and massive slow-down; but when I execute the .jar as an executable and not from the IDE it works fine.
Here is relevant code that I have had no problem with (even when loading binary file types such as .mp3, .exe, etc.)
/*...*/
#Override
protected Void doInBackground() throws Exception {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
int ch = br.read();
while(ch != -1) {
publish(ch);
ch = br.read();
}
}
finally {
try {
br.close();
} catch (IOException e) {}
}
System.gc();
return null;
}
/*...*/