Java I/O
Java的I/O大概可以分成以下几类:
- 磁盘操作:File
- 字节操作:InputStream和OutputStream
- 字符操作:Reader和Writer
- 对象操作:Serializable,ObjectInputStream,ObjectOutputStream
- 网络操作:Socket
- 非阻塞I/O操作:NIO
磁盘操作(File)
File类可以用于表示文件和目录的信息,但是它不表示文件的内容。
简单使用,递归的输出一个目录下所有文件:
/**
* Created by DK_ing on 2019/3/26.
*/
public class FileTest {
public static void listAllFiles(File dir) {
if (dir == null || !dir.exists()) {
return;
}
if (dir.isFile()) {
System.out.println(dir.getName());
return;
}
for (File file : dir.listFiles()) {
listAllFiles(file);
}
}
}
字节操作(*Stream)
使用字节流操作进行文件复制:
public static void copyFile(String src, String dist) {
try {
inputStream = new FileInputStream(src);
outputStream = new FileOutputStream(dist);
byte[] buffer = new byte[20 * 1024];
while (inputStream.read(buffer, 0, buffer.length) != -1) {
outputStream.write(buffer);
}
} catch (Exception e) {
throw new RuntimeException("copy something wrong");
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
throw new RuntimeException("Can not close io", e);
}
}
}
//TODO:此处自行脑补InputStream接口的UML
Java I/O使用了装饰器模式实现,以InputStream为例,InputStream是抽象组件,FileInputStream是InputStream的子类,属于具体组件,提供了字节流的输入操作。FilterInputStream是抽象装饰器,装饰器用于装饰组件,为组件提供额外的功能,例如BufferedInputStream为FileInputStream提供缓存的功能。
实例化一个具有缓存功能的字节流对象时,只需要在FileInputStream对象上再套一层BufferedInputStream对象即可。
FileInputStream fileInputStream = new FileInputStream(filePath);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
DataInputStream装饰器提供了对更多数据类型进行输入的操作,比如int、double等基本类型。
字符操作(*Reader | *Writer)
不管是磁盘还是网络传输,最小的存储单元都是字节,而不是字符。但是在程序中操作的通常是字符形式的数据,因此需要提供对字符进行操作的方法。
- InputStreamReader实现从字节流解码成字符流;
- OutputStreamWriter实现从字符流编码成字节流。
逐行输出文本文件的内容:
public static void readFileContent(String fileName) throws IOException {
BufferedReader bufferedReader = null;
try {
FileReader fileReader = new FileReader(fileName);
bufferedReader = new BufferedReader(fileReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
} catch (Exception e) {
e.printStackTrace();
}
if (bufferedReader != null) {
bufferedReader.close();
}
}
如果编码或者解码过程使用不同的编码方式,那么就会出现乱码。
注:关于序列化问题以及Socket问题,在分布式基础中有讲到这里不作赘述。