JavaSE IO原理及流的引入(下)
3 转换流
转换流提供了在字节流和字符流之间的转换
Java API提供了两个转换流:
InputStreamReader和OutputStreamWriter
字节流中的数据都是字符时,转成字符流操作更高效。
构造方法:(需要和InputStream/OutStream”套接“)
InputStreamReader(FileInputStream in, String charsetName);
以下案例展示输入/输出转换流的使用:
package com.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
/**
* 转换流可以把字节流转换为字符流
* 当字节流中的数据都是字符时,使用转换流转换为字符流处理效率更高!
*/
public class Test7 {
public static void main(String[] args) throws Exception{
//所有文件都有编码格式
//对我们来说,txt和Java文件一般来讲有三种编码
//ISO8859-1,西欧编码,是纯粹的英文编码,不适应汉字
//GBK和UTF-8,这两种编码是适用于中文和英文
//我们一般使用UTF-8
testInputStreamReader();
testOutputStreamWriter();
}
/**
* 转换输入流
* InputStreamReader
*/
public static void testInputStreamReader() throws Exception{
FileInputStream in = new FileInputStream("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/ddd.txt");
//把字节流转换为字符流
InputStreamReader is = new InputStreamReader(in,"UTF-8");
char[] c = new char[100];
int len = 0;
while ((len = is.read(c))!=-1){
System.out.println(new String(c,0,len));
}
is.close();
in.close();
}
/**
* 转换输出流
* @throws Exception
*/
public static void testOutputStreamWriter() throws Exception{
FileOutputStream out = new FileOutputStream("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/ddd.txt");
OutputStreamWriter os = new OutputStreamWriter(out,"UTF-8");
os.write("你好!");
os.flush();
os.close();
out.close();
}
}
注:用法和文件流类似,但是转换流注明了编码,编码一定要正确,否则会乱码录入/输出。
4 标准输入/输出流
System.in
和System.out
分别代表了系统标准的输入和输出设备。
默认输入设备时键盘,输出设备是显示器。
4.1 标准输入/输出流案例展示:
package com.io;
import java.io.BufferedReader;
import java.io.InputStreamReader;
/**
* 标准输入/输出流
*/
public class Demo04 {
public static void main(String[] args) throws Exception{
testSystemIn();
}
/**
* 标准的输入流
* @throws Exception
*/
public static void testSystemIn() throws Exception{
//创建一个接受键盘输入数据的输入流
InputStreamReader is = new InputStreamReader(System.in);
//把输入流放到缓冲流里
BufferedReader br = new BufferedReader(is);
String str = "";//定义一个临时接受数据的字符串
while ((str = br.readLine()) != null){
System.out.println(str);
}
br.close();
is.close();
}
}
/*运行结果:
输入: 你好
输出: 你好
*/
4.2 练习:把控制台输入内容写到指定txt文件中,接受到over时,结束。
话不多说,直接看代码~
package com.io;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStreamReader;
public class Demo05 {
public static void main(String[] args) throws Exception{
write2TXT();
}
/**
* 把控制台输入内容写入指定txt文件中,接收到over时,程序结束
*/
public static void write2TXT() throws Exception{
//创建一个接受键盘输入数据的输入流
InputStreamReader is = new InputStreamReader(System.in);
//把输入流放到缓冲流中
BufferedReader br = new BufferedReader(is);
//定义输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/eee.txt"));
String line = "";
while ((line = br.readLine())!=null){
//读取到的每一行都写入txt文件中
if (line.equals("over")){
break;
}
bw.write(line);
}
bw.flush();
bw.close();
br.close();
is.close();
}
}
运行结果:
控制台输入:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cTFmuphm-1583830111781)(/Users/demut/Desktop/截图/Java Targetu/JavaDay13/控制台输入.png)]
文件中显示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8ZinuceE-1583830111782)(/Users/demut/Desktop/截图/Java Targetu/JavaDay13/文件中显示.png)]
5 打印流(了解)
在整个IO包中,打印流是输出信息最方便的类。
PrintStream(字节打印流)和PrintWriter(字符打印流)提供了一系列重载的print和println方法,用于多种数据类型的输出。
-
PrintStream和PrintWriter的输出不会抛出异常
-
PrintStream和PrintWriter又自动flush功能
-
System.out返回的是PrintStream的实例
6 数据流(了解)
为了方便地操作Java语言的基本数据类型的数据,可以使用数据流。
数据流有两个类:(用于读取和写出基本类型的数据)
DataInputStream
和DataOutputStream
分别套接在InputStream
和OutputStream
节点流上
案例展示:
package com.io;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
* 数据流,专门用来做基本数据类型的读写
*/
public class Test8 {
public static void main(String[] args) throws Exception{
testDataOutputStream();
testDataInputStream();
}
/**
* 数据输出流
* 用数据输出流写到文件中的基本数据类型数据均为乱码,不能直接辨认
* -->需要数据输入流来读取!
* @throws Exception
*/
public static void testDataOutputStream() throws Exception{
DataOutputStream out = new DataOutputStream(new FileOutputStream("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/fff.txt"));
out.writeBoolean(true); //乱码
out.writeDouble(1.222d); //乱码
out.writeInt(100); //乱码
out.flush();
out.close();
}
/**
* 数据输入流
* 用数据输入流来读取数据输出流写到文件中的数据时,要保证使用和当时写数据时的数据类型一致来读取。
* 例:写时writeDouble,读时readDouble
* @throws Exception
*/
public static void testDataInputStream() throws Exception{
DataInputStream in = new DataInputStream(new FileInputStream("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/fff.txt"));
System.out.println(in.readDouble()); //只有读double时是正常的
in.close();
}
}
7 对象流
ObjectInputStream
和ObjectOutputStream
==用于存储和读取对象的处理流。==它的强大之处在于可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
例如:将person对象存入硬盘:
1. 硬盘存储的基础是什么?二进制。那就需要把对象转化为二进制的字节流,把这个流保存到电脑上。
2. 把这个对象通过网络传到另一台机器上,网络的通信基础是什么?二进制。则需把对象转化为二进制的数据流,把这个流通过网络进行传输,接受者要使用该对象,则将流转化为对象。
正是因为保存对象到硬盘(对象的持久化)和对象的网络传输,需要做这两件事,就产生了对象的输入/输出流。
序列化:用ObjectOutputStream类将一个Java对象写入IO流中。
反序列化:用ObjectInputStream类从IO流中恢复该Java对象。
ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量。
– 对象的序列化与反序列化
为了让某个类可序列化,该类必须实现以下两个接口之一:Serializable
、Externalizable
若某个类实现了Serializable接口,该类的对象就是可序列化的。
序列化:
- 创建一个ObjectOutputStream
- 调用ObjectOutputStream对象的writeObject(对象)方法输出可序列化对象。注意写出一次,操作flush()
反序列化:
- 创建一个ObjectInputSteam
- 调用readObject()方法读取流中的对象
强调:如果某个类的字段不是基本数据类型或String类型,而是另一个引用类型,那么这个引用类型必须是可序列化的,否则拥有该类型的Field的类也不能序列化。
案例展示:
package com.io;
import java.io.Serializable;
/**
* 可以序列化与反序列化的对象
*/
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
}
package com.io;
import java.io.*;
/**
* 系列化与反序列化
* 注意: 对象的序列化与反序列化使用的类要严格一致,包名,类名,类机构等所有都要一致
*/
public class Test9 {
public static void main(String[] args) throws Exception{
testSerialize();
testDeserialize();
}
/**
* 对象的序列化
*/
public static void testSerialize() throws Exception{
//定义对象输出流,把对象的序列化之后的流放到指定文件中
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/ggg.txt"));
Person p = new Person();
p.name = "张三";
p.age = 11;
out.writeObject(p);
out.flush();
out.close();
}
/**
* 对象的反序列化
*/
public static void testDeserialize() throws Exception{
//创建对象输入流对象,从指定的文件中把对象序列化后的流读取出来
ObjectInputStream in = new ObjectInputStream(new FileInputStream("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/ggg.txt"));
Object obj = in.readObject();
Person p = (Person)obj;
System.out.println(p.name);
System.out.println(p.age);
in.close();
}
}
/*运行结果:
张三
11
*/
再次强调: 对象的序列化与反序列化使用的类要严格一致,包名,类名,类机构等所有都要一致。
8 随机存取流
RandomAccessFile类支持==“随机访问”==的方式,程序可以直接跳到文件的任意地方来读、写文件。
RandomAccessFile类对象包含一个记录指针,用以标示当前读写处的位置。
RandomAccessFile类对象可以自由移动记录指针:
-
- long getFilePointer():获取文件记录指针的当前位置
- void seek(long pos):将文件记录指针定位到pos位置
RandomAccessFile类
- 构造器:
public RandomAccessFile(File file, String mode)
public RandomAccessFile(String name, String mode)
- 创建RandomAccessFile类实例需要指定一个mode参数,该参数指定RandomAccessFile的访问模式:
- r: 以只读方式打开
- rw:打开以便读取和写入
- rwd:打开以便读取和写入:同步文件内容的更新
- rws:打开以便读取和写入:同步文件内容和元数据的更新
案例展示:
package com.io;
import java.io.RandomAccessFile;
/**
* 文件的随机读写
* 程序可以直接跳到文件的任意地方来读、写文件
*/
public class Test10 {
public static void main(String[] args) throws Exception{
testRandomAccessFileRead();
testRandomAccessFileWrite();
}
/**
* 随机读文件
*/
public static void testRandomAccessFileRead() throws Exception{
//RandomAccessFile的构造有两个参数:
// 参数1是读写文件的路径
// 参数2是指定的访问模式
RandomAccessFile ra = new RandomAccessFile("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/hhh.txt", "r");
ra.seek(0);//设置读取文件内容的起始点--> 随机读取的来源,可通过设置的起始点,从文件的任意位置读取
byte[] b = new byte[1024];
int len = 0;
while ((len = ra.read(b))!=-1){
System.out.println(new String(b,0,len));
}
ra.close();
}
/**
* 随机写入文件
*/
public static void testRandomAccessFileWrite()throws Exception{
RandomAccessFile ra = new RandomAccessFile("/Users/demut/JAVASE Project/JavaSE/基础语法/src/com/io/hhh.txt","rw");
// ra.seek(0);//设置写的起始点,0代表从开头写
//注意:若从文件开头或者中间的某个位置开始写,就会用所写内容覆盖掉等长的原有内容
ra.seek(ra.length());//设置写的起始点,代表从文件的最后结尾写-->文件的追加
ra.write("你好".getBytes());
ra.close();
}
}
注:注意seek()的用法。
流的基本应用小结
-
流是用来处理数据的。
-
处理数据时,一定要明确数据源!
- 数据源可以是文件,也可以是键盘
- 数据目的地可以是文件、显示器或其他设备
-
流只是帮助数据进行传输,并对传输的数据进行处理,比如过滤处理、转换处理等。
-
字节流-缓冲流(重点)
- 输入流InputStream–FileInputStream–BufferedInputStream
- 输出流OutputStream–FileOutputStream–BufferedOutputStream
-
字符流-缓冲流(重点)
- 输入流Reader–FileReader–BufferedReader
- 输出流Writer–FileWriter–BufferedWriter
-
转换流
- InputStreamReader和OutputStreamWriter
-
对象流
- ObjectInputStream和ObjectOutputStream(难点)
- 序列化
- 反序列化
-
随机存取流RandomAccessFile(掌握读取、写入)