Java中的IO

本文系统分析Java IO,介绍其发展演变,指出影响性能的因素。详细讲解基于字节、字符、磁盘、网络的I/O操作,还提及NIO。给出经典IO操作示例,如缓冲输入文件、基本文件输出等,最后进行性能分析并给出文件读写工具类和读取二进制文件的代码。

IO是Java及众多编程语言很重要的一块,同时很多程序的瓶颈和耗时操作也都在IO这块。所以能够很好的解决IO问题对提高程序性能有很大的帮助!本章我们将要系统的对Java IO做个分析,通过理论加实践,希望读者朋友们能真正彻底的理解并且掌握了它。本章系Java之美[从菜鸟到高手演变]系列之Java IO,通过本章的学习,读者朋友们能基本了解到关于IO的很多知识。日后加以理解、分析、在项目中实践,定能灵活运用!

一、简介

IO操作面临很多问题,信息量的巨大,网络的环境等等,因为IO不仅仅是对本地文件、目录的操作,有时对二进制流、还有一部分是网络方面的资源,所以多种原因直接造成IO操作无疑是耗时且复杂多变的。Java对IO的支持是个不断的演变过程,经过了很多的优化,直到JDK1.4以后,才趋于稳定,在JDK1.4中,加入了nio类,解决了很多性能问题,虽然我们有足够的理由不去了解关于Java IO以前的情况,但是为了学好现在的类,我们还是打算去研究下,通过掌握类的优化情况来彻底理解IO的机制!Java IO主要主要在java.io包下,分为四大块近80个类:

1、基于字节操作的I/O接口:InputStream和OutputStream

2、基于字符操作的I/O接口:Writer和Reader

3、基于磁盘操作的I/O接口:File

4、基于网络操作的I/O接口:Socket(不在java.io包下)

影响IO性能的无非就是两大因素:数据的格式及存储的方式,前两类主要是数据格式方面的,后两个类是存储方式方面的:本地和网络。所以策划好这两个方面的活动,有助于我们合理使用IO。

二、基于字节的I/O操作(InputStream和OutputStream)

我们先来看看类图:

二者类似,我只详细讲解InputStream类,OutputStream留给大家自己去学习。InputStream类是个抽象类,里面核心的方法就是read()、read(byte b[])、read(byte b[], int off, int len),这三个方法是用于读取数据的底层的方法,他们可以用来读取一下这些类型的数据:

A. 字节数组

B. String对象

C. 文件

D. 管道,从一端进入,从另一端输出

E. 流

F. internet资源

每一种数据源都有相应的InputStream子类,因为InputStream是个处于顶层的类,用来处理各种数据源的类都继承了InputStream类,我们来看看这些类:

ByteArrayInputStream:处理字节数组的类,允许将内存的缓冲区当做InputStream使用。

StringBufferInputStream:将String转换成InputStream,内部实现用的是StringBuffer。

FileInputStream:从文件中读取数据。

PipedInputStream:用于从管道中读取数据。

SequenceInputStream:将多个流对象转化成一个InputStream。

FilterInputStream:装饰器类,为其它InputStream类提供功能。

做过关于IO操作的读者知道,我们很少单独使用哪个类来实现IO操作,平时都是几个类合起来使用,这其实体现了一种装饰器模式(详见:http://blog.youkuaiyun.com/zhangerqing)的思想,在后面的分析中我们会详细的分析。从上面的图1中我们可以看出,FilterInputStream虽说是Inputstream的子类,但它依然是BufferedInputStream、DataInputStream、LineNumberInputStream、PushbackInputStream类的父类,这四个类分别提供了最贴近我们程序员使用的方法,如:readInt() 、readInt()、readInt()等等。对于IO操作,不管是磁盘还是网络,最终都是对字节的操作,而我们平时写的程序都是字符形式的,所以在传输的过程中需要进行转换。在字符到字节的转换过程中,我们需要用到一个类:InputStreamReader。

三、基于字符的I/O操作(Writer和Reader)

Writer和Reader操作的目的就是操作字符和不是字节,和InputStream和OutputStream配合增加IO效果。通过InputStreamReader和OutputStreamReader可以进行字节和字符的转换,设计Writer和Reader的目的是国际化,使IO操作支持16位的Unicode。我把它们单独的画出来,因为要是全画的话,太大了放不下,有兴趣的TX可以在rational rose中导入其带的JDK类图看看,很过瘾的!

四、基于磁盘的I/O操作(File)

五、基于网络的I/O操作(Socket)

六、NIO

四-六部分由于时间关系,还没有整理完,后续会补出来!

七、经典IO操作

1、缓冲输入文件。

import java.io.BufferedReader;

import java.io.FileReader;

public class InputStreamTest {

public static String read(String filename) throws Exception {

BufferedReader br = new BufferedReader(new FileReader(filename));

String s;

StringBuffer sb = new StringBuffer();

while ((s = br.readLine()) != null) {

sb.append(s + "\n");

}

br.close();

return sb.toString();

}

public static void main(String[] args) throws Exception {

System.out.println(read("src/InputStreamTest.java"));

}

}

这段代码是从磁盘读入InputStreamTest.java文件,然后转换成字符串。输出就是将源文件原样输出。

2、从内存中读取。

import java.io.StringReader;

public class MemoryInput {

public static void main(String[] args) throws Exception {

StringReader in = new StringReader(

InputStreamTest.read("src/MemoryInput.java"));

int c;

while ((c = in.read()) != -1)

System.out.println((char) c);

}

}

read返回的是int类型的数据,所以在输出语句中用char做了强类型转换。该程序将一个一个的输出字符。

3、基本的文件输出。

import java.io.BufferedReader;

import java.io.BufferedWriter;

import java.io.FileWriter;

import java.io.PrintWriter;

import java.io.StringReader;

public class BasicFileOutput {

static String file = "basie.out";

public static void main(String[] args) throws Exception {

BufferedReader in = new BufferedReader(new StringReader(

InputStreamTest.read("src/BasicFileOutput.java")));

PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(

file)));

int lineCount = 1;

String s;

while ((s = in.readLine()) != null) {

out.println(lineCount++ + ": " + s);

}

out.close();

System.out.println(InputStreamTest.read(file));

}

}

输出:

1: import java.io.BufferedReader;

2: import java.io.BufferedWriter;

3: import java.io.FileWriter;

4、RandomAccessFile

RandomAccessFile被我们称为”自我独立的类”,因为它独立于我们前面说的IO类,与InputStream和OutputStream没什么关系,除了实现了DataOutput, DataInput两个接口外。所有方法都是重新编写,而且很多都是native方法,我们来看个例子,了解下这个类:

5、管道流

八、标准I/O

就是我们最原始的使用的从控制台输入或者输出的那些类和方法,如System.in、System.out等。

public class StandardIO {

public static void main(String[] args) throws IOException {

BufferedReader in = new BufferedReader(new InputStreamReader(System.in));

String s;

while ((s = in.readLine()) != null && s.length() != 0)

System.out.println(s);

}

}

System.in返回的是未经包装的InputStream对象,所以需要进行装饰,经InputStreamReader转换为Reader对象,放入BufferedReader的构造方法中。除此之外,System.out和System.err都是直接的PriintStream对象,可直接使用。我们也可以使用java.util包下的Scanner类来代替上述程序:

public class StandardIO {

public static void main(String[] args) throws IOException {

Scanner in = new Scanner(System.in);

String s;

while((s = in.next()) != null && s.length() != 0){

System.out.println(s);

}

}

}

九、性能分析及总结

1、一个文件读写工具类。

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.ArrayList;

import java.util.Arrays;

/**

  • 一个非常实用的文件操作类 . 2012-12-19

  • @author Bruce Eckel , edited by erqing

*/

public class TextFile extends ArrayList<String> {

private static final long serialVersionUID = -1942855619975438512L;

// Read a file as a String

public static String read(String filename) {

StringBuilder sb = new StringBuilder();

try {

BufferedReader in = new BufferedReader(new FileReader(new File(

filename).getAbsoluteFile()));

String s;

try {

while ((s = in.readLine()) != null) {

sb.append(s);

sb.append("\n");

}

} finally {

in.close();

}

} catch (IOException e) {

throw new RuntimeException(e);

}

return sb.toString();

}

// Write a single file in one method call

public static void write(String fileName, String text) {

try {

PrintWriter out = new PrintWriter(

new File(fileName).getAbsoluteFile());

try {

out.print(text);

} finally {

out.close();

}

} catch (IOException e) {

throw new RuntimeException(e);

}

}

// Read a file,spilt by any regular expression

public TextFile(String fileName, String splitter) {

super(Arrays.asList(read(fileName).split(splitter)));

if (get(0).equals(""))

remove(0);

}

// Normally read by lines

public TextFile(String fileName) {

this(fileName, "\n");

}

public void write(String fileName) {

try {

PrintWriter out = new PrintWriter(

new File(fileName).getAbsoluteFile());

try {

for (String item : this)

out.println(item);

} finally {

out.close();

}

} catch (IOException e) {

throw new RuntimeException(e);

}

}

// test,I have generated a file named data.d at the root

public static void main(String[] args) {

/ read() test /

System.out.println(read("data.d")); // testing is OK!

/ write() test /

write("out.d", "helloworld\negg"); // testing is OK!

/ constractor test /

TextFile tf = new TextFile("data.d"); // testing is OK!

}

}

2、读取二进制文件。

import java.io.BufferedInputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

/**

  • to read the binary file

  • @author erqing

*/

public class BinaryFile {

/ the parametre is a file /

public static byte[] read(File file) throws IOException {

BufferedInputStream bf = new BufferedInputStream(new FileInputStream(

file));

try {

byte[] data = new byte[bf.available()];

bf.read(data);

return data;

} finally {

bf.close();

}

}

/ the param is the path of a file /

public static byte[] read(String file) throws IOException {

return read(new File(file).getAbsoluteFile());

}

}

转载于:https://blog.51cto.com/14226273/2366101

### Java IO流的概念及使用方法 JavaIO流通过`java.io`包下的类和接口来支持,主要用于数据的读取和写入操作。IO流可以分为输入流(InputStream)和输出流(OutputStream),并且根据处理的数据单位不同,又可分为字节流和字符流[^1]。 #### 1. IO流的分类 - **字节流**:以字节为单位进行数据处理,适用于所有类型的文件,包括二进制文件。主要类有`FileInputStream`和`FileOutputStream`。 - **字符流**:以字符为单位进行数据处理,仅适用于纯文本文件。主要类有`FileReader`和`FileWriter`[^4]。 此外,JavaIO流还采用了装饰者设计模式,将流分为底层节点流和上层处理流。节点流直接与物理存储节点关联,而处理流则对节点流进行包装,提供额外的功能,如缓冲、过滤等[^1]。 #### 2. 字符流的使用示例 以下是一个使用字符流读取文件内容的示例代码: ```java import java.io.BufferedReader; import java.io.FileReader; public class Demo2 { public static void main(String[] args) { try { BufferedReader br = new BufferedReader(new FileReader("E:\\Test.txt")); String line; while ((line = br.readLine()) != null) { System.out.println(line); } br.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上述代码中,`BufferedReader`被用来提高读取效率,并且通过`readLine()`方法逐行读取文件内容[^2]。 #### 3. 序列化的使用 序列化是Java IO流的一个重要应用,用于将对象转换为字节流以便于存储或传输。为了实现序列化,类必须实现`Serializable`接口。以下是一个对象序列化的示例代码: ```java import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.io.Serializable; class Student implements Serializable { private static final long serialVersionUID = 1L; String name; int age; public Student(String name, int age) { this.name = name; this.age = age; } } public class SerializationDemo { public static void main(String[] args) throws Exception { Student student = new Student("张三", 22); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student")); oos.writeObject(student); oos.flush(); oos.close(); } } ``` 在此示例中,`ObjectOutputStream`被用来将`Student`对象序列化并保存到文件中[^3]。 #### 4. 关闭流的重要性 如果不关闭IO流,可能会导致资源泄漏,影响程序性能甚至引发异常。因此,在完成数据读写后,务必调用`close()`方法释放相关资源[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值