File对象
File file = new File("F:\\java\\java_basis\\code\\java_basisprogram");
File file1 = new File("F:\\java\\java_basis\\code\\java_basisprogram\\test01.txt");
//是否是目录
System.out.println(file.isDirectory());
//是否是文件
System.out.println(file.isFile());
System.out.println(file1.isDirectory());
System.out.println(file1.isFile());
//文件字节大小
System.out.println(file1.length());
//是否可执行
System.out.println(file1.canExecute());
//是否可读写
System.out.println(file1.canRead());
System.out.println(file1.canWrite());
//创建文件,删除文件
File file2 = new File("F:\\java\\java_basis\\code\\java_basisprogram\\test02.txt");
file2.createNewFile();
file2.delete();
//创建临时文件
File file3 = File.createTempFile("hjatemp-", ".txt");
//jvm退出时自动删除
file3.deleteOnExit();
System.out.println(file3.getAbsolutePath());
System.out.println(file3.isFile());
//遍历所有的文件和目录名
String[] list = file.list();
for (int i = 0;i<list.length;i++){
System.out.println(list[i]);
}
//遍历所有文件和目录的绝对地址
File[] files = file.listFiles();
for(File file4 : files){
System.out.println(file4);
}
//遍历所有以.txt结尾的文件的绝对路径
File[] files1 = file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".txt");
}
});
System.out.println("-------------------------------------");
for(File file5 : files1){
System.out.println(file5);
}
输出
true
false
false
true
1025
true
true
true
C:\Users\DELL\AppData\Local\Temp\hjatemp-5624244916572313819.txt
true
.idea
java_basisprogram.iml
out
src
test01.txt
F:\java\java_basis\code\java_basisprogram.idea
F:\java\java_basis\code\java_basisprogram\java_basisprogram.iml
F:\java\java_basis\code\java_basisprogram\out
F:\java\java_basis\code\java_basisprogram\src
F:\java\java_basis\code\java_basisprogram\test01.txt
F:\java\java_basis\code\java_basisprogram\test01.txt
InputStream
要特别注意的一点是,InputStream
并不是一个接口,而是一个抽象类,它是所有输入流的超类。这个抽象类定义的一个最重要的方法就是int read()
,签名如下:
public abstract int read() throws IOException;
package com.hja;
import java.io.*;
public class TestIO_InputStream {
public static void main(String[] args) throws IOException {
byte[] data = {72,101,108,108,111,33};
try (ByteArrayInputStream stream = new ByteArrayInputStream(data)) {
int n;
while ( (n = stream.read()) != -1){
System.out.println((char)n);
}
}
// String s;
// try (InputStream input = new FileInputStream("F:\\java\\java_basis\\code\\java_basisprogram\\test01.txt")) {
// int n;
// StringBuilder sb = new StringBuilder();
// while ((n = input.read()) != -1) {
// sb.append((char) n);
// }
// s = sb.toString();
// }
// System.out.println(s);
try (InputStream inputStream = new FileInputStream("F:\\java\\java_basis\\code\\java_basisprogram\\test01.txt")) {
String s1 = readAsString(inputStream);
System.out.println(s1);
}
try(ByteArrayInputStream stream = new ByteArrayInputStream(data)){
String s = readAsString(stream);
System.out.println(s);
}
}
//封装方法
public static String readAsString(InputStream inputStream) throws IOException {
int n;
StringBuilder sb = new StringBuilder();
while ((n=inputStream.read()) != -1){
char c = (char) n;
sb.append(c);
}
return sb.toString();
}
}
OutputStream
和InputStream
类似,OutputStream
也是抽象类,它是所有输出流的超类。这个抽象类定义的一个最重要的方法就是void write(int b)
,签名如下:
public abstract void write(int b) throws IOException;
Filter模式
通过一个“基础”组件再叠加各种“附加”功能组件的模式,称之为Filter模式(或者装饰器模式:Decorator)。它可以让我们通过少量的类来实现各种功能的组合:
┌─────────────┐
│ InputStream │
└─────────────┘
▲ ▲
┌────────────────────┐ │ │ ┌─────────────────┐
│ FileInputStream │─┤ └─│FilterInputStream│
└────────────────────┘ │ └─────────────────┘
┌────────────────────┐ │ ▲ ┌───────────────────┐
│ByteArrayInputStream│─┤ ├─│BufferedInputStream│
└────────────────────┘ │ │ └───────────────────┘
┌────────────────────┐ │ │ ┌───────────────────┐
│ ServletInputStream │─┘ ├─│ DataInputStream │
└────────────────────┘ │ └───────────────────┘
│ ┌───────────────────┐
└─│CheckedInputStream │
└───────────────────┘
序列化
序列化是指把一个Java对象变成二进制内容,本质上就是一个byte[]
数组。
为什么要把Java对象序列化呢?因为序列化后可以把byte[]
保存到文件中,或者把byte[]
通过网络传输到远程,这样,就相当于把Java对象存储到文件或者通过网络传输出去了。
- 可序列化的Java对象必须实现
java.io.Serializable
接口,类似Serializable
这样的空接口被称为“标记接口”(Marker Interface); - 反序列化时不调用构造方法,可设置
serialVersionUID
作为版本号(非必需); - Java的序列化机制仅适用于Java,如果需要与其它语言交换数据,必须使用通用的序列化方法,例如JSON。
//序列化
public static void main(String[] args) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
try (ObjectOutputStream output = new ObjectOutputStream(buffer)) {
// 写入int:
output.writeInt(12345);
// 写入String:
output.writeUTF("Hello");
// 写入Object:
output.writeObject(Double.valueOf(123.456));
}
System.out.println(Arrays.toString(buffer.toByteArray()));
}
//反序列化
try (ObjectInputStream input = new ObjectInputStream(...)) {
int n = input.readInt();
String s = input.readUTF();
Double d = (Double) input.readObject();
}
Reader
Reader
是Java的IO库提供的另一个输入流接口。和InputStream
的区别是,InputStream
是一个字节流,即以byte
为单位读取,而Reader
是一个字符流,即以char
为单位读取:
InputStream | Reader |
---|---|
字节流,以byte 为单位 | 字符流,以char 为单位 |
读取字节(-1,0~255):int read() | 读取字符(-1,0~65535):int read() |
读到字节数组:int read(byte[] b) | 读到字符数组:int read(char[] c) |
FileReader
FileReader
是Reader
的一个子类,它可以打开文件并获取Reader
。
CharArrayReader
CharArrayReader
可以在内存中模拟一个Reader
,它的作用实际上是把一个char[]
数组变成一个Reader
,这和ByteArrayInputStream
非常类似
StringReader
StringReader
可以直接把String
作为数据源,它和CharArrayReader
几乎一样:
try (Reader reader = new StringReader("Hello")) {
}
InputStreamReader
既然Reader
本质上是一个基于InputStream
的byte
到char
的转换器,那么,如果我们已经有一个InputStream
,想把它转换为Reader
,是完全可行的。InputStreamReader
就是这样一个转换器,它可以把任何InputStream
转换为Reader
。示例代码如下:
// 持有InputStream:
InputStream input = new FileInputStream("src/readme.txt");
// 变换为Reader:
Reader reader = new InputStreamReader(input, "UTF-8");
//解决中文乱码问题
try (Reader reader = new InputStreamReader(new FileInputStream("F:\\java\\java_basis\\code\\java_basisprogram\\test03.txt"), "GB2312")) {
int i ;
StringBuilder sb = new StringBuilder();
while ((i = reader.read()) != -1) {
sb.append((char) i);
}
String s = sb.toString();
System.out.println(s);
}
Writer
FileWriter
FileWriter
就是向文件中写入字符流的Writer
。它的使用方法和FileReader
类似:
try (Writer writer = new FileWriter("readme.txt", StandardCharsets.UTF_8)) {
writer.write('H'); // 写入单个字符
writer.write("Hello".toCharArray()); // 写入char[]
writer.write("Hello"); // 写入String
}
CharArrayWriter
CharArrayWriter
可以在内存中创建一个Writer
,它的作用实际上是构造一个缓冲区,可以写入char
,最后得到写入的char[]
数组,这和ByteArrayOutputStream
非常类似:
try (CharArrayWriter writer = new CharArrayWriter()) {
writer.write(65);
writer.write(66);
writer.write(67);
char[] data = writer.toCharArray(); // { 'A', 'B', 'C' }
}
StringWriter
StringWriter
也是一个基于内存的Writer
,它和CharArrayWriter
类似。实际上,StringWriter
在内部维护了一个StringBuffer
,并对外提供了Writer
接口。
OutputStreamWriter
除了CharArrayWriter
和StringWriter
外,普通的Writer实际上是基于OutputStream
构造的,它接收char
,然后在内部自动转换成一个或多个byte
,并写入OutputStream
。因此,OutputStreamWriter
就是一个将任意的OutputStream
转换为Writer
的转换器:
try (Writer writer = new OutputStreamWriter(new FileOutputStream("readme.txt"), "UTF-8")) {
// TODO:
}
package com.hja;
import java.io.*;
import java.nio.charset.StandardCharsets;
public class TestIO_Writer {
public static void main(String[] args) throws IOException {
try (Writer writer = new FileWriter("F:\\java\\java_basis\\code\\java_basisprogram\\TestIO_Writer.txt")) {
writer.write(11);//直接写入int类型失败
writer.write(String.valueOf(11));
writer.write("hja");
writer.write("胡建安");
writer.write("hello".toCharArray());
}
try(Writer writer = new OutputStreamWriter(new FileOutputStream("F:\\java\\java_basis\\code\\java_basisprogram\\TestIO_Writer2.txt"), "GB2312")){
writer.write(12);//直接写入int类型失败
writer.write(String.valueOf(12));
writer.write("hja");
writer.write("胡建安");
writer.write("hello".toCharArray());
}
}
}
PrintStream和PrintWriter
PrintStream
是一种能接收各种数据类型的输出,打印数据时比较方便:
System.out
是标准输出;System.err
是标准错误输出。
PrintWriter
是基于Writer
的输出。