2 zachaxy Zachaxy 于 2014.12.14 13:28 提问

关于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("hello,world!");

    }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,而不写内容,请问是怎么回事??

3个回答

guwei4037
guwei4037   Ds   Rxr 2014.12.14 13:32

用这个:
try {
FileWriter fw = new FileWriter("test.txt");
PrintWriter pw = new PrintWriter(fw);
pw.write("你好");
pw.close();
} catch (IOException e) {
e.printStackTrace();
}

woashizhangsi
woashizhangsi 回复Zachaxy: 生生死死生生死死生生死死
接近 3 年之前 回复
Zachaxy
Zachaxy 而且我不明白,不close就写不进去吗,难道是在close执行之后才把内容写进去的?
接近 3 年之前 回复
Zachaxy
Zachaxy java7以后,IO的资源类不是都实现了AutoCloseable接口了吗?那么在try…catch执行结束后不是会自动帮你close掉吗?
接近 3 年之前 回复
guwei4037
guwei4037   Ds   Rxr 2014.12.14 13:35

PrintStream和PrintWriter的区别,参考:http://blog.csdn.net/y3wegy/article/details/8783314

defonds
defonds   Ds   Rxr 2014.12.15 10:21

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,不然会有数据丢失。
这下你该明白了吧?

Csdn user default icon
上传中...
上传图片
插入图片