未公开的mustang核心秘密(三):jdk读取文件的秘密
2007-07-12 11:13
281 查看
最近做一个很简单的函数,要两个返回值,我打算有一个类封装一下返回,后来领导要求使用StringBuilder返回,不用 StringBuffer,因为局部变量StringBuffer最后还是要编译为StringBuilder,因为StringBuilder没有任何 同步。
问了一下大家的看法,风南说InputStream 的int read(byte[] b) 从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中,也是类似的,看来有必要研究一下IO了。
InputStream类中重要的函数,只有一个抽象的有用,
public abstract int read() throws IOException;
其他两个read的意义不大。
public int read(byte b[], int off, int len) throws IOException 和
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
下面看它的子类FileInputStream的实现,
/* File Descriptor - handle to the open file */
private FileDescriptor fd;
这个很重要,这是文件句柄,C语言使用fopen函数的都知道。
/**
* Opens the specified file for reading.
* @param name the name of the file
*/
private native void open(String name) throws FileNotFoundException;
/**
* Reads a byte of data from this input stream. This method blocks
* if no input is yet available.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* file is reached.
* @exception IOException if an I/O error occurs.
*/
public native int read() throws IOException;
/**
* 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;
子类修改了父的实现
/**
* Reads up to <code>b.length</code> bytes of data from this input
* stream into an array of bytes. This method blocks until some input
* is available.
*
* @param b the buffer into which the data is 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 IOException if an I/O error occurs.
*/
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
/**
* 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);
}
看出readBytes是关键的所在,windows的native code中只有
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_close0(JNIEnv *env, jobject this) {
handleClose(env, this, fis_fd);
}
是平台相关的。
其他的在share中
FileInputStream.c代码
jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */
/**************************************************************
* static methods to store field ID's in initializers
*/
得到fd的值,这个很重要
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_initIDs(JNIEnv *env, jclass fdClass) {
fis_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;");
}
/**************************************************************
* Input stream
*/
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_open(JNIEnv *env, jobject this, jstring path) {
fileOpen(env, this, path, fis_fd, O_RDONLY);
}
JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_read(JNIEnv *env, jobject this) {
return readSingle(env, this, fis_fd);
}
JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_readBytes(JNIEnv *env, jobject this,
jbyteArray bytes, jint off, jint len) {
return readBytes(env, this, bytes, off, len, fis_fd);
}
JNIEXPORT jlong JNICALL
Java_java_io_FileInputStream_skip(JNIEnv *env, jobject this, jlong toSkip) {
jlong cur = jlong_zero;
jlong end = jlong_zero;
FD fd = GET_FD(this, fis_fd);
if ((cur = IO_Lseek(fd, (jlong)0, (jint)SEEK_CUR)) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "Seek error");
} else if ((end = IO_Lseek(fd, toSkip, (jint)SEEK_CUR)) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "Seek error");
}
return (end - cur);
}
JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_available(JNIEnv *env, jobject this) {
jlong ret;
FD fd = GET_FD(this, fis_fd);
if (IO_Available(fd, &ret)) {
if (ret > INT_MAX) {
ret = (jlong) INT_MAX;
}
return jlong_to_jint(ret);
}
JNU_ThrowIOExceptionWithLastError(env, NULL);
return 0;
}
主要是readBytes的实现,打开io_util.c文件
/* IO helper functions */
int
readSingle(JNIEnv *env, jobject this, jfieldID fid) {
int nread;
char ret;
FD fd = GET_FD(this, fid);
nread = IO_Read(fd, &ret, 1);
if (nread == 0) { /* EOF */
return -1;
} else if (nread == JVM_IO_ERR) { /* error */
JNU_ThrowIOExceptionWithLastError(env, "Read error");
} else if (nread == JVM_IO_INTR) {
JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
}
return ret & 0xFF;
}
/* The maximum size of a stack-allocated buffer.
*/
#define BUF_SIZE 8192
int
readBytes(JNIEnv *env, jobject this, jbyteArray bytes,
jint off, jint len, jfieldID fid)
{
int nread, datalen;
char stackBuf[BUF_SIZE];
char *buf = 0;
FD fd;
if (IS_NULL(bytes)) {
JNU_ThrowNullPointerException(env, 0);
return -1;
}
datalen = (*env)->GetArrayLength(env, bytes);
if ((off < 0) || (off > datalen) ||
(len < 0) || ((off + len) > datalen) || ((off + len) < 0)) {
JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", 0);
return -1;
}
if (len == 0) {
return 0;
} else if (len > BUF_SIZE) {
buf = malloc(len);
if (buf == 0) {
JNU_ThrowOutOfMemoryError(env, 0);
return 0;
}
} else {
buf = stackBuf;
}
fd = GET_FD(this, fid);
nread = IO_Read(fd, buf, len);
if (nread > 0) {
(*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf);
} else if (nread == JVM_IO_ERR) {
JNU_ThrowIOExceptionWithLastError(env, "Read error");
} else if (nread == JVM_IO_INTR) { /* EOF */
JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
} else { /* EOF */
nread = -1;
}
if (buf != stackBuf) {
free(buf);
}
return nread;
}
注意IO_Read在io_util_md.h做了手脚的,
#define IO_Read JVM_Read
其实就是JVM_Read,JVM_Read在hotspot源码中定义的
//%note jvm_r6
return (jint)hpi::read(fd, buf, nbytes);
hpi定义了大量的函数
// HPI_FileInterface
static inline char* native_path(char *path);
static inline int file_type(const char *path);
static inline int open(const char *name, int mode, int perm);
static inline int close(int fd);
static inline jlong lseek(int fd, jlong off, int whence);
static inline int ftruncate(int fd, jlong length);
static inline int fsync(int fd);
static inline int available(int fd, jlong *bytes);
static inline size_t read(int fd, void *buf, unsigned int nBytes);
static inline size_t write(int fd, const void *buf, unsigned int nBytes);
static inline int fsize(int fd, jlong *size);
这就是和平台相关的代码了。window下通过HPIDECL宏转换的
问了一下大家的看法,风南说InputStream 的int read(byte[] b) 从输入流中读取一定数量的字节并将其存储在缓冲区数组 b 中,也是类似的,看来有必要研究一下IO了。
InputStream类中重要的函数,只有一个抽象的有用,
public abstract int read() throws IOException;
其他两个read的意义不大。
public int read(byte b[], int off, int len) throws IOException 和
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
下面看它的子类FileInputStream的实现,
/* File Descriptor - handle to the open file */
private FileDescriptor fd;
这个很重要,这是文件句柄,C语言使用fopen函数的都知道。
/**
* Opens the specified file for reading.
* @param name the name of the file
*/
private native void open(String name) throws FileNotFoundException;
/**
* Reads a byte of data from this input stream. This method blocks
* if no input is yet available.
*
* @return the next byte of data, or <code>-1</code> if the end of the
* file is reached.
* @exception IOException if an I/O error occurs.
*/
public native int read() throws IOException;
/**
* 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;
子类修改了父的实现
/**
* Reads up to <code>b.length</code> bytes of data from this input
* stream into an array of bytes. This method blocks until some input
* is available.
*
* @param b the buffer into which the data is 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 IOException if an I/O error occurs.
*/
public int read(byte b[]) throws IOException {
return readBytes(b, 0, b.length);
}
/**
* 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);
}
看出readBytes是关键的所在,windows的native code中只有
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_close0(JNIEnv *env, jobject this) {
handleClose(env, this, fis_fd);
}
是平台相关的。
其他的在share中
FileInputStream.c代码
jfieldID fis_fd; /* id for jobject 'fd' in java.io.FileInputStream */
/**************************************************************
* static methods to store field ID's in initializers
*/
得到fd的值,这个很重要
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_initIDs(JNIEnv *env, jclass fdClass) {
fis_fd = (*env)->GetFieldID(env, fdClass, "fd", "Ljava/io/FileDescriptor;");
}
/**************************************************************
* Input stream
*/
JNIEXPORT void JNICALL
Java_java_io_FileInputStream_open(JNIEnv *env, jobject this, jstring path) {
fileOpen(env, this, path, fis_fd, O_RDONLY);
}
JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_read(JNIEnv *env, jobject this) {
return readSingle(env, this, fis_fd);
}
JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_readBytes(JNIEnv *env, jobject this,
jbyteArray bytes, jint off, jint len) {
return readBytes(env, this, bytes, off, len, fis_fd);
}
JNIEXPORT jlong JNICALL
Java_java_io_FileInputStream_skip(JNIEnv *env, jobject this, jlong toSkip) {
jlong cur = jlong_zero;
jlong end = jlong_zero;
FD fd = GET_FD(this, fis_fd);
if ((cur = IO_Lseek(fd, (jlong)0, (jint)SEEK_CUR)) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "Seek error");
} else if ((end = IO_Lseek(fd, toSkip, (jint)SEEK_CUR)) == -1) {
JNU_ThrowIOExceptionWithLastError(env, "Seek error");
}
return (end - cur);
}
JNIEXPORT jint JNICALL
Java_java_io_FileInputStream_available(JNIEnv *env, jobject this) {
jlong ret;
FD fd = GET_FD(this, fis_fd);
if (IO_Available(fd, &ret)) {
if (ret > INT_MAX) {
ret = (jlong) INT_MAX;
}
return jlong_to_jint(ret);
}
JNU_ThrowIOExceptionWithLastError(env, NULL);
return 0;
}
主要是readBytes的实现,打开io_util.c文件
/* IO helper functions */
int
readSingle(JNIEnv *env, jobject this, jfieldID fid) {
int nread;
char ret;
FD fd = GET_FD(this, fid);
nread = IO_Read(fd, &ret, 1);
if (nread == 0) { /* EOF */
return -1;
} else if (nread == JVM_IO_ERR) { /* error */
JNU_ThrowIOExceptionWithLastError(env, "Read error");
} else if (nread == JVM_IO_INTR) {
JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
}
return ret & 0xFF;
}
/* The maximum size of a stack-allocated buffer.
*/
#define BUF_SIZE 8192
int
readBytes(JNIEnv *env, jobject this, jbyteArray bytes,
jint off, jint len, jfieldID fid)
{
int nread, datalen;
char stackBuf[BUF_SIZE];
char *buf = 0;
FD fd;
if (IS_NULL(bytes)) {
JNU_ThrowNullPointerException(env, 0);
return -1;
}
datalen = (*env)->GetArrayLength(env, bytes);
if ((off < 0) || (off > datalen) ||
(len < 0) || ((off + len) > datalen) || ((off + len) < 0)) {
JNU_ThrowByName(env, "java/lang/IndexOutOfBoundsException", 0);
return -1;
}
if (len == 0) {
return 0;
} else if (len > BUF_SIZE) {
buf = malloc(len);
if (buf == 0) {
JNU_ThrowOutOfMemoryError(env, 0);
return 0;
}
} else {
buf = stackBuf;
}
fd = GET_FD(this, fid);
nread = IO_Read(fd, buf, len);
if (nread > 0) {
(*env)->SetByteArrayRegion(env, bytes, off, nread, (jbyte *)buf);
} else if (nread == JVM_IO_ERR) {
JNU_ThrowIOExceptionWithLastError(env, "Read error");
} else if (nread == JVM_IO_INTR) { /* EOF */
JNU_ThrowByName(env, "java/io/InterruptedIOException", 0);
} else { /* EOF */
nread = -1;
}
if (buf != stackBuf) {
free(buf);
}
return nread;
}
注意IO_Read在io_util_md.h做了手脚的,
#define IO_Read JVM_Read
其实就是JVM_Read,JVM_Read在hotspot源码中定义的
//%note jvm_r6
return (jint)hpi::read(fd, buf, nbytes);
hpi定义了大量的函数
// HPI_FileInterface
static inline char* native_path(char *path);
static inline int file_type(const char *path);
static inline int open(const char *name, int mode, int perm);
static inline int close(int fd);
static inline jlong lseek(int fd, jlong off, int whence);
static inline int ftruncate(int fd, jlong length);
static inline int fsync(int fd);
static inline int available(int fd, jlong *bytes);
static inline size_t read(int fd, void *buf, unsigned int nBytes);
static inline size_t write(int fd, const void *buf, unsigned int nBytes);
static inline int fsize(int fd, jlong *size);
这就是和平台相关的代码了。window下通过HPIDECL宏转换的
相关文章推荐
- 未公开的mustang核心秘密(五): java判断文件类型和文件打开
- 未公开的mustang核心秘密(四):jdk中实现的rawsocket
- 未公开的mustang核心秘密(二):jni的返回中文问题
- 未公开的mustang核心秘密(一):java的FileSystem
- java 读取文件成二进制数组 需要jdk 7 以上
- python核心编程学习笔记-2016-08-02-01-读取文件的函数中的文件指针问题
- ZendFramework学习第三章(核心组件—使用配置数据之从php配置文件中读取数据)
- ZendFramework学习第三章(核心组件—使用配置数据之从ini配置文件中读取数据)
- Jdk8一行代码读取文件
- 【转】 Windows XPSP2(build 2600)未公开的核心数据结构定义文件
- Struts核心配置文件的分类和读取顺序
- ZendFramework学习第三章(核心组件—使用配置数据之从php配置文件中读取数据)
- 关于JDK出现警告:无法读取AppletViewer属性文件的解决办法
- JDK核心技术卷II高级特性第八卷(第八版)流与文件2
- Spring-boot中读取核心配置文件application和自定义properties配置文件的方式
- 读取CLASS文件JDK版本
- Spring配置不重复读取核心配置文件和创建ApplicationContext
- Spring调用JDK的ResourceBundle读取配置文件
- AB程序核心代码(MFC从文件读取一行+MFC字符串处理+C在文件末尾追加内容)
- ZendFramework学习第三章(核心组件—使用配置数据之从ini配置文件中读取数据)