Hello.


I recently started studying Java and OOP. I am currently creating a class that writes text to a file in a particular format. I have 'finished' it, and it works, but I am unsure as to the quality of the implementation.

This is how it works:

* First of all: the class has no attributes, just a method... Is this correct?

* Second: the method receives three parameters one word, another word and a sentence. The first word is supposed to be a word in one language, the second would be its ranslation into another one, and the third is a comment regarding the word. All of them are strings

* Third: the method in question is the one that creates three variables (String) to write them to a file.

Is this OK? Should I make a constructor and have the user provide the three strings?

This class is intended to be instantiated by another program (the GUI), this program will collect the three string from graphical user input. My idea is that it takes the input as variables and then passes these variables to the objects mehotd so it can write in the file.

I guess it's poorly designed, any ideas?

Sounds reasonable so far. Maybe you would want to pass the file name to a constructor for this class so that it's not hard coded? If you are writing this info to a file then presumably you will read it back at some point? If so all the code associated with writing and reading the file should be in the same class so that there's only one class to loom at for anything related to the file record formats etc.

So, there is nothing wrong with having a class without instance attributes? Or should I make the filename a class attribute too?

I agree completely with James. Without seeing the code itself, it sounds okay so far.

Building on his post: Anything that might change in the future (like the file name) could be given a default value in the class. Then provide two separate constructors, one of them allowing you to provide a custom file name.

So, there is nothing wrong with having a class without instance attributes? Or should I make the filename a class attribute too?

If you don't need to use them, don't put them in. But yes, filename would be a good way of making your class more flexible.

public class ClassName
{
    private String filename = "default_name.txt";

    // Default constructor
    public ClassName()
    {
        doSomething();
    }

    // Constructor that takes filename as a parameter
    public ClassName( String filename )
    {
        this.filename = filename;
        doSomething();
    }

    private void doSomething()
    {
        // Do whatever you need to do here
    }
}

Oh geat!! That really helps. Question about your code: that this.filename is referring to the classe's filename not to the method filename, right?

You said you were writing the strings to a file, and that's the file name we are talking about. It's never a good idea to hard-code a file name because it may or may not be appropriate for whatever machine the app is finally run on. So let's suppose the class is called TranslationsStore (a place where translations are stored). In outline it could look like this:

public class TranslationsStore {
   public TranslationsStore (String fileName) } // file where info is written
     ...
   }
   public void writeTranslation(String word1, String word2, String comment) {
     // write this info to the file
   }
   // method(s) for reading the info back from the file
}

So then in your GUI you could have code like:

// initialisation...
   TranslationsStore store = new TranslationsStore("data.txt");

// when the user clicks the OK button...
   store.writeTranslation(word1TextField.getText(), //etc

Finally, a simple file name like "data.txt" can be a big problem because the directory is not specified, and will depend on exactly how the java program is started. Java has a method that gives you the user's home directory, so that is a good place to put any files in the absence of a better idea. You use it like this:

String defaultStoreFileName = System.getProperty("user.home") + "/data.txt"

Edited 5 Years Ago by JamesCherrill: n/a

Oh geat!! That really helps. Question about your code: that this.filename is referring to the classe's filename not to the method filename, right?

Yes. When you use the "this" keyword it means you are referring to the class itself, not the local scope (inside the method).

Finally, a simple file name like "data.txt" can be a big problem because the directory is not specified, and will depend on exactly how the java program is started. Java has a method that gives you the user's home directory, so that is a good place to put any files in the absence of a better idea. You use it like this:

String defaultStoreFileName = System.getProperty("user.home") + "/data.txt"

Adding to that, it might also be worthwhile using System.getProperty("file.separator") to ensure compatibility on as many systems as possible.

String defaultStoreFileName = System.getProperty("user.home") + System.getProperty("file.separator") + "data.txt"
Comments
good relevant advice

Adding to that, it might also be worthwhile using System.getProperty("file.separator") to ensure compatibility on as many systems as possible.

Very good advice.

> Adding to that, it might also be worthwhile using System.getProperty("file.separator") to ensure compatibility on as many systems as possible.

Or better yet IMO, try not to mess with FS paths thinking of them as strings and use appropriate constructors:

final File homeDir = new File(System.getProperty("user.home"));
final File defaultFileStore = new File(homeDir, "data.txt");

The appending trick will work in this case but would haunt you in case you are picking up the base directory from a configuration file and someone decides to add the trailing \ or / for you. In that case, appending will result in you ending up with two path separators after the directory name, not good. :-)

Edited 5 Years Ago by ~s.o.s~: n/a

Great , great. This is excellent. You're being really helpful :)

I'll post the code as soon as I am done with it. Now, I tried to follow S.O.S's advice regarding filepaths, and I came up with this:

private void writeToFile(String originalWord, String translatedWord){	
		try{		
			String homeDir = System.getProperty("user.home");
			FileWriter theFile = new FileWriter(homeDir + "/My Documents/" + fileName + ".txt", true);
	 		BufferedWriter output = new BufferedWriter(theFile);
			output.write(originalWord + "\t" + translatedWord + "\n");
			output.close();
		}
                catch (Exception e){
			System.err.println("Error: " + e.getMessage());
		}
	
	}

Filename is the filename provided in the constructor. Now the funny thing is it doesn't work if I have it write to user.home, but it does if I add '/My Documents/'. It's a Windows XP machine, so the user.home should be C:\Documents and settings\USERNAME\.

Edited 5 Years Ago by G_S: n/a

> Now, I tried to follow S.O.S's advice regarding filepaths, and I came up with this:

You are still relying on string concatenation for building up file/dir paths. Also, what exactly happens when you say "doesn't work"? Exception? Here is a simple snippet which should work and uses File constructors instead of "+" on Strings.

// try..catch..finally left out for brevity
public static void main(String[] args) throws Exception {
	final File homeDir = new File(System.getProperty("user.home"));
	final FileWriter writer = new FileWriter(new File(homeDir, "a.txt"), true);
	final PrintWriter pWriter = new PrintWriter(writer);
	pWriter.printf("%s -> %s%n", "home", "a place you can always go to");
	pWriter.close();
}

> Now, I tried to follow S.O.S's advice regarding filepaths, and I came up with this:

You are still relying on string concatenation for building up file/dir paths. Also, what exactly happens when you say "doesn't work"? Exception? Here is a simple snippet which should work and uses File constructors instead of "+" on Strings.

// try..catch..finally left out for brevity
public static void main(String[] args) throws Exception {
	final File homeDir = new File(System.getProperty("user.home"));
	final FileWriter writer = new FileWriter(new File(homeDir, "a.txt"), true);
	final PrintWriter pWriter = new PrintWriter(writer);
	pWriter.printf("%s -> %s%n", "home", "a place you can always go to");
	pWriter.close();
}

I solved the problem, but DanyWeb wouldn't let me edit after 30 minutes. The problem was that HomeDir is C:\Documents and setting\USERNAME, without the trailing '\' so it was saving the files to nowhere.

I added that "/" and everything is fine now.

So tell me:

1 - How do I get it to write to My Documents folder instead of the home folder (because the name My documents changes with language).

2 - How could I avoid using trailing? Remember that getProperty(user.home) returns the home without the trailing \.

3 - Also, you use a different object for the file, is there any problem with mine? Why are so many ways of creating files with Java?

> 0. I added that "/" and everything is fine now.

As I have been mentioning repeatedly, you should never have a need to deal with "/" or "\" when dealing with files in Java. The different File constructors make it possible for you to manipulate paths in java in a platform agnostic way.

> 1 - How do I get it to write to My Documents folder instead of the home folder (because the name My documents changes with language).

There is no system property for "My Documents" so you would have to hardcode the directory name or read it from a configuration file.

> 2 - How could I avoid using trailing? Remember that getProperty(user.home) returns the home without the trailing \.

Read point 0's explanation.

> 3 - Also, you use a different object for the file, is there any problem with mine? Why are so many ways of creating files with Java?

Yes, the problem with your approach is that you explicitly use path separators which lead to non-portable code.

> 0. I added that "/" and everything is fine now.

As I have been mentioning repeatedly, you should never have a need to deal with "/" or "\" when dealing with files in Java. The different File constructors make it possible for you to manipulate paths in java in a platform agnostic way.

OK, got it. So I have to get rid of the / and \.


I'll try your last snippet. The problem was that I'm not using File, but FileWriter, and FileWriter seems to be unable to write to places that don't end with '/'.

I see, so I'll have to use a config file to get it to write to My Documents? I guess I'll have to have the user specify a filesave path...

> I'll try your last snippet. The problem was that I'm not using File, but FileWriter, and FileWriter seems to be unable to write to places that don't end with '/'.

FileWriter and File are in no way related and serve completely different purpose. FileWriter takes in a File object which relieves you from using "/" or "\". Try it out.

> I guess I'll have to have the user specify a filesave path...

Yes, or just hard-code it, which wouldn't be nice. Just make sure you validate the path entered by the user and throw a BadConfiguration exception if it points to a non-existent path or a file instead of directory.

This question has already been answered. Start a new discussion instead.