Java function question - java

Alright I am very new to Java and am trying to develop an application to teach myself how to use the language.
I have been copying and pasting the same few lines of code all over, and I know that there is a way to consolidate this into a function, but cannot quite figure it out.
FileOutputStream fout4 = openFileOutput("building1hourly.txt", MODE_WORLD_READABLE);
OutputStreamWriter osw4 = new OutputStreamWriter(fout4);
osw4.write("" +iHourlyAfter);
osw4.flush();
osw4.close();
Now isn't there some type of way I could do something like this
public void writerFunction("What to write to file", "name stream", "name writer", "MODE"){insert above code here}

Yes absolutely:
public void writeToFile(String fileName, String contents, int mode) throws IOException {
FileOutputStream fout = openFileOutput(fileName, mode);
OutputStreamWriter osw = new OutputStreamWriter(fout);
osw.write(contents);
osw.flush();
osw.close();
}

First of all, great job so far. Learning programming is just like learning math (except more fun), you can read about it all you want in a book, but you don't really understand concepts until you DO them. You're going about this the right way.
Now, to answer your question: Yes, you can encapsulate the process of writing to a file in a function. Let's call it writeToFile. You want to "call" this function by sending it arguments. The arguments are the information that the function needs to do its work.
There are two sides to a function: the declaration, and the invocation. Just like in math, you can define a function f(x), where f does something. For example: say I have the function f(x) = 2x - 4. That equation is what we call the function declaration, in that we are defining what f does, and you are defining the parameters that it accepts, namely a single value x. Then you want to apply that function on a certain value x, so you might do something like: f(4). This is the function invocation. You are invoking, or calling the function, and sending 4 as the argument. The code that invokes a function is called the caller.
Let's start with the declaration of the function that you want to build:
public void writeToFile (String data, String fileName)
This function defines two parameters in its signature; it expects a String containing the data you will write to the file, and the fileName to which we will write the data. The void means that this function does not return any data back to the caller.
The complete function, the body of which you provided in your post:
public void writeToFile (String data, String fileName){
FileOutputStream fout4 = openFileOutput(fileName, MODE_WORLD_READABLE);
OutputStreamWriter osw4 = new OutputStreamWriter(fout4);
osw4.write("" +iHourlyAfter);
osw4.flush();
osw4.close();
}
Now you will want to call, or invoke this function from somewhere else in your code. You can do this like so:
writeToFile("stuff I want to write to a file", "myFile.txt");

Related

How to initialize FileWriter outside of the main() method

I am writting a program in Java using the Spark Streaming framework (even if you don't know what Spark is you may still know the answer to my problem ).
I am basically receiving strings, one per second, through a socket and want to save them in a txt file ( each string separated by a paragraph. So something like this :
FileWriter a = new Filewriter (path to file);
a.append(string s);
a.append('\n');
a.flush;
The way Spark Streaming works is by converting the main () method into a big while loop, so in order for me to save the strings I receive in the same file, I need to declare the a variable outside of the main () (otherwise it will keep initializing and saving only the last string it receives ).
The problem is, because of an IOEXCEPTION, I have to do this:
public static void writer () throws IOException
{
FileWriter a= new Filewriter (path to file );
}
But if I call writer() in the main () I get the same problem as before ( I keep initializing a).
How can I initialize a outside the main (), so I don't have this problem?
Thank you so much.
You can declare it as a field, however you need to catch the exception in the constructor. You can do this
private final PrintWriter writer = new PrintWriter(filename, true);
Using PrintWriter has the advantage that
it places an appropriate newline at the end of each line.
it can be enabled to autoflush.
You can call it with
writer.println(text);

Java writes writes line multiple times?

static void goOut(String in) {
//instance variables
String fileCopy = currentLine + in;
try {
FileWriter writer = new FileWriter(output,true);
writer.write(line1 + System.getProperty("line.separator", "\r\n"));
writer.write(fileCopy + System.getProperty("line.separator", "\r\n"));
} catch(IOException ex) {
ex.printStackTrace();
}
}
Edited code to the correct standard as pointed out by other users.
of course because thats what you r telling it to do. every time is called it writes both x and the number. a quick fix: you can keep a flag if it is the first run set it flag = true. and check within ur method, sth like this:
public class YourClass{
private boolean didRun = false;
static void goOut(String in) {
...... init ur file and writer
if(!didRun)
writer.write(Y);
writer.write(in);
writer.close();
didRun = true;
}
}
I dont know the rest of the code but i think thats what u need
I believe you want to separate the jobs the "goOut" is responsible for.
You should make "goOut" only write the numbers (in your example).
The writing of the y's (in your example) should not be apart of the method and called once, at the start of writing to the file.
Also, #Jon Skeet is right about the multiple FileWriters. Use one, since its the same file.
Agree, sounds like a disaster.
When you use multiple writers to access the file, I would expect to get unpredictable results.
I dont think there is any guarantee that FileWriter1 would complete the task before FileWriter2.
In addition, the method is not synchronized.

Getting an InputStream to read more than once, regardless of markSupported()

I need to be able to re-use a java.io.InputStream multiple times, and I figured the following code would work, but it only works the first time.
Code
public class Clazz
{
private java.io.InputStream dbInputStream, firstDBInputStream;
private ArrayTable db;
public Clazz(java.io.InputStream defDB)
{
this.firstDBInputStream = defDB;
this.dbInputStream = defDB;
if (db == null)
throw new java.io.FileNotFoundException("Could not find the database at " + db);
if (dbInputStream.markSupported())
dbInputStream.mark(Integer.MAX_VALUE);
loadDatabaseToArrayTable();
}
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
this.dbInputStream = firstDBInputStream;
if (dbInputStream.markSupported())
dbInputStream.reset();
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
String CSV = "";
for (int i = 0; fileScanner.hasNextLine(); i++)
CSV += fileScanner.nextLine() + "\n";
db = ArrayTable.createArrayTableFromCSV(CSV);
}
public void reloadDatabase()//A method called by the UI
{
try
{
loadDatabaseToArrayTable();
}
catch (Throwable t)
{
//Alert the user that an error has occurred
}
}
}
Note that ArrayTable is a class of mine, which uses arrays to give an interface for working with tables.
Question
In this program, the database is shown directly to the user immediately after the reloadDatabase() method is called, and so any solution involving saving the initial read to an object in memory is useless, as that will NOT refresh the data (think of it like a browser; when you press "Refresh", you want it to fetch the information again, not just display the information it fetched the first time). How can I read a java.io.InputStream more than once?
You can't necessarily read an InputStream more than once. Some implementations support it, some don't. What you are doing is checking the markSupported method, which is indeed an indicator if you can read the same stream twice, but then you are ignoring the result. You have to call that method to see if you can read the stream twice, and if you can't, make other arrangements.
Edit (in response to comment): When I wrote my answer, my "other arrangements" was to get a fresh InputStream. However, when I read in your comments to your question about what you want to do, I'm not sure it is possible. For the basics of the operation, you probably want RandomAccessFile (at least that would be my first guess, and if it worked, that would be the easiest) - however you will have file access issues. You have an application actively writing to a file, and another reading that file, you will have problems - exactly which problems will depend on the OS, so whatever solution would require more testing. I suggest a separate question on SO that hits on that point, and someone who has tried that out can perhaps give you more insight.
you never mark the stream to be reset
public Clazz(java.io.InputStream defDB)
{
firstDBInputStream = defDB.markSupported()?defDB:new BufferedInputStream(defDB);
//BufferedInputStream supports marking
firstDBInputStream.mark(500000);//avoid IOException on first reset
}
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
this.dbInputStream = firstDBInputStream;
dbInputStream.reset();
dbInputStream.mark(500000);//or however long the data is
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
StringBuilder CSV = "";//StringBuilder is more efficient in a loop
while(fileScanner.hasNextLine())
CSV.append(fileScanner.nextLine()).append("\n");
db = ArrayTable.createArrayTableFromCSV(CSV.toString());
}
however you could instead keep a copy of the original ArrayTable and copy that when you need to (or even the created string to rebuild it)
this code creates the string and caches it so you can safely discard the inputstreams and just use readCSV to build the ArrayTable
private String readCSV=null;
public final void loadDatabaseToArrayTable() throws java.io.IOException
{
if(readCSV==null){
this.dbInputStream = firstDBInputStream;
java.util.Scanner fileScanner = new java.util.Scanner(dbInputStream);
StringBuilder CSV = "";//StringBuilder is more efficient in a loop
while(fileScanner.hasNextLine())
CSV.append(fileScanner.nextLine()).append("\n");
readCSV=CSV.toString();
fileScanner.close();
}
db = ArrayTable.createArrayTableFromCSV(readCSV);
}
however if you want new information you'll need to create a new stream to read from again

Writing a string to an OutputStream without using int onebyte

This is a total beginner question, I've spent the past hour searching both stackoverflow and Google, but I haven't found what I'm looking for, hopefully someone here can point me in the right direction.
I'm trying to write a string to an OutputStream, which I will then use to write data to a MySQL database. I've successfully retrieved data from a MySQL (from a .php, implementing JSON and RESTful), so I have some idea of what I'm doing, I think. I'm creating a method which will take a string and return an output stream, and I'm having trouble writing to an output stream, because when I try to initialize one, it creates an anonymous inner class with the write(int oneByte) method. That's not what I want.
private static OutputStream convertStringtoStream(String string) {
byte[] stringByte = string.getBytes();
OutputStream os = new OutputStream() {
#Override
public void write(int oneByte) throws IOException {
/** I'd rather this method be something like
public void write(byte[] bytes), but it requires int oneByte*/
}
};
//return os here
}
As you can see, I want to write to my OutputStream with the buffer, not a single byte. I'm sure this is simple question, but I've not been able to find an answer, or even sample code which does what I want. If someone could point me in the right direction I'd really appreciate it. Thanks.
Your method could look like this, but I'm not sure what it would accomplish. How would you use the returned OutputStream?
private static OutputStream convertStringtoStream(String string) {
byte[] stringByte = string.getBytes();
ByteArrayOutputStream bos = new ByteArrayOutputStream(string.length());
bos.write(stringByte);
return bos;
}
Also, note that using String.getBytes() might get you into trouble in the long run because it uses the system's default encoding. It's better to choose an explicit encoding and use the String.getBytes(Charset) method.
Instead of using the abstract OutputStream class, you might want to use ByteArrayOutputStream which allows you to write a buffer. Even better perhaps would be ObjectOutputStream which would allow you to write string directly since string is serializable. Hope that helps.

Is it possible to avoid temp files when a Java method expects Reader/Writer arguments?

I'm calling a method from an external library with a (simplified) signature like this:
public class Alien
{
// ...
public void munge(Reader in, Writer out) { ... }
}
The method basically reads a String from one stream and writes its results to the other. I have several strings which I need processed by this method, but none of them exist in the file system. The strings can get quite long (ca 300KB each). Ideally, I would like to call munge() as a filter:
public void myMethod (ArrayList<String> strings)
{
for (String s : strings) {
String result = alienObj.mungeString(s);
// do something with result
}
}
Unfortunately, the Alien class doesn't provide a mungeString() method, and wasn't designed to be inherited from. Is there a way I can avoid creating two temporary files every time I need to process a list of strings? Like, pipe my input to the Reader stream and read it back from the Writer stream, without actually touching the file system?
I'm new to Java, please forgive me if the answer is obvious to professionals.
You can easily avoid temporary files by using any/all of these:
CharArrayReader / CharArrayWriter
StringReader / StringWriter
PipedReader / PipedWriter
A sample mungeString() method could look like this:
public String mungeString(String input) {
StringWriter writer = new StringWriter();
alienObj.munge(new StringReader(input), writer));
return writer.toString();
}
StringReader
StringWriter
If you are welling to work with binary arrays in-memory like you do in C# then I think the PipedWriter & PipedReader are the most convenient way to do so. Check this:
Is it possible to avoid temp files when a Java method expects Reader/Writer arguments?

Categories

Resources