问题描述
- 关于java的IO中PrintWriter问题
- public class PrintIOTest {
public static void main(String[] ages){
try{
FileOutputStream fos = new FileOutputStream(""test.txt"");
PrintStream ps = new PrintStream(fos);
ps.print(""helloworld!"");}catch (FileNotFoundException e){ e.printStackTrace(); } /*try{ FileWriter fw = new FileWriter(""test.txt""); PrintWriter pw = new PrintWriter(fw); pw.write(""你好""); }catch(IOException e){ e.printStackTrace(); }*/}
}
用字节流外面套一个PrintStream运行正常,但是换成注释里的内容却只能新建test.tex,而不写内容,请问是怎么回事??
解决方案
用这个:
try {
FileWriter fw = new FileWriter(""test.txt"");
PrintWriter pw = new PrintWriter(fw);
pw.write(""你好"");
pw.close();
} catch (IOException e) {
e.printStackTrace();
}
解决方案二:
PrintStream和PrintWriter的区别,参考:http://blog.csdn.net/y3wegy/article/details/8783314
解决方案三:
FileWriter 你需要显式调用 flush 方法。FileWriter 的 close 调用的是其父类 OutputStreamWriter 的 close 方法,其源码如下:
public void close() throws IOException {
se.close();
}
se 是 OutputStreamWriter 对象的私有 StreamEncoder 变量。查看 StreamEncoder 的 close 源码如下:
public void close() throws IOException {
synchronized (lock) {
if (!isOpen)
return;
implClose();
isOpen = false;
}
}
void implClose() throws IOException {
flushLeftoverChar(null true);
try {
for (;;) {
CoderResult cr = encoder.flush(bb);
if (cr.isUnderflow())
break;
if (cr.isOverflow()) {
assert bb.position() > 0;
writeBytes();
continue;
}
cr.throwException();
}
if (bb.position() > 0)
writeBytes();
if (ch != null)
ch.close();
else
out.close();
} catch (IOException x) {
encoder.reset();
throw x;
}
}
在 close 之前先将数据 flush。这就是显式调用 FileWriter 的 close 能够写入数据的原因。
OK,这是 FileWriter 的源码分析。现在来看 PrintStream,你调用的是这个:
public void print(String s) {
if (s == null) {
s = ""null"";
}
write(s);
}
它调用了自己封装的 write 方法:
private void write(String s) {
try {
synchronized (this) {
ensureOpen();
textOut.write(s);
textOut.flushBuffer();
charOut.flushBuffer();
if (autoFlush && (s.indexOf('n') >= 0))
out.flush();
}
}
catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
}
catch (IOException x) {
trouble = true;
}
}
它进行了显式 flush,这就是 PrintStream 的 write 不需要显式 flush 的原因。
回过头来再看 FileWriter 的 write 方法,你调用的是其继承自 java.io.Writer 的:
public void write(String str) throws IOException {
write(str 0 str.length());
}
它调用了 java.io.Writer 的:
public void write(String str int off int len) throws IOException {
synchronized (lock) {
char cbuf[];
if (len <= writeBufferSize) {
if (writeBuffer == null) {
writeBuffer = new char[writeBufferSize];
}
cbuf = writeBuffer;
} else { // Don't permanently allocate very large buffers.
cbuf = new char[len];
}
str.getChars(off (off + len) cbuf 0);
write(cbuf 0 len);
}
}
它调用了抽象方法
abstract public void write(char cbuf[] int off int len) throws IOException;
因为你使用 FileWriter,所以它实际上调用的是 OutputStreamWriter 实现的 public void write(char cbuf[] int off int len):
public void write(char cbuf[] int off int len) throws IOException {
se.write(cbuf off len);
}
se(也就是 sun.nio.cs.StreamEncoder) 实现的 write 方法是不自行 flush 的。有其源码为证:
public void write(char cbuf[] int off int len) throws IOException {
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
implWrite(cbuf off len);
}
}
void implWrite(char cbuf[] int off int len)
throws IOException
{
CharBuffer cb = CharBuffer.wrap(cbuf off len);
if (haveLeftoverChar)
flushLeftoverChar(cb false);
while (cb.hasRemaining()) {
CoderResult cr = encoder.encode(cb bb false);
if (cr.isUnderflow()) {
assert (cb.remaining() <= 1) : cb.remaining();
if (cb.remaining() == 1) {
haveLeftoverChar = true;
leftoverChar = cb.get();
}
break;
}
if (cr.isOverflow()) {
assert bb.position() > 0;
writeBytes();
continue;
}
cr.throwException();
}
}
它使用了字节缓存,在适当的时候才会 flush 一下。
也就是说你 PrintStream 写数据不需要显式 flush,而 FileWriter 写数据需要你显式 flush,不然会有数据丢失。
这下你该明白了吧?