File I/O source code--读取文件 相关方法阅读
2014-12-09 19:07
393 查看
上一篇本来是要介绍读取文件的,后来写着写着,感觉我连如何创建文件都不知道,所以索性就标题改了,挪到这篇来讨论读取文件的方法
我们从br.readLine()直接来跟踪代码
最终会执行到in.read(cb, dst, cb. length - dst)这步骤,当执行完这步之后文件中的数据将会存放到cb数组中来,拿in.read( .. )方法又做了什么呢
进去我们发现它是一个抽象方法:
那java.io.Reader抽象类肯定有实现类来实现这个方法,经过查找发现在sun.nio.cs.StreamDecoder中:
上面有一句in.read(bb.array(), bb.arrayOffset() + pos, rem); 这句是直接调用java.io.FileInputStream类型中的方法
代码跟到这里我就跟不下去了,至于jvm是如何调用系统中的方法来读取磁盘文件的,我不知道,不过我在网上看到一篇这样的文章,对这个I/O有大概的一些了解,它的工作原理如下图:
我觉得这篇文章讲的很好,详细可参考:深入分析 Java I/O 的工作机制
还有一篇是讲解I/O底层的:Java I/O底层是如何工作的?
/* 读入TXT文件 */ String pathname = "D:\\input.txt"; //绝对路径或相对路径都可以,这里是绝对路径,写入文件时演示相对路径 File filename = new File(pathname); // 要读取以上路径的input.txt文件 InputStreamReader reader = new InputStreamReader( new FileInputStream(filename)); // 建立一个输入流对象reader BufferedReader br = new BufferedReader(reader); //建立一个对象,它把文件内容转成计算机能读懂的语言 String line = ""; line = br.readLine(); while (line != null) { System.out.println(line); line = br.readLine(); // 一次读入一行数据 }
我们从br.readLine()直接来跟踪代码
/** * Reads a line of text. A line is considered to be terminated by any one * of a line feed ('\n'), a carriage return ('\r'), or a carriage return * followed immediately by a linefeed. * * @return A String containing the contents of the line, not including * any line-termination characters, or null if the end of the * stream has been reached * * @exception IOException If an I/O error occurs * * @see java.nio.file.Files#readAllLines */ public String readLine() throws IOException { return readLine(false); }
/** * Reads a line of text. A line is considered to be terminated by any one * of a line feed ('\n'), a carriage return ('\r'), or a carriage return * followed immediately by a linefeed. * * @param ignoreLF If true, the next '\n' will be skipped * * @return A String containing the contents of the line, not including * any line-termination characters, or null if the end of the * stream has been reached * * @see java.io.LineNumberReader#readLine() * * @exception IOException If an I/O error occurs */ String readLine(boolean ignoreLF) throws IOException { StringBuffer s = null; int startChar; synchronized (lock) { ensureOpen(); boolean omitLF = ignoreLF || skipLF; bufferLoop: for (;;) { if (nextChar >= nChars) fill(); if (nextChar >= nChars) { /* EOF */ if (s != null && s.length() > 0) return s.toString(); else return null; } boolean eol = false; char c = 0; int i; /* Skip a leftover '\n', if necessary */ if (omitLF && (cb[nextChar] == '\n')) nextChar++; skipLF = false; omitLF = false; charLoop: for (i = nextChar; i < nChars; i++) { c = cb[i]; if ((c == '\n') || (c == '\r')) { eol = true; break charLoop; } } startChar = nextChar; nextChar = i; if (eol) { String str; if (s == null) { str = new String(cb, startChar, i - startChar); } else { s.append(cb, startChar, i - startChar); str = s.toString(); } nextChar++; if (c == '\r') { skipLF = true; } return str; } if (s == null) s = new StringBuffer(defaultExpectedLineLength); s.append(cb, startChar, i - startChar); } } }我跟踪代码发现会进入fill()方法:
/** * Fills the input buffer, taking the mark into account if it is valid. */ private void fill() throws IOException { int dst; if (markedChar <= UNMARKED) { /* No mark */ dst = 0; } else { /* Marked */ int delta = nextChar - markedChar; if (delta >= readAheadLimit) { /* Gone past read-ahead limit: Invalidate mark */ markedChar = INVALIDATED; readAheadLimit = 0; dst = 0; } else { if (readAheadLimit <= cb.length) { /* Shuffle in the current buffer */ System.arraycopy(cb, markedChar, cb, 0, delta); markedChar = 0; dst = delta; } else { /* Reallocate buffer to accommodate read-ahead limit */ char ncb[] = new char[readAheadLimit]; System.arraycopy(cb, markedChar, ncb, 0, delta); cb = ncb; markedChar = 0; dst = delta; } nextChar = nChars = delta; } } int n; do { n = in.read(cb, dst, cb.length - dst); } while (n == 0); if (n > 0) { nChars = dst + n; nextChar = dst; } }
最终会执行到in.read(cb, dst, cb. length - dst)这步骤,当执行完这步之后文件中的数据将会存放到cb数组中来,拿in.read( .. )方法又做了什么呢
进去我们发现它是一个抽象方法:
/** * Reads characters into a portion of an array. This method will block * until some input is available, an I/O error occurs, or the end of the * stream is reached. * * @param cbuf Destination buffer * @param off Offset at which to start storing characters * @param len Maximum number of characters to read * * @return The number of characters read, or -1 if the end of the * stream has been reached * * @exception IOException If an I/O error occurs */ abstract public int read(char cbuf[], int off, int len) throws IOException;
那java.io.Reader抽象类肯定有实现类来实现这个方法,经过查找发现在sun.nio.cs.StreamDecoder中:
/** * Reads characters into a portion of an array. * * @param cbuf Destination buffer * @param offset Offset at which to start storing characters * @param length Maximum number of characters to read * * @return The number of characters read, or -1 if the end of the * stream has been reached * * @exception IOException If an I/O error occurs */ public int read(char cbuf[], int offset, int length) throws IOException { return sd.read(cbuf, offset, length);
public int read(char cbuf[], int offset, int length) throws IOException { int off = offset; int len = length; synchronized (lock) { ensureOpen(); if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } if (len == 0) return 0; int n = 0; if (haveLeftoverChar) { // Copy the leftover char into the buffer cbuf[off] = leftoverChar; off++; len--; haveLeftoverChar = false; n = 1; if ((len == 0) || !implReady()) // Return now if this is all we can produce w/o blocking return n; } if (len == 1) { // Treat single-character array reads just like read() int c = read0(); if (c == -1) return (n == 0) ? -1 : n; cbuf[off] = (char)c; return n + 1; } return n + implRead(cbuf, off, off + len); } }
int implRead(char[] cbuf, int off, int end) throws IOException { // In order to handle surrogate pairs, this method requires that // the invoker attempt to read at least two characters. Saving the // extra character, if any, at a higher level is easier than trying // to deal with it here. assert (end - off > 1); CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off); if (cb.position() != 0) // Ensure that cb[0] == cbuf[off] cb = cb.slice(); boolean eof = false; for (;;) { CoderResult cr = decoder.decode(bb, cb, eof); if (cr.isUnderflow()) { if (eof) break; if (!cb.hasRemaining()) break; if ((cb.position() > 0) && !inReady()) break; // Block at most once int n = readBytes(); if (n < 0) { eof = true; if ((cb.position() == 0) && (!bb.hasRemaining())) break; decoder.reset(); } continue; } if (cr.isOverflow()) { assert cb.position() > 0; break; } cr.throwException(); } if (eof) { // ## Need to flush decoder decoder.reset(); } if (cb.position() == 0) { if (eof) return -1; assert false; } return cb.position(); }
private int readBytes() throws IOException { bb.compact(); try { if (ch != null) { // Read from the channel int n = ch.read(bb); if (n < 0) return n; } else { // Read from the input stream, and then update the buffer int lim = bb.limit(); int pos = bb.position(); assert (pos <= lim); int rem = (pos <= lim ? lim - pos : 0); assert rem > 0; int n = in.read(bb.array(), bb.arrayOffset() + pos, rem); if (n < 0) return n; if (n == 0) throw new IOException("Underlying input stream returned zero bytes"); assert (n <= rem) : "n = " + n + ", rem = " + rem; bb.position(pos + n); } } finally { // Flip even when an IOException is thrown, // otherwise the stream will stutter bb.flip(); } int rem = bb.remaining(); assert (rem != 0) : rem; return rem; }
上面有一句in.read(bb.array(), bb.arrayOffset() + pos, rem); 这句是直接调用java.io.FileInputStream类型中的方法
/** * Reads up to <code>len</code> bytes of data from this input stream * into an array of bytes. If <code>len</code> is not zero, the method * blocks until some input is available; otherwise, no * bytes are read and <code>0</code> is returned. * * @param b the buffer into which the data is read. * @param off the start offset in the destination array <code>b</code> * @param len the maximum number of bytes read. * @return the total number of bytes read into the buffer, or * <code>-1</code> if there is no more data because the end of * the file has been reached. * @exception NullPointerException If <code>b</code> is <code>null</code>. * @exception IndexOutOfBoundsException If <code>off</code> is negative, * <code>len</code> is negative, or <code>len</code> is greater than * <code>b.length - off</code> * @exception IOException if an I/O error occurs. */ public int read(byte b[], int off, int len) throws IOException { return readBytes(b, off, len); }
/** * Reads a subarray 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 * @exception IOException If an I/O error has occurred. */ private native int readBytes(byte b[], int off, int len) throws IOException;
代码跟到这里我就跟不下去了,至于jvm是如何调用系统中的方法来读取磁盘文件的,我不知道,不过我在网上看到一篇这样的文章,对这个I/O有大概的一些了解,它的工作原理如下图:
我觉得这篇文章讲的很好,详细可参考:深入分析 Java I/O 的工作机制
还有一篇是讲解I/O底层的:Java I/O底层是如何工作的?
相关文章推荐
- File I/O source code--新建文件 相关方法阅读
- File I/O source code--写入文件 相关方法阅读
- ArrayList source code相关方法阅读
- php读取网络文件curl,fsockopen,file_get_contents,file,fopen几种方法
- 按字符串读取文件内容NSString stringWithContentsOfFile: (NSString类方法)
- php 使用file_get_contents读取大文件的方法
- java 使用相对路径读取文件File(类构造方法)
- PHP相关系列 - linux环境下PHP无法读取CSV文件中文字的解决方法
- 本文给出了一种方便实用的解决大文件的读取、存储等处理的方法,并结合相关程序代码对具体的实现过程进行了介绍
- linux kernel source code阅读记录(一)LDS文件详解
- Spring: 读取 .properties 文件地址,json转java对象,el使用java类方法相关 (十三)
- html5 使用FileReader对象的readAsDataURL方法来读取图像文件
- Win7中Javascript读取File框中文件路径变更为C:\Fakepath的解决方法
- SVN无法读取cruuent修复方法 Can't read file : End of file found 文件:txn_current、current
- unable to read project file....不能读取项目文件的解决方法
- FileReader读取文件方法
- php读取网络文件 curl, fsockopen ,file_get_contents 几个方法的效率对比
- file()创建文件方法 分类: python python基础学习 2012-12-24 18:17 239人阅读 评论(0) 收藏
- SVN无法读取cruuent修复方法 Can't read file : End of file found 文件:txn_current、current
- filestream read方法 循环读取固定文件