IO流的理解。

  • I/O操作目标
    从数据源当中读取数据,以及将数据写入到数据目的地当中,如图:

image.png

  • IO的分类方法
    第一种分法:输入流、输出流
    第二种分法:字节流、字符流
    第三种分法:节点流、处理流

image.png

image.png

数据的流向以程序为参考,数据进来——输入流,数据从程序出去——输出流
输入流:只能从中读取数据,而不能向其写出数据
输出流:只能向其写出数据,而不能从中读取数据

输入流的基类,抽象类:InputStream(输入字节流)和Reader(输入字符流)
分别有一个用于读取文件的输入流:FileInputStream和FileReader  //都是节点流,和指定文件关联

输出流的基类,抽象类:OutputStream和Write
执行输出的类:FileOutputStream和FileWriter

  • 读取文件和写入文件的方法
    字节流的核心类:

image.png
核心类的核心方法:
InputStream:
int read(byte[ ] b , int off , int len)
三个参数:

  • 第一个参数是一个byte类型的数组,read读取的数据放在这个byte类型的数据中
  • 第二个参数是是偏移量offset的缩写,读进去来的数据从第几位开始放:比如读取的是10个字节,int off 是0,意思就是把读取的来的字节,从0开始,一个个放进去;如果int off 是5,则byte数组的第五位开始读
  • 第三个参数是length,意思是read一词读取数据,最多读多少次数据
  • 返回值是这次调用这个方法总共读取了多少个字节的数据,读取的是10,则返回的就是10
  • 一般来讲,int off 是0,int len就是数组的长度
    OutputStream:
    void write(byte[ ] b , int off , int len )
  • 第一个参数是一个byte类型的数组,将需求斜入的文件放在这个数组中
  • 第二个参数是是偏移量offset的缩写,数组中的数据从第几位开始写:比如10个字节,int off 是0,意思就是从0开始写;如果int off 是5,则byte数组的第五位开始写
  • 第三个参数是length,意思是总共最多写入多少字节的数据
  • 一般来讲,int off 是0,int len就是数组的长度
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
输入demo:
//第一步:导入包,因为java io类都在io包中 “*”代表全部导进来的意思
import java.io.*;
class Test{
//声明FileInputStream这个类的引用
FileInputStream fis = null;

//需要try catch 因为读取文件未知,可能发生异常
try{
//生成代表输入流的对象,并传入所需要读取的数据源当前文件夹目录
fis = new FileInputStream("d:/work/src/from.txt")

//new一个数组,因为字节流的传输需要数组
byte [] buffer = new byte[100]; //数组长度设为100

//调用输入对象的read方法,传入数组名,偏移量,长度,读取即可
fis.read(buffer , 0 ,buffer.length);

//把buffer字节数组转化为字符串(不转的话打印出来的是字节码)
String s= new String(buffer); //一个带数组参数的构造函数

//调用trim方法,去掉字符串的首尾空格(中间的空格去不掉)和空字符
s = s.trim();

//遍历数组
for(int i = 0 , i < buffer.length , i++){

System.out.println(buffer[i]);
}
}
catch(Exception e){
System.out.println(e)
}
finally{
try{
//关闭流也可能会出现异常,所以也需要try catch
fis.close;
}
catch(Exception e){
System.out.println(e)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
输出流demo(先要读取到,再写入):
import java.io.*;
class Test{
FileInputStream fis = null;
FileOutputStream fos = null;
try{
fis = new FileInputStream("d:/work/src/from.txt")
fos = new FileOutputStream(d:/work/src/to.txt);
byte[] buffer =new byte[100];

//临时变量 int temp,代表读取字节的长度
int temp = fis.read(buffer , 0 , buffer.length)
fos.write(buffer , 0 , temp);
}
catch(Exception e){
System.out.println(e);
}
finally(Exception e){
System.out.println(e);
}
}
  • 大文件的读写方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
输出流demo(先要读取到,再写入):
//大文件字节太多,需要一次读一部分,先把一部分数据放到数组中,写入,让后再读取一部分,也就是需要循环读写
import java.io.*;
class Test{
FileInputStream fis = null;
FileOutputStream fos = null;
try{
fis = new FileInputStream("d:/work/src/from.txt")
fos = new FileOutputStream(d:/work/src/to.txt);
byte[] buffer =new byte[1024]; //以1024为单位,1k = 1024字节

while(true){ //while循环,布尔值为真,运行一次,读取一次数据,每次读1024个字节
int temp = fis.read(buffer , 0 , buffer.length)
if(temp == -1){ //当长度为-1时,跳出循环(读到文件尾部,就是-1了)
break;
}
fos.write(buffer , 0 , temp); //读一次写一次
}

}
catch(Exception e){
System.out.println(e);
}
finally(Exception e){
fis.close;
fos.close;
System.out.println(e);
}
}
  • 字符流的使用方法
    读写文件时,以字符为基础
    字节输入流:都是reader(父类,抽象类)子类
    经常用的子类:FileReader
    核心方法:int read(char [] c , int off , int len) //返回值整型 int   参数char类型的数组
    字节输出流:都是Writer类(父类,抽象类)的子类
    经常用的子类:FileWriter
    核心方法:void write(char[ ] c , int off ,int len) //返回为空
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import.java.io.*;
public static void main(String args[])
FileReader fr = null;
FileWriter fw = null;
try{
fr = new FileReader("d:/work/src/from.txt");
fw = new FileWriter("d:/work/src/to.txt");

//new一个字符数组
char[] buffer = new char[100];
int temp = fr.read(buffer , 0 , buffer,length);
fw.write(buffer, 0 , temp);
}
catch(Exception e){
System.out.println(e);
}
finally{
try{
fr.close;
fw.close;
}
catch(Exception e){
System.out.println(e)
}
}
}
  • 处理流使用实例
    处理流常用类:
    BufferedReadeer(父类Reader(输入类),字符流),所以这个类是字符输入处理流
    常用方法:
    public String readLind()  //一次性读入一行的数据,返回字符串
    生成BufferedReadeer对象的方法:
    BufferedReadeer in = new BufferedReader(new FileReader(“foo.in”))  //构造函数中,接收的是一个Reader类型的对象,传入源路径
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import.java.io.*;
class Test{
public static void main(String args[]){

//声明这两个类的引用。使用处理流时,都必须要有一个节点流
FileReader fileReadr = null;
BufferedReader bufferedReader = null;

try{

//这两步就是装饰者(Decorator)设计模式
fileReader = new FileReader(d:/work/src/from.txt); //读取源路径

//将FileReader类的对象作为BufferReader类的参数传进来
bufferReader = new BufferReader(fileReader); //用bufferReader()装饰FileReader()

//初始一个字符串为空
String line = null;

//为true则运行
while(true){

//调用BufferReader的readLine()方法(这个方法返回的是字符串),把这个方法获取的字符串赋值给line
line = buffer.readLine();

//如果line为空(读到文件尾部会返回为空),证明已经读完
if(line = null){
break;
}
System.out.println(line)

}
catch(Exception e){
System.out.println(e);
}
}
}
}
  • 装饰者(Decorator)模式

image.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//A公司进门必须说你好,B进门必须穿鞋套
demo:
//worker 接口;
interface Worker{
public void doSomeWork();
}

//水管工继承Worker抽象类,重写工作方法
class Plumber implements Worker{
public void doSomeWork(){
System.out.println("修水管");
}
}
//木匠工继承Worker抽象类,重写工作方法
class Carpenter implements Worker{
public void doSomeWork(){
System.out.println("修门窗");
}
}

class Aworker implements Worker{
private Worker worker;

//构造函数,加1个Work参数
public AWork(Work work){
this.worker = worker;
}
//重写A公司doSomeWork()方法
public void doSomeWork(){
System.out.println("你好");
worker.doSomeWorker; //这个worker 不管是什么工人,只是代表A公司的人
}
}

主函数:
class Test{
public static void main(String args[]){
Plumber plumber = new Plumber();
AWorker aWoker = new Aworker(plumber); //Plumber 继承Worker接口,所以可以向上转型
aWorker.doSomeWork();
}
}
输出:
你好
修水管