处理输入输出的方式称为流。
Stream(流)的特性是一维的,单方向的。
流的基础类
InputStream
OutputStream
标准输入/出流
字节层面的流传输。
System.out.println("Text")
System.in
Scanner in = new Scanner(System.in);
文件流
字节层面的流传输。
FileOutputStream
FileInputStream
FileOutputStream 示例:
public class File_Stream {
public static void main(String[] args) {
System.out.println("hello world");
byte[] buf = new byte[10];
for (int i=0; i<buf.length;i++){
buf[i] = (byte)i;
}
try {
FileOutputStream out = new FileOutputStream("a.dat");
out.write(buf);
out.close();
}
catch (FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
流过滤器
以介质流对象为基础层构建过滤器流,最终形成的流对象能在数据的输入输出过程中,逐层使用过滤器流的方法来读写数据。
DataInput(Output)Stream 类可以进行基本数据类型的传输。
(字节流)fileInpitStream | bufferedInputStream | DataInputStream | 基本数据类型
下文代码就增加了 buffer 和 data 两个流过滤器。
因为流过滤器需要在文件流的基础上进行再次封装,所以引用文件流程的代码进行修改:
try {
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("b.dat")));
// FileOutputStream out = new FileOutputStream("a.dat");
// out.write(buf);
int i = 0xcafebabe;
out.writeInt(i);
out.close();
}
需要注意的是 DataOutputStream 是将存储在内存中的数据,保存到文件中;并没有转换成自然语言,所以读取也需要通过相应的方式进行 DataInputStream的 封装;
try {
DataOutputStream out = new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream("b.dat")));
// FileOutputStream out = new FileOutputStream("a.dat");
// out.write(buf);
int i = 0xcafebabe;
out.writeInt(i);
out.close();
DataInputStream in = new DataInputStream(
new BufferedInputStream(
new FileInputStream("b.dat")));
int j = in.readInt();
System.out.println(j);
}
文本流
Reader/Writer
reader/Writer 本身是处理 Unicode 字符的。但在使用场景上,因为有多种文本编码格式,所以需要借助流来打开文件,用流过滤器来建立 Reader/Writer 来进行输入和输出。
// Reader/Writer
PrintWriter out_p = new PrintWriter(
new BufferedWriter(
// OutputStreamWriter 构建了 Stream 和 Writer 之间的桥梁
new OutputStreamWriter(
new FileOutputStream("a.txt"))));
int k = 123456;
// 文本流中的 print 表示打印到文件中?
out_p.print(k);
out_p.close();
// 读文件
BufferedReader in_r = new BufferedReader(
new InputStreamReader(
new FileInputStream("src/../a.txt")));
String line;
while ((line=in_r.readLine()) != null){
System.out.println(line);
}
常用 BufferedReader 来读文件, readLine()来获取内容。
LineNumberReader 读文件可以得到行号, getLineNumber()。
FileReader
InputStreamReader 的子类,所有方法都从父类中继承而来。
-
FileReader(File file)
- 在给定从中读取数据的 File 的情况下创建一个新 FileReader
-
FileReader(String fileName)
- 在给定从中读取数据的文件名的情况下创建一个新的 FileReader
FileReader 不能指定编码转换方式。
格式化输入输出
输出
PrintWriter
- format("格式",。。。);
- printf("格式",。。。);
- print(各种基本类型);
- println(各种基本类型);
输入
Scnner
- 在 InputStream 或 Reader 上简历一个 Scanner 对象可以从流中文本解析出以文本表达的各种基本类型
- next...()
流的应用
使用 sicket 活的流数据。
本地调式需在 mac 本地输入命令 nc -l 12345
public class SocketStream {
public static void main(String[] args) {
try {
Socket socket = new Socket(InetAddress.getByName("localhost"),12345);
PrintWriter out = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(
socket.getOutputStream())));
out.println("Hello");
// 若不刷新缓存,服务端不会显示 hello
out.flush();
BufferedReader reader = new BufferedReader(
new InputStreamReader(
socket.getInputStream()));
String line;
while ((line=reader.readLine())!=null) {
System.out.println(line);
}
out.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 因为 read()函数是阻塞的,在督导所需的内容之前会停下来
- 使用read() “高级”的函数,入nextInt()、readLine()都是同样的
- 所以常用单独的线程来做 socket 读的等待,或使用 nio 的channel 选择机制
- 对于socket,可以设置 SO 时间
- setSoTimeout(int timeOut)
对象串行化
对象通过写出描述自己状态的数值来记录自己 ,这个过程叫对象的串行化(Serialization) 。串行化的主要任务是写出对象实例变量的数值。如果变量是另一对象的引用,则引用的对象也要串行化。这个过程是递归的,串行化可能要涉及一个复杂树结构的单行化,包括原有对象、对象的对象、对象的对象的对象等等。对象所有权的层次结构称为图表(graph)。
自己写的类对象写到文件里。
- ObjectInpuStream 类
- readObject()
- ObjectOutputStream 类
- writeObject()
- Serializable 接口
class Student implements Serializable {
private String name;
private int age;
private int grade;
public Student(String name, int age, int grade) {
this.name = name;
this.age = age;
this.grade = grade;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", grade=" + grade +
'}';
}
}
public class ObjectStream {
public static void main(String[] args) {
try {
Student s1 = new Student("John",18,8);
System.out.println(s1);
// obj stream 写到文件
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("obj.dat"));
out.writeObject(s1);
out.close();
// obj stream 读
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("src/../obj.dat"));
Student s2 = (Student) in.readObject();
System.out.println(s2);
in.close();
System.out.println(s1==s2);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
读回来的虽然内容一致,但对象新造的不同对象。