Hi,
I am writing a Class file (FileSaver.java), which has the outline:
public class FileSaver {
private JFileChooser _fileChooser = null;
public FileSaver()
{
_fileChooser = new JFileChooser(new File("."));
_fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
}
public void saveFile()
{
... //writes to the external file
}
} //end of class
This class will pup up a gui to let user choose the directory and file
name etc. It will be called anytime when the major program needs to save
something. Right now, when something needs to be saved, the code for
saving is repeated typed in that place. I hope to pull out those code
and create an object which can do saving for anybody, anytime.
Sometime it is several lines of text needs to be saved, sometimes it is
other things(e.g. image). I hope this class file FileSaver can be as
generic as possible. So I am thinking to let the major program pass
something(OutpurStream?) as arguments. I am not clear how to achieve
this purpose. Could you give me some help?
Thank you.
Oliver Wong - 04 Oct 2006 20:07 GMT
> Hi,
>
[quoted text clipped - 26 lines]
> something(OutpurStream?) as arguments. I am not clear how to achieve this
> purpose. Could you give me some help?
How about having your data-classes implement some sort of interface
which dictates that they provide an InputStream which are the bytes
representing the content of your data?
Then your FileSaver class would take an instance of this interface, call
the method to get the InputStream, and read the bytes, and write those bytes
to the desired file.
- Oliver
Shawn - 04 Oct 2006 20:28 GMT
> How about having your data-classes implement some sort of interface
> which dictates that they provide an InputStream which are the bytes
[quoted text clipped - 5 lines]
>
> - Oliver
It would be much better if you could elaborate a little more or even
throw in some code? I am not very experienced yet. I barely follow what
you mean.
Thank you.
Oliver Wong - 05 Oct 2006 15:09 GMT
>> How about having your data-classes implement some sort of interface
>> which dictates that they provide an InputStream which are the bytes
[quoted text clipped - 9 lines]
>
> Thank you.
See Chris Uppal's second solution (the one which he says he's not sure
is worth it due to messiness). That's essentially what I was proposing.
- Oliver
Chris Uppal - 05 Oct 2006 12:59 GMT
> public void saveFile()
> {
> ... //writes to the external file
> }
Would it make more sense for your generic file saver to return an open
OutputStream to the caller ? The caller would then use that to write
application-specific data to the file. That seems simpler to me, than
expecting the caller to "package up" its output code in a form that can be
directly invoked by the FileSaver.
That does have the disadvantage that the caller will be expected to close() the
file, but personally I don't see that as a big enough problem to justify much
extra complexity.
Still, if you do want to ensure that the file is closed by the FileSaver you
could do something like
Define an Interface:
interface FileWriter
{
void write(OutputStream out)
throws IOException;
}
Make your FileSaver take a FileWriter as one parameter (to its constructor or
to some other method). E.g.
class FileSaver
{
....
void promptAndSave(
String suggestedFileName,
// ...etc...
FileWriter writer)
throws IOException
{
// ...prompt for filename...
// ...open file...
try
{
writer.write(output);
}
finally
{
output.close();
}
}
....
}
And then when you use a FileWriter you can pass a local instance of FileWriter
to promptAndSave(). That instance might be one of your existing objects
(probably the object representing the data which is to be written to the file,
but extended to implement FileWriter), or almost as likely it would be
appropriate to create a local class (possibly an anonymous one, though I don't
like 'em myself), to do the job.
As I say, that's all a bit complicated. It is undoubtedly cleaner, and in a
different language I would follow that pattern without hesitation, but Java
makes it pretty messy, and since the gain is only that I don't have to remember
to close() the stream, I'm not sure the mess is worth it.
-- chris
Shawn - 05 Oct 2006 18:08 GMT
>> public void saveFile()
>> {
[quoted text clipped - 63 lines]
>
> -- chris
Thank you very much. I will take the first approach.
Shawn - 05 Oct 2006 18:48 GMT
One more question: In the following program, I feel I am stuck with the
line:
printwriter = new PrintWriter(new
FileOutputStream(_fileChooser.getSelectedFile()));
Because the stuff I am saving maynot be text files. If it is other
things, then FileOutputStream should be replaced.
I cannot figure out more generic ways.
Thank you for your help.
<code>
public class FileSavingHelper {
private JFileChooser _fileChooser = null;
public FileSavingHelper()
{
_fileChooser = new JFileChooser(new File("."));
_fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
}
public PrintWriter getPrintWriter()
{
PrintWriter printwriter = null;
if (_fileChooser.showSaveDialog(null) ==
JFileChooser.APPROVE_OPTION) //user clicks Save button
{
//open the printwriter
try
{
printwriter = new PrintWriter(new
FileOutputStream(_fileChooser.getSelectedFile()));
}
catch(FileNotFoundException e)
{
System.out.println("Error opening the file " +
_fileChooser.getSelectedFile().getAbsolutePath());
}
}
else //user clicked Cancel button
{
System.out.println("Save command cancelled by user.");
}
return printwriter;
} //end of getPrintWriter
}
</code>
To use it:
PrintWriter pw = new FileSavingHelper().getPrintWriter();
pw.println("Hello");
pw.println("");
pw.println("This is Thursday");
pw.close();
Chris Uppal - 06 Oct 2006 11:00 GMT
> One more question: In the following program, I feel I am stuck with the
> line:
> printwriter = new PrintWriter(new
> FileOutputStream(_fileChooser.getSelectedFile()));
Don't pass any sort of java.io.Writer to what I called the FileWriter. Always
pass a java.io.OutputStream and let the FileWriter wrap that in an
OutputStreamWriter if it wants to.
BTW, it would /probably/ be a good idea for your FileWriter to wrap a
BufferedOutputStream around the FileOutputStream before passing it to the
FileWriter. If you do decide to do that, then you should make it clear in the
documentation[*] that the FileSaver is guaranteed to do so.
-- chris
[*] if there is any ;-)