您的位置:首页 > 其它

File I/O source code--写入文件 相关方法阅读

2014-12-10 14:14 393 查看
测试例子:

/* 写入Txt文件 */
File writename = new File(".\\output.txt"); //相对路径,如果没有则要建立一个新的output。txt文件
writename.createNewFile(); // 创建新文件
BufferedWriter out = new BufferedWriter(new FileWriter(writename));
out.write("我会写入文件啦\r\n"); // \r\n即为换行
out.flush(); // 把缓存区内容压入文件
out.close(); // 最后记得关闭文件


我们从out.write( ... )来看,它首先会调用java.io.Write 类中的方法:

/**
* Writes a string.
*
* @param  str
*         String to be written
*
* @throws  IOException
*          If an I/O error occurs
*/
public void write(String str) throws IOException {
write(str, 0, str.length());
}


本来应该调用java.io.Write类中的write(String str, int off, int len)方法,但是BufferedWriter类中重写了这个方法,所以调用子类中重写的方法:

/**
* Writes a portion of a String.
*
* <p> If the value of the <tt>len</tt> parameter is negative then no
* characters are written.  This is contrary to the specification of this
* method in the {@linkplain java.io.Writer#write(java.lang.String,int,int)
* superclass}, which requires that an {@link IndexOutOfBoundsException} be
* thrown.
*
* @param  s     String to be written
* @param  off   Offset from which to start reading characters
* @param  len   Number of characters to be written
*
* @exception  IOException  If an I/O error occurs
*/
public void write(String s, int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();

int b = off, t = off + len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
s.getChars(b, b + d, cb, nextChar);
b += d;
nextChar += d;
if (nextChar >= nChars)
flushBuffer();
}
}
}
注意看这里的s.getChar(b, b + d, cb, nextChar),本来这里的cb数组是空的,但是执行完这句后就有值了,原因我看了一下,是因为String的值会拆成数组然后赋值给cb数组:

/**
* Copies characters from this string into the destination character
* array.
* <p>
* The first character to be copied is at index <code>srcBegin</code>;
* the last character to be copied is at index <code>srcEnd-1</code>
* (thus the total number of characters to be copied is
* <code>srcEnd-srcBegin</code>). The characters are copied into the
* subarray of <code>dst</code> starting at index <code>dstBegin</code>
* and ending at index:
* <p><blockquote><pre>
*     dstbegin + (srcEnd-srcBegin) - 1
* </pre></blockquote>
*
* @param      srcBegin   index of the first character in the string
*                        to copy.
* @param      srcEnd     index after the last character in the string
*                        to copy.
* @param      dst        the destination array.
* @param      dstBegin   the start offset in the destination array.
* @exception IndexOutOfBoundsException If any of the following
*            is true:
*            <ul><li><code>srcBegin</code> is negative.
*            <li><code>srcBegin</code> is greater than <code>srcEnd</code>
*            <li><code>srcEnd</code> is greater than the length of this
*                string
*            <li><code>dstBegin</code> is negative
*            <li><code>dstBegin+(srcEnd-srcBegin)</code> is larger than
*                <code>dst.length</code></ul>
*/
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > count) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, offset + srcBegin, dst, dstBegin,
srcEnd - srcBegin);
}


cb数组有了值后,我们再看flushBuffer()方法:

/**
* Flushes the output buffer to the underlying character stream, without
* flushing the stream itself.  This method is non-private only so that it
* may be invoked by PrintStream.
*/
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
}


核心就在这里的out.write(cb, 0, nextChar) 我跟踪源代码发现会进入java.io.Writer类中的:

/**
* Writes a portion of an array of characters.
*
* @param  cbuf
*         Array of characters
*
* @param  off
*         Offset from which to start writing characters
*
* @param  len
*         Number of characters to write
*
* @throws  IOException
*          If an I/O error occurs
*/
abstract public void write(char cbuf[], int off, int len) throws IOException;


这里会调用java.io.OutputStreamWriter类中的方法(java.io.FileWriter继承java.io.OutputStreamWriter):

/**
* Writes a portion of an array of characters.
*
* @param  cbuf  Buffer of characters
* @param  off   Offset from which to start writing characters
* @param  len   Number of characters to write
*
* @exception  IOException  If an I/O error occurs
*/
public void write(char cbuf[], int off, int len) throws IOException {
se.write(cbuf, off, len);
}


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();
}
}


上面的这句话需要注意一下:CharBuffer cb = CharBuffer.wrap(cbuf, off, len); 解读意思就是讲数据放入字符缓冲区

/**
* Wraps a char array into a buffer.
*
* <p> The new buffer will be backed by the given char array;
* that is, modifications to the buffer will cause the array to be modified
* and vice versa.  The new buffer's capacity will be
* <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit
* will be <tt>offset + length</tt>, and its mark will be undefined.  Its
* {@link #array </code>backing array<code>} will be the given array, and
* its {@link #arrayOffset </code>array offset<code>} will be zero.  </p>
*
* @param  array
*         The array that will back the new buffer
*
* @param  offset
*         The offset of the subarray to be used; must be non-negative and
*         no larger than <tt>array.length</tt>.  The new buffer's position
*         will be set to this value.
*
* @param  length
*         The length of the subarray to be used;
*         must be non-negative and no larger than
*         <tt>array.length - offset</tt>.
*         The new buffer's limit will be set to <tt>offset + length</tt>.
*
* @return  The new char buffer
*
* @throws  IndexOutOfBoundsException
*          If the preconditions on the <tt>offset</tt> and <tt>length</tt>
*          parameters do not hold
*/
public static CharBuffer wrap(char[] array,
int offset, int length)
{
try {
return new HeapCharBuffer(array, offset, length);
} catch (IllegalArgumentException x) {
throw new IndexOutOfBoundsException();
}
}


看完flushBuffer();方法,我们再来看看out.flush();方法:

/**
* Flushes the stream.
*
* @exception  IOException  If an I/O error occurs
*/
public void flush() throws IOException {
se.flush();
}
public void flush() throws IOException {
synchronized (lock) {
ensureOpen();
implFlush();
}
}


我们来看看implFlush()方法:

void implFlush() throws IOException {
implFlushBuffer();
if (out != null)
out.flush();
}


void implFlushBuffer() throws IOException {
if (bb.position() > 0)
writeBytes();
}


private void writeBytes() throws IOException {
bb.flip();
int lim = bb.limit();
int pos = bb.position();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);

if (rem > 0) {
if (ch != null) {
if (ch.write(bb) != rem)
assert false : rem;
} else {
out.write(bb.array(), bb.arrayOffset() + pos, rem);
}
}
bb.clear();
}


当程序执行到out.write(bb.array(), bb.arrayOffset() + pos, rem);这句的时候我不知道是在哪里实现的,断点老是进不去,纠结很久.........

第二天,重新梳理一遍: java.io.FileWriter的构造方法如下:

/**
* Constructs a FileWriter object given a File object.
*
* @param file  a File object to write to.
* @throws IOException  if the file exists but is a directory rather than
*                  a regular file, does not exist but cannot be created,
*                  or cannot be opened for any other reason
*/
public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
}


/**
* Creates an OutputStreamWriter that uses the default character encoding.
*
* @param  out  An OutputStream
*/
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}


而我上面 用到的out对象是java.io.OutputStream,这里就很清楚了,我用到的肯定是java.io.FileOutputStream对象,那么为什么我断点进入不了呢,后来我把源码重新编译一次放入rt.jar包中,断点进入了 哈哈:

/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this file output stream.
*
* @param      b     the data.
* @param      off   the start offset in the data.
* @param      len   the number of bytes to write.
* @exception  IOException  if an I/O error occurs.
*/
public void write(byte b[], int off, int len) throws IOException {
writeBytes(b, off, len, append);
}


/**
* Writes a sub array as a sequence of bytes.
* @param b the data to be written
* @param off the start offset in the data
* @param len the number of bytes that are written
* @param append {@code true} to first advance the position to the
*     end of file
* @exception IOException If an I/O error has occurred.
*/
private native void writeBytes(byte b[], int off, int len, boolean append)
throws IOException;


这里最终又用到了本地方法,这时java的任务算是告一段落,剩下的交给操作系统底层来完成了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐