FileWriter vs FileOutputStream in Java - java

I'm little confused about FileWriter and FileOutputStream. As I see source code of FileWriter there are just 4 constructors and each constructor is calling FileOutputStream's constructor.
public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
}
public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
}
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}
public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
}
public FileWriter(FileDescriptor fd) {
super(new FileOutputStream(fd));
}
After searching difference between them I found mentioned here.
FileOutputStream is meant for writing streams of raw bytes such as
image data. For writing streams of characters, consider using
FileWriter.
How FileWriter can make difference? Even it still calling FileOutputStream's constructor without any changing.

FileWriter is a Writer. It's about writing text - and it happens to be writing it to a file. It does that by holding a reference to a FileOutputStream, which is created in the FileWriter constructor and passed to the superclass constructor.
FileOutputStream is an OutputStream. It's about writing binary data. If you want to write text to it, you need something to convert that text to binary data - and that's exactly what FileWriter does. Personally I prefer to use FileOutputStream wrapped in an OutputStreamWriter by me to allow me to specify the character encoding (as FileWriter always uses the platform default encoding, annoyingly).
Basically, think of FileWriter is a simple way of letting you write:
Writer writer = new FileWriter("test.txt");
instead of
Writer writer = new OutputStreamWriter(new FileOutputStream("test.txt"));
Except I'd normally recommend using the overload of the OutputStreamWriter constructor that accepts a Charset.

FileOutputStream is to write primitive types of data, like int, while FileWriter is to write character-oriented data.
FileOutputStream does not come with methods to deal with strings. If you want to use FileOutputStream to write a string to a file, you have to go like:
FileOutputStream fos=new FileOutputStream();
String str="Hello";
byte b[]=str.getBytes();
fos.write(b);
fos.close();
In Filewriter there is no conversion between string and byte array. You could simply use:
FileWriter fr=new FileWriter("C:\\");
fr.write("Hello");
fr.close();
Do not forget to throw any exceptions if needed.

A FileOutputStream writes bytes directly. A FileWriter encapsulates a FileOutputStream (by creating it in the FileWriter constructor as in your question) and provides convenience methods to write characters and Strings.

Actually, the question is when do use Reader/Writer and when Stream?
How to Decide Which to use:
1.If you are dealing with binary data (e.g. an image) use Streams.
2.If you are using non-ASCII Unicode characters, use Readers/Writers.
3.If you are using ordinary ASCII text you can (usually) use either.

Related

Appending data in a CSV in selenium automation

I have a CSV file in Resources of my automation script and I need to amend one cell value to a parameter value I get by creating a folder in a site, I ran this code but then an error comes:
"(The process cannot access the file because it is being used by another process)".
Can anyone let me know how to write my parameter value to CSV file cell, please.
TIA
Method:
public static void writeCSV(String filePath, String separator) throws IOException {
try (OutputStream fileStream = new BufferedOutputStream(new FileOutputStream(filePath));
Writer outStreamWriter = new OutputStreamWriter(fileStream, StandardCharsets.UTF_8);
BufferedWriter buffWriter = new BufferedWriter(outStreamWriter)) {
buffWriter.append("https://mobile/sample_v4.zip");
buffWriter.append(separator);
buffWriter.append(createdTitle);
buffWriter.append(separator);
buffWriter.append("http://2-title-conversion/documentlibrary");
buffWriter.append(separator);
buffWriter.append("TRUE");
buffWriter.append(separator);
buffWriter.append("TRUE");
buffWriter.flush();
}
#Test segment,
loginPg.writeCSV("C:\\Users\\urathya\\Documents\\Automation\\03-11\\resources\\CS.csv",",");
You are not closing the output stream, please close it, it will close file and you can use the same file to append the data.

Write object to zip file in json format

My goal is to write an object to zip file in json format. The simplest way of doing it is:
ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
String json = gson.toJson(object);
zip.write(json.getBytes());
But I want to avoid to load the whole object to a single string. So I wrapped a zip stream into a writer object:
Writer writer = new OutputStreamWriter(zip);
And after that I write the entry in the following way:
zip.putNextEntry(entry);
gson.toJson(content, writer);
writer.flush();
zip.closeEntry();
zip.flush();
It works fine, but it seems very messy using writer and zip objects at the same time. Is there any better solution for this problem?
You can make it a bit simplier with Jackson which has methods to write directly to an OutputStream
ObjectMapper mapper = new ObjectMapper();
try (ZipOutputStream out = new ZipOutputStream(new FileOutputStream(zipFile))){
out.putNextEntry(new ZipEntry("object.json"));
mapper.writeValue(out, object);
}
You may declare one or more resources in a try-with-resources statement. For example
try (
ZipOutputStream zip = new ZipOutputStream(new BufferedOutputStream(new
FileOutputStream(zipFile)));
Writer writer = new OutputStreamWriter(zip);
) {
zip.putNextEntry(entry);
gson.toJson(content, writer);
}
The close methods are automatically called in this order. Note that the close methods of resources are called in the opposite order of their creation. With regards to flush, close flush it first.
public abstract void close() throws IOException
Closes the stream, flushing it first. Once the stream has been closed, further write() or flush() invocations will cause an IOException to be thrown. Closing a previously closed stream has no effect.

Which one is better approach so as to able to use wrapper class read() / write() method with android.content.res.Resources.openRawResource() method?

//Reading a image file from #drawable res folder and writing to a file on external sd card
//below one works no doubt but I want to imrpove it:
OutputStream os = new FileOutputStream(file); //File file.........
InputStream is =getResources().openRawResource(R.drawable.an_image);
byte[] b = new byte[is.available()];
is.read(b);
os.write(b);
is.close();
os.close();
In above code I am using basic io classes to read and write. My question is what can I do in order to able to use wrapper classes like say DataInputStream/ BufferedReaderd or PrintStream / BufferedWriter /PrintWriter.
As openRawResources(int id ) returns InputStream ;
to read a file from res I either need to typecast like this:
DataInputStream is = (DataInputStream) getResources().openRawResource(R.drawble.an_image));
or I can link the stream directly like this:
DataInputStream is = new DataInputStream(getResources().openRawResource(R.drawable.greenball));
and then I may do this to write it to a file on sd card:
PrintStream ps =new PrintStream (new FileOutputStream(file));
while(s=is.readLine()!=null){
ps.print(s);
}
So is that correct approach ? which one is better? Is there a better way?better practice..convention?
Thanks!!!
If openRawResource() is documented to return an InputStream then you cannot rely on that result to be any more specific kind of InputStream, and in particular, you cannot rely on it to be a DataInputStream. Casting does not change that; it just gives you the chance to experience interesting and exciting exceptions. If you want a DataInputStream wrapping the the result of openRawResource() then you must obtain it via the DataInputStream constructor. Similarly for any other wrapper stream.
HOWEVER, do note that DataInputStream likely is not the class you want. It is appropriate for reading back data that were originally written via a DataOutputStream, but it is inappropriate (or at least offers no advantages over any other InputStream) for reading general data.
Furthermore, your use of InputStream.available() is incorrect. That method returns the number of bytes that can currently be read from the stream without blocking, which has only a weak relationship with the total number of bytes that could be read from the stream before it is exhausted (if indeed it ever is).
Moreover, your code is also on shaky ground where it assumes that InputStream.read(byte[]) will read enough bytes to fill the array. It probably will, since that many bytes were reported available, but that's not guaranteed. To copy from one stream to another, you should instead use code along these lines:
private final static int BUFFER_SIZE = 2048;
void copyStream(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
int nread;
while ( (nread = in.read(buffer) != 0 ) do {
out.write(buffer, 0, nread);
}
}

Appending to ObjectOutputStream (writing multiple objects w/o closing stream)

Desclaimer My question is different from two following links
Question 1
Question 2
public class AppendableObjectOutputStream extends ObjectOutputStream {
public AppendableObjectOutputStream(OutputStream out) throws IOException {
super(out);
}
#Override
protected void writeStreamHeader() throws IOException {}
}
The problem with above solutions is that they do not support writing multiple objects to appendable stream w/o closing the stream.
If I open appendable stream, write multiple objects - then at time of reading I can read only first object properly and on trying to read second object, I get EOF exception.
If I proceed the way like write on object to appendable stream, close stream. Then again open stream, write another object close and so on. This way I am able to read multiple objects properly.
fileOutputStream = new FileOutputStream("abc.dat",true);
outputBuffer = new BufferedOutputStream(fileOutputStream);
objectStream = new AppendableObjectOutputStream(outputBuffer);
BucketUpdate b1 = new BucketUpdate("getAllProducts1",null,"1",null);
BucketUpdate b2 = new BucketUpdate("getAllProducts2",null,"2",null);
BucketUpdate b3 = new BucketUpdate("getAllProducts3",null,"3",null);
objectStream.writeObject(b1);
objectStream.writeObject(b2);
objectStream.writeObject(b3);
objectStream.close();
Calling ObjectOutputStream.reset() after writing each object will fix this.
If you check question you mentioned, you will see that you have to use AppendableObjectOutputStream only to append objects to file, if file already contains some objects. For empty file you have to use ordinary ObjectOutputStream because the header should be written to the beginning in this case.

How to save Chinese Characters to file with java?

I use the following code to save Chinese characters into a .txt file, but when I opened it with Wordpad, I couldn't read it.
StringBuffer Shanghai_StrBuf = new StringBuffer("\u4E0A\u6D77");
boolean Append = true;
FileOutputStream fos;
fos = new FileOutputStream(FileName, Append);
for (int i = 0;i < Shanghai_StrBuf.length(); i++) {
fos.write(Shanghai_StrBuf.charAt(i));
}
fos.close();
What can I do ? I know if I cut and paste Chinese characters into Wordpad, I can save it into a .txt file. How do I do that in Java ?
There are several factors at work here:
Text files have no intrinsic metadata for describing their encoding (for all the talk of angle-bracket taxes, there are reasons XML is popular)
The default encoding for Windows is still an 8bit (or doublebyte) "ANSI" character set with a limited range of values - text files written in this format are not portable
To tell a Unicode file from an ANSI file, Windows apps rely on the presence of a byte order mark at the start of the file (not strictly true - Raymond Chen explains). In theory, the BOM is there to tell you the endianess (byte order) of the data. For UTF-8, even though there is only one byte order, Windows apps rely on the marker bytes to automatically figure out that it is Unicode (though you'll note that Notepad has an encoding option on its open/save dialogs).
It is wrong to say that Java is broken because it does not write a UTF-8 BOM automatically. On Unix systems, it would be an error to write a BOM to a script file, for example, and many Unix systems use UTF-8 as their default encoding. There are times when you don't want it on Windows, either, like when you're appending data to an existing file: fos = new FileOutputStream(FileName,Append);
Here is a method of reliably appending UTF-8 data to a file:
private static void writeUtf8ToFile(File file, boolean append, String data)
throws IOException {
boolean skipBOM = append && file.isFile() && (file.length() > 0);
Closer res = new Closer();
try {
OutputStream out = res.using(new FileOutputStream(file, append));
Writer writer = res.using(new OutputStreamWriter(out, Charset
.forName("UTF-8")));
if (!skipBOM) {
writer.write('\uFEFF');
}
writer.write(data);
} finally {
res.close();
}
}
Usage:
public static void main(String[] args) throws IOException {
String chinese = "\u4E0A\u6D77";
boolean append = true;
writeUtf8ToFile(new File("chinese.txt"), append, chinese);
}
Note: if the file already existed and you chose to append and existing data wasn't UTF-8 encoded, the only thing that code will create is a mess.
Here is the Closer type used in this code:
public class Closer implements Closeable {
private Closeable closeable;
public <T extends Closeable> T using(T t) {
closeable = t;
return t;
}
#Override public void close() throws IOException {
if (closeable != null) {
closeable.close();
}
}
}
This code makes a Windows-style best guess about how to read the file based on byte order marks:
private static final Charset[] UTF_ENCODINGS = { Charset.forName("UTF-8"),
Charset.forName("UTF-16LE"), Charset.forName("UTF-16BE") };
private static Charset getEncoding(InputStream in) throws IOException {
charsetLoop: for (Charset encodings : UTF_ENCODINGS) {
byte[] bom = "\uFEFF".getBytes(encodings);
in.mark(bom.length);
for (byte b : bom) {
if ((0xFF & b) != in.read()) {
in.reset();
continue charsetLoop;
}
}
return encodings;
}
return Charset.defaultCharset();
}
private static String readText(File file) throws IOException {
Closer res = new Closer();
try {
InputStream in = res.using(new FileInputStream(file));
InputStream bin = res.using(new BufferedInputStream(in));
Reader reader = res.using(new InputStreamReader(bin, getEncoding(bin)));
StringBuilder out = new StringBuilder();
for (int ch = reader.read(); ch != -1; ch = reader.read())
out.append((char) ch);
return out.toString();
} finally {
res.close();
}
}
Usage:
public static void main(String[] args) throws IOException {
System.out.println(readText(new File("chinese.txt")));
}
(System.out uses the default encoding, so whether it prints anything sensible depends on your platform and configuration.)
If you can rely that the default character encoding is UTF-8 (or some other Unicode encoding), you may use the following:
Writer w = new FileWriter("test.txt");
w.append("上海");
w.close();
The safest way is to always explicitly specify the encoding:
Writer w = new OutputStreamWriter(new FileOutputStream("test.txt"), "UTF-8");
w.append("上海");
w.close();
P.S. You may use any Unicode characters in Java source code, even as method and variable names, if the -encoding parameter for javac is configured right. That makes the source code more readable than the escaped \uXXXX form.
Be very careful with the approaches proposed. Even specifying the encoding for the file as follows:
Writer w = new OutputStreamWriter(new FileOutputStream("test.txt"), "UTF-8");
will not work if you're running under an operating system like Windows. Even setting the system property for file.encoding to UTF-8 does not fix the issue. This is because Java fails to write a byte order mark (BOM) for the file. Even if you specify the encoding when writing out to a file, opening the same file in an application like Wordpad will display the text as garbage because it doesn't detect the BOM. I tried running the examples here in Windows (with a platform/container encoding of CP1252).
The following bug exists to describe the issue in Java:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
The solution for the time being is to write the byte order mark yourself to ensure the file opens correctly in other applications. See this for more details on the BOM:
http://mindprod.com/jgloss/bom.html
and for a more correct solution see the following link:
http://tripoverit.blogspot.com/2007/04/javas-utf-8-and-unicode-writing-is.html
Here's one way among many. Basically, we're just specifying that the conversion be done to UTF-8 before outputting bytes to the FileOutputStream:
String FileName = "output.txt";
StringBuffer Shanghai_StrBuf=new StringBuffer("\u4E0A\u6D77");
boolean Append=true;
Writer writer = new OutputStreamWriter(new FileOutputStream(FileName,Append), "UTF-8");
writer.write(Shanghai_StrBuf.toString(), 0, Shanghai_StrBuf.length());
writer.close();
I manually verified this against the images at http://www.fileformat.info/info/unicode/char/ . In the future, please follow Java coding standards, including lower-case variable names. It improves readability.
Try this,
StringBuffer Shanghai_StrBuf=new StringBuffer("\u4E0A\u6D77");
boolean Append=true;
Writer out = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(FileName,Append), "UTF8"));
for (int i=0;i<Shanghai_StrBuf.length();i++) out.write(Shanghai_StrBuf.charAt(i));
out.close();

Categories