JAVA IO流采用的是装饰器设计模式,通过IO操作可以完成对特定设备进行数据的读写操作,深入理解IO的设计和使用,可以提供程序的性能和简便性,本篇文章将带大家系统地了解JAVA IO技术。
1. 流的分类
1.1 输入流输出流
输入流:只能从中读取数据,
输出流:只能向其写入数据。
1.2 字节流和字符流
字节流和字符流所操作的数据单元不同,字节流操作的数据单元是8位的字节,而字符流操作的数据单元是16位的字符。
字节流的基类是InputStream和OutputStream。
字符流的基类是Reader和Writer。
1.3 节点流和处理流
节点流(低级流):从/向一个特定的IO设备(如键盘、网络)读/写数据。
处理流(高级流):对一个已存在的流进行连接或封装,通过封装后的流进行读/写操作。
处理流的优点:
- 提高性能,增加缓冲的方式提高输入/输出的执行效率。
- 简化操作,通过提供一系列便捷的方法进行一次输入/输出大批量的内容。
- 消除不同节点流的实现差异。采用相同的代码、透明的方式来访问不同的输入/输出设备的数据流。
2. 输入流
抽象基类InputStream和Reader分别是用于处理字节和字符。
Reader类的实现如下:
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
public int read(java.nio.CharBuffer target) throws IOException {
int len = target.remaining();
char[] cbuf = new char[len];
int n = read(cbuf, 0, len);
if (n > 0)
target.put(cbuf, 0, n);
return n;
}
public int read() throws IOException {
char cb[] = new char[1];
if (read(cb, 0, 1) == -1)
return -1;
else
return cb[0];
}
public int read(char cbuf[]) throws IOException {
return read(cbuf, 0, cbuf.length);
}
abstract public int read(char cbuf[], int off, int len) throws IOException;
private static final int maxSkipBufferSize = 8192;
private char skipBuffer[] = null;
public long skip(long n) throws IOException {
if (n < 0L)
throw new IllegalArgumentException("skip value is negative");
int nn = (int) Math.min(n, maxSkipBufferSize);
synchronized (lock) {
if ((skipBuffer == null) || (skipBuffer.length < nn))
skipBuffer = new char[nn];
long r = n;
while (r > 0) {
int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
if (nc == -1)
break;
r -= nc;
}
return n - r;
}
}
public boolean ready() throws IOException {
return false;
}
public boolean markSupported() {
return false;
}
public void mark(int readAheadLimit) throws IOException {
throw new IOException("mark() not supported");
}
public void reset() throws IOException {
throw new IOException("reset() not supported");
}
abstract public void close() throws IOException;
}
InputStream类的实现如下:
public abstract class InputStream implements Closeable {
private static final int MAX_SKIP_BUFFER_SIZE = 2048;
public abstract int read() throws IOException;
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
public long skip(long n) throws IOException {
long remaining = n;
int nr;
if (n <= 0) {
return 0;
}
int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
return n - remaining;
}
public int available() throws IOException {
return 0;
}
public void close() throws IOException {}
public synchronized void mark(int readlimit) {}
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
}
public boolean markSupported() {
return false;
}
}
InputStream和Reader类都有3个方法名相同的同名重载方法read,使用方法除了操作数据类型外,并无二致。
下面分别对这两个抽象类的子类使用编写示例:
通过FileInputStream读取文件并打印
package com.maltose.test;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputStreamTest {
public static void main(String[] args) throws IOException {
try(FileInputStream fileInputStream = new FileInputStream("E:\\document\\news.txt")) {
byte buffer[] = new byte[1024];
int readIndex = -1;
while((readIndex = fileInputStream.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, readIndex));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
通过FileReader读取文件信息
package com.maltose.test;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest {
public static void main(String[] args) {
try(FileReader fileReader = new FileReader("E:\\document\\news.txt")) {
int readIndex = -1;
char buffer[] = new char[100];
while ((readIndex = fileReader.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, readIndex));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
自动关闭资源使用try语句可以保证输入流一定会被关闭。
3. 输出流
抽象基类OutputStream和Writer分别用于处理字节和字符的输出。
FileOutputStream示例:
package com.maltose.test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest {
public static void main(String[] args) {
try(FileInputStream fileInputStream = new FileInputStream("E:\\document\\news.txt");
FileOutputStream fileOutputStream = new FileOutputStream("E:\\document\\news2.txt")) {
byte buffer[] = new byte[1024];
int readIndex = -1;
while ((readIndex = fileInputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, readIndex);
}
} catch (IOException e) {
}
}
}
FileWriter示例:
package com.maltose.test;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest {
public static void main(String[] args) {
try(FileWriter fileWriter = new FileWriter("E:\\document\\news2.txt")) {
fileWriter.write("你好吗?伙计\r\n");
fileWriter.write("我现在很好!!!\r\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
4. 处理流
处理流是高级流,它的构造器的入参不是物理IO设备节点,而是已存在的流。
处理流PrintWriter示例
package com.maltose.test;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class FileWriterTest {
public static void main(String[] args) {
try(FileWriter fileWriter = new FileWriter("E:\\document\\news2.txt");
PrintWriter printWriter = new PrintWriter(fileWriter)) {
printWriter.println("你好吗?伙计");
printWriter.println("我现在很好!!!");
printWriter.println("我现在很好!!!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
处理流PrintStream的示例
package com.maltose.test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
public class FileOutputStreamTest {
public static void main(String[] args) {
try(FileOutputStream fileOutputStream = new FileOutputStream("E:\\document\\news3.txt");
PrintStream ps = new PrintStream(fileOutputStream)) {
ps.println("这是一个字符串,用来测试处理流的");
ps.println("怎么样?感觉不错吧?");
} catch (IOException e) {
e.printStackTrace();
}
}
}
5. JAVA IO体系
分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
访问数组 | ByteArrayInputStream | ByteArrayOutputStream | CharArrayReader | CharArrayWriter |
访问管道 | PipedInputStream | PipedOutputStream | PipedReader | PipedWriter |
访问字符串 | StringReader | StringWriter | ||
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream | 1 | |
打印流 | PrintStream | PrintWriter |
如果输入/输出的内容是文本内容,则应该考虑使用字符流;如果进行输入/输出的内容是二进制内容,则应该考虑使用字节流。
网友评论