一、序言
IO操作,才程序中比较普遍,JAVA 中提出了IO/NIO 的概念,也一直在说NIO 比IO快,一直不知道原因,就想memcache 和ehcache 比较优劣一样,这些东西得自己看看如何实现的,才 知道区别,从而才知道优劣以及试用范围,而不仅仅是“听说”!这里我可以先了解下JAVA 如何操作IO的。
二、代码示例
我们先看看简单文件操作:
// 这是将文件转换成输入流的的一种方式,获得了流我们就能干很多事 FileInputStream in = new FileInputStream(new File("...file"));
再看看FileInputStream 的源码:
public FileInputStream(File file) throws FileNotFoundException { String name = (file != null ? file.getPath() : null); // 安全管理器,这里暂时不说 SecurityManager security = System.getSecurityManager(); if (security != null) { // 检查是否可以按这名字读取 security.checkRead(name); } if (name == null) { throw new NullPointerException(); } // 获得文件描述,这个JDK 未公布 fd = new FileDescriptor(); // 打开文件,这是个native 方法,我们可以用openjdk 看看里面 open(name); }
在FileInputStream.c下可以找到方法
// open 方法 JNIEXPORT void JNICALL Java_java_io_FileInputStream_open(JNIEnv *env, jobject this, jstring path) { fileOpen(env, this, path, fis_fd, O_RDONLY); }
OK。我们从该文件上面的引用io_util_md.c找到实现:
void fileOpen(JNIEnv *env, jobject this, jstring path, jfieldID fid, int flags) { jlong h = winFileHandleOpen(env, path, flags); if (h >= 0) { // 设置fd 的值 SET_FD(this, h, fid); } }
在上面文件里面可以看到:winFileHandleOpen,
jlong winFileHandleOpen(JNIEnv *env, jstring path, int flags) { const DWORD access = (flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : (flags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ; const DWORD sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; const DWORD disposition = /* Note: O_TRUNC overrides O_CREAT */ (flags & O_TRUNC) ? CREATE_ALWAYS : (flags & O_CREAT) ? OPEN_ALWAYS : OPEN_EXISTING; const DWORD maybeWriteThrough = (flags & (O_SYNC | O_DSYNC)) ? FILE_FLAG_WRITE_THROUGH : FILE_ATTRIBUTE_NORMAL; const DWORD maybeDeleteOnClose = (flags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : FILE_ATTRIBUTE_NORMAL; const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose; HANDLE h = NULL; if (onNT) { WCHAR *pathbuf = pathToNTPath(env, path, JNI_TRUE); if (pathbuf == NULL) { /* Exception already pending */ return -1; } h = CreateFileW( pathbuf, /* Wide char path name */ access, /* Read and/or write permission */ sharing, /* File sharing flags */ NULL, /* Security attributes */ disposition, /* creation disposition */ flagsAndAttributes, /* flags and attributes */ NULL); free(pathbuf); } else { WITH_PLATFORM_STRING(env, path, _ps) { h = CreateFile(_ps, access, sharing, NULL, disposition, flagsAndAttributes, NULL); } END_PLATFORM_STRING(env, _ps); } if (h == INVALID_HANDLE_VALUE) { int error = GetLastError(); if (error == ERROR_TOO_MANY_OPEN_FILES) { JNU_ThrowByName(env, JNU_JAVAIOPKG "IOException", "Too many open files"); return -1; } throwFileNotFoundException(env, path); return -1; } return (jlong) h; }
好吧,上面代码我也搞不明白- -,但是这几句代码:
h = CreateFileW( pathbuf, /* Wide char path name */ access, /* Read and/or write permission */ sharing, /* File sharing flags */ NULL, /* Security attributes */ disposition, /* creation disposition */ flagsAndAttributes, /* flags and attributes */ NULL); 以及 WITH_PLATFORM_STRING(env, path, _ps) { h = CreateFile(_ps, access, sharing, NULL, disposition, flagsAndAttributes, NULL);
我的理解是,这里通过CreateFileW方法,创建了一个类似文件描述的结构,然后通过CreateFile调windows 下面的底层方法,填充这个结构的数据,那么这个文件对象就能被我们上层对象识别了,就能是获取里面的资源。
OK,我们现在创建了对文件之间的连接,拿到文件流对象之后,来看看我们常用的read 方法。
// 对字节的操作 public native int read() throws IOException; private native int readBytes(byte b[], int off, int len) throws IOException;
在FileInputStream.c 里面同样可以找到
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); }
继续看io_util.c 里面:
jint readSingle(JNIEnv *env, jobject this, jfieldID fid) { jint nread; char ret; FD fd = GET_FD(this, fid); if (fd == -1) { JNU_ThrowIOException(env, "Stream Closed"); return -1; } // 看出是一个一个的读取,fd 表示刚才文件描述的一种结构 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", NULL); } return ret & 0xFF; }
关于IO_Read 的东西,在io_util_md.h 有定义:
/* * HPI是一个与主机通信的并行接口 * Route the routines through HPI */ #define IO_Write JVM_Write #define IO_Sync JVM_Sync #define IO_Read JVM_Read #define IO_Lseek JVM_Lseek #define IO_Available JVM_Available #define IO_SetLength JVM_SetLength
关于JVM_Read 我在jvm.h 里面看到
/* // 从文件里面读取 a char array * Read data from a file decriptor into a char array. * // 文件的来源 * fd the file descriptor to read from. // 读出来的存放位置 * buf the buffer where to put the read data. // 读的字节数 * nbytes the number of bytes to read. * * This function returns -1 on error, and 0 on success. */ JNIEXPORT jint JNICALL JVM_Read(jint fd, char *buf, jint nbytes);
然后在jvm.cpp 里面找到
关于这段代码,大神告诉我是宏定义,关于C和C++ 的东西,我已经无力回天啦。
当然我们知道了介绍,可以理解这里会让调系统的read 方法。
这可以参考:“操作系统read 的原理实现”,google 一下很多,这里就不解释了
jvm.cpp 里面有很多关于IO这块的,可以去看看,但是都是 宏定义。。
关于linux 下的这些代码,还有涉及一下阻塞等东西,以后在去研究一下操作系统的东西吧。
JVM_LEAF(jint, JVM_Read(jint fd, char *buf, jint nbytes)) JVMWrapper2("JVM_Read (0x%x)", fd); //%note jvm_r6 return (jint)os::restartable_read(fd, buf, nbytes); JVM_END
小结:
1.本想了解下底层怎么操作的,但是大概了解下了,最终到read 或者write 的时候,一些基础知识不够,还是不能透彻,但是也足够我们大致了解了。
2.按上面的思路可以看出大概的思路,虽然没写write 的过程,但是最终都是通过流,或者说字符数组在内存里面的一些操作进行,包括我们用装饰器模式搞了很多其他流,基本原理一样,仅仅为了方便加了额外的功能。
3. 有不对的地方还请指出,仅仅是个人学习,分享作用
相关推荐
摘要:Java源码,文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、...
摘要:Java源码,文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、...
* 通常,Reader 所作的每个读取请求都会导致对底层字符或字节流进行相应的读取请求。因此,建议用 BufferedReader包装所有其 read() * 操作可能开销很高的 Reader(如 FileReader和 InputStreamReader)。 * ...
摘要:Java源码,文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、...
摘要:Java源码,文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、...
摘要:Java源码,文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、...
封装javamail、利用谷歌在线翻译编写的jar包、 封装文件IO操作、封装dom4j,进行xml文件的操作。 压缩包内附doc文档,容易操作。
摘要:Java源码,文件操作,数据压缩,文件传输 Java数据压缩与传输实例,可以学习一下实例化套按字、得到文件输入流、压缩输入流、文件输出流、实例化缓冲区、写入数据到文件、关闭输入流、关闭套接字关闭输出流、...
近年来,企业和java开发人员针对java类文件的保护,在对java底层类加 载机制的深度分析后,提出了一系列的保护措施,如本地编译、代码隔离技术、 代码混淆技术、数字水印技术。本文对Java类...
修改数据库连接字段,以及对应包名,即可调用。看的懂的可以选在加载配置文件来获取数据库连接信息。
Java数组倒置 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印...
假定你熟悉基本的I/O操作,比如通过Java I/O API读写文件。这些内容不在本文的讨论范围。 目录 缓存处理和内核vs用户空间 虚拟内存 内存分页 面向文件、块的I/O 文件锁定 面向流的I/O 缓存...
通过这种方法,Java API class文件为底层主机提供了具有平台无关性、标准接口的Java程序。对Java程序而言,无论平台内部如何,Java API都会有同样的表现和可预测的行为。正是由于在每个特定的主机平台上明确地实现了...
通过这种方法,Java API class文件为底层主机提供了具有平台无关性、标准接口的Java程序。对Java程序而言,无论平台内部如何,Java API都会有同样的表现和可预测的行为。正是由于在每个特定的主机平台上明确地实现了...
INI文件操作类库 [ini4j] [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试...
INI文件操作类库 [ini4j] [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试...
INI文件操作类库 [ini4j] [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试...
INI文件操作类库 [ini4j] [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试...
INI文件操作类库 [ini4j] [ini4j] 是一个简单的Java类库,用来读写Windows的ini配置文件。同时还包含一个 Java Perferences API 的实现。 拒绝服务测试工具 Port Groper PortGroper 是一款java写的开源拒绝服务测试...
Java数组倒置 简单 Java图片加水印,支持旋转和透明度设置 摘要:Java源码,文件操作,图片水印 util实现Java图片水印添加功能,有添加图片水印和文字水印,可以设置水印位置,透明度、设置对线段锯齿状边缘处理、水印...