本文大多技术围绕调整磁盘文件 I/O,但是有些内容也同样适合网络 I/O 和窗口输出。
第一部分技术讨论底层的I/O问题,然后讨论诸如压缩,格式化和串行化等高级I/O问题。然而这个讨论没有包含应用设计问题,例如搜索算法和数据结构,也没有讨论系统级的问题,例如文件高速缓冲。
Java语言采取两种截然不同的磁盘文件结构。一个是基于字节流,另一个是字符序列。在Java语言中一个字符有两个字节表示,而不是像通常的语言如c语言那样是一个字节。因此,从一个文件读取字符时需要进行转换。这个不同在某些情况下是很重要的,就像下面的几个例子将要展示的那样。
低级I/O相关的问题:
缓冲
读写文本文件
格式化的代价
随机访问
高级I/O问题
压缩
高速缓冲
分解
串行化
获取文件信息
更多信息
加速I/O的基本规则
避免访问磁盘
避免访问底层的操作系统
避免方法调用
避免个别的处理字节和字符
很明显这些规则不能在所有的问题上避免,因为如果能够的话就没有实际的I/O被执行。
对于一个1 MB的输入文件,以秒为单位的执行时间是:
FileInputStream的read方法,每次读取一个字节,不用缓冲 6.9秒
BufferedInputStream的read方法使用BufferedInputStream 0.9秒
FileInputStream的read方法读取数据到直接缓冲 0.4秒
或者说在最慢的方法和最快的方法间是17比1的不同。
这个巨大的加速并不能证明你应该总是使用第三种方法,即自己做缓冲。这可能是一个错误的倾向特别是在处理文件结束事件时没有仔细的实现。在可读性上它也没有其它方法好。但是记住时间花费在哪儿了以及在必要的时候如何矫正是很有用。方法2 或许是对于大多应用的 "正确" 方法.
方法 2 和 3 使用了缓冲技术, 大块文件被从磁盘读取,然后每次访问一个字节或字符。缓冲是一个基本而重要的加速I/O 的技术,而且有几个类支持缓冲(BufferedInputStream 用于字节, BufferedReader 用于字符)。
缓冲区越大I/O越快吗?典型的Java缓冲区长1024 或者 2048 字节,一个更大的缓冲区有可能加速 I/O但比重很小,大约5 到10%。
方法1: 读方法
第一个方法简单的使用FileInputStream的read方法:
FileInputStream的read方法每次读取文件的下一个字节,触发了大量的底层运行时系统调用
优点:编码简单,适用于小文件
缺点:读写频繁,不适用于大文件
import java.io.*;
public class intro1 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis = new FileInputStream(args[0]); //建立指向文件的读写流
int cnt = 0;
int b;
while ((b = fis.read()) != -1) { // FileInputStream的read方法每次读取文件一个字节
if (b == '\n')
cnt++;
}
fis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
方法 2: 使用大缓冲区
第二种方法使用大缓冲区避免了上面的问题:
BufferedInputStream的read方法 把文件的字节块读入缓冲区,然后每次读取一个字节,每次填充缓冲只需要访问一次底层存储接口
优点:避免每个字节的底层读取,编码相对不复杂
缺点:缓存占用了小量内存
import java.io.*;
public class intro2 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis = new FileInputStream(args[0]);
BufferedInputStream bis = new BufferedInputStream(fis); //把文件读取流指向缓冲区
int cnt = 0;
int b;
while ((b = bis.read()) != -1) { //BufferedInputStream的read方法 把文件的字节块独
//入缓冲区BufferedInputStream,然后每次读取一个字节
if (b == '\n')
cnt++;
}
bis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
方法 3: 直接缓冲
FileInputStream的read方法直接读入字节块到直接缓冲buf,然后每次读取一个字节。
优点:速度最快,
缺点:编码稍微复杂,可读性差,占用了小量内存,
import java.io.*;
public class intro3 {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
FileInputStream fis = new FileInputStream(args[0]);
byte buf[] = new byte[2048];
int cnt = 0;
int n;
while ((n = fis.read(buf)) != -1) { // FileInputStream的read方法直接读入字节块到
//直接缓冲buf,然后每次读取一个字节
for (int i = 0; i < n; i++) {
if (buf[i] == '\n')
cnt++;
}
}
fis.close();
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
方法4: 缓冲整个文件
缓冲的极端情况是事先决定整个文件的长度,然后读取整个文件。
优点:把文件底层读取降到最少,一次,
缺点:大文件会耗尽内存。
import java.io.*;
public class readfile {
public static void main(String args[]) {
if (args.length != 1) {
System.err.println("missing filename");
System.exit(1);
}
try {
int len = (int)(new File(args[0]).length());
FileInputStream fis = new FileInputStream(args[0]);
byte buf[] = new byte[len]; //建立直接缓冲
fis.read(buf); // 读取整个文件
fis.close();
int cnt = 0;
for (int i = 0; i < len; i++) {
if (buf[i] == '\n')
cnt++;
}
System.out.println(cnt);
}
catch (IOException e) {
System.err.println(e);
}
}
}
这个方法很方便,在这里文件被当作一个字节数组。但是有一个明显得问题是有可能没有读取一个巨大的文件的足够的内存。
缓冲的另一个方面是向窗口终端的文本输出。缺省情况下, System.out ( 一个PrintStream) 是行缓冲的,这意味着在遇到一个新行符后输出缓冲区被提交。
分享到:
相关推荐
java控制串口发送数据时在windows环境下正常,linux环境下报错C [librxtxSerial.so+0x75da] Java_gnu_io_RXTXPort_nativeDrain+0xea,经多方查询验证为rxtx包版本问题,用本文档中的版本可以正常运行
该文件用于解决通过java控制串口发送数据给时在Linux...报错内容如下: [librxtxSerial.so+0x75da] Java_gnu_io_RXTXPort_nativeDrain+0xea。经过一番研究得出结论为为rxtx包版本问题,使用本文档中的版本即可正常运行
本资源“java_io.rar”提供了关于如何在Java中进行文件操作的示例代码,包括读取、移动、删除和复制文件等常见任务。我们将深入探讨这些主题,以便更好地理解Java I/O API的使用。 首先,让我们从读取本地文件开始...
Java IO(Input/Output)是Java编程语言中用于处理输入和输出操作的重要部分。这个"j0601IO_chicken_Java-IO_prettyjtt_"标题可能指的是一个关于Java IO的学习资源,其中"chicken"可能是一个比喻,表示初学者或者...
本篇主要介绍Java中的IO操作中的类层次结构以及缓冲流的使用。 #### 类层次结构 Java IO体系主要通过一系列抽象类和接口构建而成,形成了丰富的类层次结构。这种结构不仅方便了程序员理解和使用,也极大地扩展了...
Java IO 复用技术是针对服务器并发处理能力的关键所在,特别是在高并发环境下,服务器需要能够及时处理大量并发的TCP连接,同时保持高效利用CPU和其他资源。并发编程的目标是尽可能提高处理并发连接的数量,直到物理...
在"Java_IO.rar"这个压缩包中,包含了一个名为"Java_IO操作_(读写、追加、删除、移动、复制、修改).docx"的文档,该文档详细介绍了如何使用Java的IO流进行各种文件操作。以下是对这些操作的详细介绍: 1. **读取...
Java中的IO操作是进行文件处理的核心技术之一,涵盖了读写、追加、删除、移动、复制、修改等基本功能。本文将围绕这些操作展开详细解释,重点解析如何使用Java进行文件的读取。 ### 一、Java IO读取文件内容 #### ...
Java IO流是Java平台中处理输入/输出操作的核心机制,广泛应用于数据的读写、文件复制、网络通信等场景。"get9va"可能是指一个特定的教程或课程系列的一部分,这里的"09_IOAndProperties"标题暗示我们将深入探讨Java...
由于文件名为"SE_JAVA_EXP_E046",我们可以推测这可能是系列练习题中的第46个,可能涉及到一些进阶主题,例如面向对象编程、异常处理、多线程、集合框架或者IO流等。 在Java编程中,面向对象编程(Object-Oriented ...
Java IO(Input/Output)是Java编程语言中用于处理输入输出操作的基础框架,它提供了丰富的类库,使得程序能够与各种设备、文件、网络进行数据交互。然而,传统的IO模型在处理大量并发连接时表现出效率较低的问题,...
Java中的IO操作不仅仅局限于对文件的操作,还包括对内存数组的处理、网络通信的处理等,具有很高的灵活性和强大的功能。在进行文件读写操作时,我们通常会先建立一个File对象来表示要操作的文件,然后根据需要读写的...
在本实验中,我们将探讨Java IO的基础知识,包括流的概念、不同类型的流以及如何将这些概念应用到实际的数据库操作中。 首先,让我们了解一下Java IO的基本概念。Java IO框架是Java标准库的一部分,它提供了一系列...
Java中的IO操作基于流(Stream)的概念,流是数据的序列,可以是字节流或字符流。流的方向分为输入流(Input Stream)和输出流(Output Stream),它们分别用于数据的读取和写入。 2. **基本流类型** - 字节流:...
Java IO(Input/Output)是Java平台中用于处理输入输出操作的重要部分,它允许程序与外部设备进行数据交互。在Java中,IO流分为两大类:字节流和字符流,每种流又有输入流和输出流之分,分别用于数据的读取和写入。 ...
java.io是Java卡API_V2.2.1中定义的一部分,提供了Java卡应用程序的输入/输出操作能力。该包包括File、InputStream、OutputStream、Reader、Writer等类和接口。 9. 类摘要 Java卡API_V2.2.1中定义了一些重要的类,...