1. 软件系统的I/O
输入:系统接收的信号或数据
输出:系统发出的信号或数据
2.Java I/O APIs
例一:txt的读写
FileReader inputStream = null;
FileWriter outputStream = null;
try {
inputStream = new FileReader(“in.txt");
outputStream = new FileWriter("output.txt");
int c;
while ((c = inputStream.read()) != -1)
outputStream.write(c);
} finally {
if (inputStream != null)
inputStream.close();
if (outputStream != null)
outputStream.close();
}
例二:bin文件的读写
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream(“in.bin");
out = new FileOutputStream(“output.bin");
int c;
while ((c = in.read()) != -1)
out.write(c);
} finally {
if (in != null)
in.close();
if (out != null)
out.close();
}
3.Java nio APIs
I/O读写性能在很多场合下是系统的性能瓶颈
IO | NIO |
---|---|
Stream oriented | Buffer oriented |
Blocking IO | Non blocking IO |
Selectors |
Stream Oriented vs. Buffer Oriented
面向流的Java IO:从一个流中一次读一个或几个字节,对读到的字节做什么操作取决于你。读到的东西没有在任何地方被缓存。不能在流中前后移动。
面向缓冲器的Java NIO:数据被读到一个缓冲器中,之后被处理。可以在缓冲器中前后移动,这使得处理数据更加自由。
Blocking vs. Non-blocking IO
Java IO 的几个流都是blocking的:当线程调用read()或write()时,该线程被阻塞,直到有要读取的数据,或者数据被完全写入。 在此期间,该线程无法执行任何其他操作。
Java NIO的non-blocking模式允许线程请求从channel读取数据,并且要么只获取当前可用的内容,要么获取不到数据,如果当前没有数据可用,线程可以做其他的事情,而不是在数据可供读取之前保持阻塞状态。
线程在IO请求没有被阻塞时做的事情通常是在其他通道上执行IO。也就是说,单个线程现在可以管理多个输入和输出通道。
Selectors
Java NIO的selectors允许单个线程监视多个输入通道。
您可以使用selectors注册多个通道,然后使用单个线程“选择”具有可用于处理的输入的通道,或者选择准备写入的通道。
selector机制使单个线程管理多个通道更为简单
Buffer
缓冲区是物理内存的一部分区域,当数据从一个位置移动到另一个位置时,用来临时存储数据。
缓冲区可能在硬件中一块固定的内存位置,软件中的虚拟数据缓冲区指向物理内存中的一个位置。
所有情况中,数据缓冲区中的数据都被存储在物理存储介质中。
大多数缓冲区都是用软件实现的,由于软件通常使用更快的RAM来存储临时数据,与硬盘驱动器相比,访问时间要快得多。
缓冲区的应用场合:
数据的接收率和被加工率有区别,且这些比率是变量时。
使用BufferedReader读文件
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
try {
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
String everything = sb.toString();
} finally {
br.close();
}
NIO中的buffers:
一个Buffer对象是包含了固定数量数据的容器,
它的行为像一个byte[]数组,但被封装为内部存储可以是一块系统内存的形式。
ByteBuffer类:
代表一个存储原始字节的,长度固定的向量。
六类操作:
- 绝对/相对get和put方法,读取和写入单个字节;
- 相对批量get方法,将连续的字节序列从此缓冲区转移到数组中
- 相对批量put方法,用于将字节序列或其他字节缓冲区中的连续字节序列传输到此缓冲区中;
- 绝对和相对的get和put方法,用于读取和写入其他基本类型的值,以特定字节顺序将它们转换为字节序列;
- 创建 viewbuffers 的方法,允许将字节缓冲区视为包含某些其他基本类型值的缓冲区;
- 压缩,复制和切片字节缓冲区的方法。
Channel
NIO buffer对象可以直接从channel中读写。
打开Channel:
Socket channel类有静态工厂方法open()
SocketChannel sc = SocketChannel.open() ;
Sc.connect(new InetSocketAddress(hostname, portnumber))
File channels不能直接创建,首先使用传统的Java I/O机制创建FileInputStream, FileOutputStream或RandomAccessFile,然后应用 getChannel()方法取得相关联的NIO channel
RandomAccessFile raf = new RandomAccessFile(filename, “r”) ;
FileChannel fc = raf.getChannel() ;
所有继承自ByteChannel接口的channel都提供 read()和write()方法
4.从io到nio:更好的I/O性能
4.1 Stream
/**
* Reads all lines from a text file and prints them.
* Uses Java 1.0-era (circa 1996) Streams to read the file.
*/
public class StreamCat {
public static void main(String[] args) throws IOException {
DataInputStream dis = new DataInputStream( new FileInputStream(args[0]));
// Don't do this! DataInputStream.readLine is DEPRECATED!
String line;
while ((line = dis.readLine()) != null)
System.out.println(line);
}
}
4.2 Reader
/**
* Reads all lines from a text file and prints them.
* Uses Java 1.1-era (circa 1997) Streams to read the file.
*/
public class ReaderCat {
public static void main(String[] args) throws IOException {
try (BufferedReader rd = new BufferedReader( new FileReader(args[0]))) {
String line;
while ((line = rd.readLine()) != null) {
System.out.println(line);
// you could also wrap System.out in a PrintWriter
}
}
}
}
4.3 NIO
/**
* Reads all lines from a text file and prints them.
* Uses nio FileChannel and ByteBuffer.
*/
public class NioCat {
public static void main(String[] args) throws IOException {
ByteBuffer buf = ByteBuffer.allocate(512);
try (FileChannel ch = FileChannel.open(Paths.get(args[0]), StandardOpenOption.READ)) {
int n;
while ((n = ch.read(buf)) > -1) {
System.out.print(new String(buf.array(), 0, n));
buf.clear();
}
}
}
}
4.4 Scanner
/**
* Reads all lines from a text file and prints them
* Uses Java 5 scanner.
*/
public class ScannerCat {
public static void main(String[] args) throws IOException {
try (Scanner s = new Scanner(new File(args[0]))) {
while (s.hasNextLine())
System.out.println(s.nextLine());
}
}
}
4.5 Lines
/**
* Reads all lines from a text file and prints them. Uses Files,
* Java 8-era Stream API (not IO Streams!) and method references.
*/
public class LinesCat {
public static void main(String[] args) throws IOException {
Files.lines(Paths.get(args[0])).forEach(System.out::println);
}
}