JavaIO概述:
JavaIO大体分为两个流:字符流和字节流,其他各种流操作都是对这两个流的装饰或者继承。
字节流的超类:InputStream(输入流)和OutputStream(输出流)
字符流的超类:Reader(输入流)和 Writer(输出流)
要区分输入输出流,就要站在程序的角度看,输入流意思就是向程序里面输入数据,把东西从外部读到程序。
输出流就是将程序里面的东西写到外部的某个载体上,比如写入文件,打印在标准输出(屏幕)上。
区分字符字节流:只要是Writer,Reader结尾的就是字符流,只要是InputStream和OutputStream结尾的都是字节流。
JavaIO中各种流类之间的关系图:
JavaIO流用到了装饰者模式,这也就是为啥会有这样的代码了,
Writer writer = new OutputStreamWriter(new FileOutputStream(FILE));
而且使用的时候都是上转型。使用父类或者父类的父类或者接口来作为对象的引用。
模拟以上代码,自己写一个打印流:
// 打印流
public void TestPrintStream() throws Exception{
class PrintUtil{ // 内部类
private OutputStream out; // 用来接收OutputStream的子类
public PrintUtil(OutputStream out) {
this.out = out;
}
// 下面函数都是对传入的OutputStream的子类进行操作的。
public void print(String str) {
try {
out.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public void println(String str) {
this.print(str + "\r\n");
}
public void print(int i) {
this.print(String.valueOf(i));
}
public void println(int i) {
this.println(String.valueOf(i));
}
}
PrintUtil system = new PrintUtil(new FileOutputStream(FILE));
system.println("换行输出");
system.print(5);
system.print("不换行输出");
}
运行结果:
常见IO流的使用:
字节流(InputStream / OutputStream)字符流 (Reader / Writer)转换流 (OutputStreamWriter / InputStreamReader)文件拷贝(字节流实现)字符编码 (编码解码一致才可以正确显示,使用utf-8)内存操作流 (ByteArrayInputStream / ByteArrayOutputStream)打印流 (PrintStream)标准IO (System.in System.out, System.err)序列化 (ObjectInputStream / ObjectOutputStream)Scanner类
package IO流;
import java.io.*;
import org.junit.Test;
class Person implements Serializable{
private String name;
private int age;
private transient int height; // 被transient关键字修饰的将不会被序列化
public Person() {}
public Person(String name, int age, int height) {
super();
this.name = name;
this.age = age;
this.height = height;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", height=" + height + "]";
}
}
public class OtherIO {
// 操作对象为文件
private static File FILE = new File("C:\\Users\\hasee\\Desktop\\dir\\test.txt");
// 字节输入输出流,处理图片,声音,文件
public void TestInputStreamAndOutputstream() throws Exception{
//输出流,使用true为追加输入
OutputStream os = new FileOutputStream(FILE, true);
os.write("字节流写入文件".getBytes());
os.close();
// 输入流,写在try中为自动关闭,不推荐使用
try(InputStream is = new FileInputStream(FILE)){
byte[] bs = new byte[1024];
int len = is.read(bs);
System.out.println(new String(bs, 0, len));
is.close();
}catch (Exception e) {
e.printStackTrace();
}
}
// 字符输入输出流, 适合处理中文。
public void TestWriterAndReader() throws Exception{
Writer writer = new FileWriter(FILE, true);
writer.write("字符流写入文件");
writer.close();
writer.flush(); // 刷新缓冲区
Reader reader = new FileReader(FILE);
char[] cs = new char[1024];
int len = reader.read(cs);
System.out.println(new String(cs, 0, len));
reader.close();
}
// 转换流,字符字节流的相互转换,啥转啥就是啥啥。。OutputStreamWriter
public void TestConversionFlow() throws Exception{
// 字节转字符
Writer writer = new OutputStreamWriter(new FileOutputStream(FILE));
writer.write("转换流");
writer.close();
// 字符转字节
Reader reader = new InputStreamReader(new FileInputStream(FILE));
char[] cs = new char[1024];
int len = reader.read(cs);
System.out.println(new String(cs, 0, len));
reader.close();
}
// 文件拷贝
public void TestFileCopy() throws Exception{
File src = new File("D:\\testFileCopy\\src.jpg");
File dest = new File("D:\\testFileCopy\\dest.jpg");
// 读取src文件
byte[] buffer = new byte[1024];
InputStream is = new FileInputStream(src);
OutputStream os = new FileOutputStream(dest);
new Thread(()->{
int len = 0;
try {
while((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
is.close();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
// 字符编码
public void TestEncoding() throws Exception {
OutputStream out = new FileOutputStream(FILE);
out.write("Test 这是一个测试字符编码的".getBytes("UTF-8"));
out.close();
}
// 内存操作流
public void TestByteArrayStream() throws Exception {
String str = "hello word";
// 读到程序
InputStream is = new ByteArrayInputStream(str.getBytes());
OutputStream os = new ByteArrayOutputStream();
// 写入内存,不需要缓冲区,因为内存就是缓冲区
int len = 0;
while((len = is.read()) != -1) {
os.write(Character.toUpperCase(len));
}
System.out.println(os);
is.close();
os.close();
}
// 打印流
public void TestPrintStream() throws Exception{
class PrintUtil{
private OutputStream out;
public PrintUtil(OutputStream out) {
this.out = out;
}
public void print(String str) {
try {
out.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public void println(String str) {
this.print(str + "\r\n");
}
public void print(int i) {
this.print(String.valueOf(i));
}
public void println(int i) {
this.println(String.valueOf(i));
}
}
PrintUtil system = new PrintUtil(new FileOutputStream(FILE));
system.println("换行输出");
system.print(5);
system.print("不换行输出");
}
// 标准IO, System类,Scanner类
public void TestStanderdIO() throws Exception{
InputStream is = System.in;
byte[] buffer = new byte[1024];
int len = is.read(buffer);
System.out.println(new String(buffer, 0, len));
}
@Test
// 序列化,内部类注意事项,
// 如果只有内部类实现序列化,而外部封装类没有实现序列化接口,就会在对内部类进行序列化的时候报出异常。
public void TestSerial() throws Exception{
// 将对象序列化写入文件
Person p = new Person("张三", 20, 170);
ObjectOutputStream objectOut = new ObjectOutputStream(new FileOutputStream(FILE));
objectOut.writeObject(p);
objectOut.close();
// 反序列化,从文件中读取对象
ObjectInputStream objectIn = new ObjectInputStream(new FileInputStream(FILE));
Person person = (Person) objectIn.readObject();
System.out.println(person);
}
}
Scanner类:
//以后除了二进制文件拷贝的处理之外,
//那么只要是针对程序的信息输出都是用打印流(PrintStream、PrintWriter),信息输入使用Scanner(读入程序)
@Test
public void TestScanner() {
Scanner scanner = new Scanner(System.in);
// 使用hasnext的时候,默认使用的是\n作为分隔符, 这里使用空格作为分隔符
scanner.useDelimiter(" ");
while(scanner.hasNext()) {
String str = scanner.next();
System.out.println(str);
}
scanner.close();
}
运行结果如下: