0803(023天 输入输出流03 节点流+过滤流)

本文详细介绍了Java中的输入输出流,包括节点流(文件节点流、内存流)和过滤流的使用,如FileInputStream、FileOutputStream、BufferedReader、BufferedWriter等。此外,还讨论了如何处理中文乱码问题以及数据流和打印流的运用。
摘要由CSDN通过智能技术生成

0803(023天 输入输出流03 节点流+过滤流)

每日一狗(田园犬西瓜瓜

在这里插入图片描述

复习:

应用场景

  • 字节流:针对二进制位文件 (音频,视频)
  • 字符流:针对文本文件(txt文件。。。)

节点流

课前小练习(文件的词频统计)

package com.yang1;

import java.io.FileReader;
import java.io.Reader;

public class 课前小练习 {

	public static void main(String[] args) {
		myRead();
	}

	// 读取并进行词频统计
	public static void myRead() {
		ArrayList myArr = new ArrayList(40);
		try (Reader in = new FileReader("G:\\蓝鸥\\0704(000天 )\\笔记\\课堂笔记.md")) {
			int tmp = 0;
			while ((tmp = in.read()) > 0) {
				if (tmp == '\n' || tmp == '\r' || tmp == '\t') {
					tmp = ' ';
				}

				myArr.add((char) tmp);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		myArr.sorted();
		myArr.show();
	}
}

class MyChar {
	private char myChar;
	private int count;

	public MyChar(char myChar) {
		this.myChar = myChar;
		this.count = 1;
	}

	// 频次加一
	public void plusOne() {
		count++;
	}

	@Override
	public String toString() {
		return myChar + "(" + count + ")";
	}
	/

	public char getMyChar() {
		return myChar;
	}

	public int getCount() {
		return count;
	}
}

class ArrayList {
	private MyChar[] arr;
	private int len;

	public ArrayList() {
		this(10);
	}

	public ArrayList(int lenght) {
		arr = new MyChar[lenght];
		len = 0;
	}

	// 按照出现频率进行排序
	public void sorted() {
		for (int i = 1; i < len; i++) {
			for (int j = 0; j < len - i; j++) {
				if (big(j, j + 1)) {
					MyChar tmp = arr[j];
					arr[j] = arr[j + 1];
					arr[j + 1] = tmp;
				}

			}
		}
	}

	// 判定是否需要交换
	public boolean big(int i, int j) {
		boolean res = false;
		if (arr[i].getCount() < arr[j].getCount()) {
			res = true;
		} else if (arr[i].getCount() == arr[j].getCount()) {
			res = arr[i].getMyChar() > arr[j].getMyChar();
		}
		return res;
	}

	// 展示词频统计结果
	public void show() {
		for (int i = 0; i < len; i++) {
			System.out.print(arr[i]);
		}
	}

	// 传入一个字符,实现词频追加统计
	public void add(char c) {
		MyChar myChar = select(c);
		if (myChar != null) {
			myChar.plusOne();
		} else {
			if (len == arr.length) {
				swell();
			}
			arr[len] = new MyChar(c);
			len++;
		}
	}

	// 数组扩容
	public void swell() {
		MyChar[] newArr = new MyChar[len * 3 / 2];
		for (int i = 0; i < len; i++) {
			newArr[i] = arr[i];
		}
		arr = newArr;
	}

	// 字符查询
	public MyChar select(char c) {
		MyChar res = null;
		for (int i = 0; i < len; i++) {
			if (arr[i].getMyChar() == c) {
				res = arr[i];
				break;
			}
		}
		return res;
	}
}

节点流的分类

类型字符流字节流
File文件FileReader、FileWriterFileInputStream、FileOutputStream
内存数组CharArrayReader、 CharArrayWriterByteArrayInputStream、 ByteArrayOutputStream
内存字串StringReader、 StringWriter
管道PipedReader、 PipedWriterPipedInputStream、 PipedOutputStream

1. 文件节点流

FileInputStream和FileOutputStream是文件字节流,是一种节点流

1.1 构造方法

输入流

  • FileInputStream(“文件名称”),如果文件不存在则报错FileNotFoundException

  • FileInputStream(File)

输出流

  • FileOutputStream(“文件名称”) 如果文件不存在则新建文件,如果文件存在则覆盖文件内容
  • FileOutputStream(String name文件名称, boolean append是否采用追加方式)

1.2 基本方法

输入read

  • read():读取并返回整形数据
  • read(byte[]):将数据读取之字节数组中,返回值为int,有用数据的最后索引

输出write

  • write(int):将(char)int 写入到输出流中
  • write(byte[]):将字节数组中的数据写入到输出流中

2. 内存流

2.1 可变长数组

用于适配不同已经封装好的方法中参数的类型;

这个工具方法要的是输入流,另一个工具方法又要的是输出流(方法内部无法重写)

可以用一个内存输入流先充当这个输入流,在获取到这个输入流的字节数组,在把他封装到一个输出流,传入到另一个工具方法中使用。

使用中间流来进行数据格式的转换

CharArrayReader(char[] buf);
CharArrayRead(char[] buf, int offset, int length);

CharArrayWriter用于实现向一个字符数组中写入数据,这个数组可以自动调整大小

ByteArrayInputStream、ByteArrayOutputStream和CharArrayReader以及CharArrayWriter类似,支 持操作的内容不同而已,操作byte[]与char[]

案例:读取输入字符流,将其转存至变长数组中,在变长数组末尾追加指定字符串,将其转换为输出流,在终端输出输出流存储的数据

public class Test2 {
	public static void main(String[] args) throws Exception {
		String str="abc中国人民解放军123";
		char[] arr=str.toCharArray();
		Reader r=new CharArrayReader(arr);
		while(true) {
			int kk=r.read();
			if(kk==-1)
				break;
			System.out.println((char)kk);
		}
		System.out.println("键盘录入数据");
		Scanner sc=new Scanner(System.in);
		Writer w=new CharArrayWriter();
		while(true) {
			String ss=sc.nextLine();
			if("quit".equals(ss)) break;
			w.write(ss);
		}
		//需要使用CharArrayWriter中定义的特殊方法,获取输出的目标数组
		if(w instanceof CharArrayWriter) {
			CharArrayWriter caw=(CharArrayWriter)w;
			caw.append("asdfasd");//向输出的数组末尾添加内容  StringBuilder
			//获取输出的目标数组
			char[] target=caw.toCharArray();
			System.out.println(new String(target));
		}
	}
}

2.2 内存字符串流(来源和去处都是字符串)

  • StringReader(可读)
    • in.read():int 获取一个整型值(字符)
  • StringWriter(可写)
    • out.write(int):将整型值代表的字符写入调用者中
    • out.getBuffer():StringBuffer,返回当前对象中所存储的字符串
package com.yang4;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;

public class T01 {
/**
中
华
家
t
e
s 
t
abcdefghijklmnopqrstuvwxyz{
 */
	public static void main(String[] args) throws IOException {
		String ss = "中华家test";
		Reader in = new StringReader(ss);
		while (true) {
			int i = in.read();
			if (i == -1) {
				break;
			}
			System.out.println((char) i);
		}
		Writer out = new StringWriter();
		for (int i = 0; i < 27; i++) {
			out.write('a' + i);
		}
		if (out instanceof StringWriter) {
			StringWriter sw = (StringWriter) out;
			StringBuffer sb = sw.getBuffer();
			System.out.println(sb);
		}
	}

}

2.3 缓冲区

部分文件需要进行临时存储,但是文件级别的转存,是要经过硬盘的,也就是外存,效率较低;

这时可以使用内存流来维护缓冲区,这就可以大大的提升数据处理的效率


过滤流类型

过滤流就是在节点流的基础上附加功能,这边使用的就是装饰模式来进行实现。

装饰模式的4个角色:通用接口、被装饰对象、抽象装饰、装饰器

处理类型字符流字节流
缓存BufferedReader、BufferedWriterBufferedInputStream、 BufferedOutputStream
过滤处理FilterReader、FilterWriterFilterInputStream、 FilterOutputStream
桥接处理InputStreamReader、 OutputStreamWriter
对象序列化 处理ObjectInputStream、 ObjectOutputStream
数据转换DataInputStream、 DataOutputStream
行数统计LineNumberReaderLineNumberInputStream
回滚处理PushbackReaderPushbackInputStream
打印功能PrintWriterPrintWriter

1. 过滤流的实现

就是decorate模式中的抽象装饰角色

FilterInputStream/FilterOutputStream和FilterReader/FilterWriter

2.1 装饰模式复习

4个角色:通用接口、被装饰对象、抽象装饰、装饰器

public class FilterInputStream extends InputStream { 
    //典型的装饰模式
    protected volatile InputStream in; //被装饰目标
     //通过构造器组装被装饰对象
    protected FilterInputStream(InputStream in) { 
       
        this.in = in;
    }
    //调用Filter中的read方法时实际操作是由被装饰对象实现的
    public int read() throws IOException {
    	return in.read();
    }
}

所谓的过滤流实际上就是类似上面的加密处理,在输入之后(后置处理,被装饰对象先执行)或者输出 之前(前置处理,先处理然后被装饰对象执行)进行一下额外的处理,最终实际操作是调用被装饰对象 的方法完成工作,依靠这种装饰模式实现在节点流的基础上附加额外功能.当然也允许多个过滤流嵌套从 而达到功能累加的目的

FilterInputStream实际上就是一个装饰抽象角色

2.2 案例:自定义流实现循环13加密:

读取数据不变:FileReader—BufferedReader

写出数据自定义过滤流SecurityWriter(FilterWriter)

package com.yang4;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;

public class T02 {

	public static void main(String[] args) throws FileNotFoundException, IOException {
		try (SecurityWriter in = new SecurityWriter(new FileReader("data/Test01.java"))) {
			while (true) {
				int i = in.read();
				if (i < 0) {
					break;
				}
				System.out.print((char) i);
			}
		}

	}

}

class SecurityWriter extends FilterReader {

	public SecurityWriter(Reader in) {
		super(in);
	}

	public int read() throws IOException {
		int k = super.read();
		if (k >= 'A' && k <= 'Z') {
			k = (k - 'A' + 13) % 26 + 'A';
		} else if (k >= 'a' && k <= 'z') {
			k = (k - 'a' + 13) % 26 + 'a';
		}
		return k;
	}
}

2. 读取中文处理乱码

2.1 FileReader

使用字符流进行操作

2.2 new String(btye[])

读取字节流,使用String给的方法进行字符拼接

package com.lianxiti;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class Test03 {

	public static void main(String[] args) throws FileNotFoundException, IOException {
		try (InputStream in = new FileInputStream("data/output.txt")) {
			byte[] arr = new byte[1024];
			int len = in.read(arr);
			System.out.println(new String(arr, 0, len)); // 种花家
		}
	}

}

2.3 桥接流

InputStreamReader和OutputStreamWriter是java.io包中用于处理字符流的最基本的类,

用来在字节流和字符流之间作为中介:从字节输入流读入字节,并按编码规范转换为字符;往字节输出流写字符时先将字符按编码规范转换为字节。使用这两者进行字符处理时,在构造方法中应指定一定的平台规范,以便把以字节方式表示的流转换为特定平台上的字符表示。转换流可以在构造时指定其编码字符集

InputStreamReader用于将一个InputStream类型的输入流自动转换为Reader字符流

OutputStreamWriter用于将一个Writer字符输出流转换为OutputStream字节输出流

package com.yang4;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;

public class T03 {

	public static void main(String[] args) throws Exception {
		// 桥接流
		// 输入字节流 转 输入字符流
		InputStream in = new FileInputStream("data/Test01.java");
		Reader r = new InputStreamReader(in);
		while (true) {
			int k = r.read();
			if (k == -1) {
				break;
			}
			System.out.print((char) k);
		}
		// 输出字节流 转 输出字符流
		OutputStream out = new FileOutputStream("data/output.txt");
		Writer w = new OutputStreamWriter(out);
		w.write("种花家");
		w.flush();
		w.close();
	}

}

3. 缓冲流

只要能想办法减少对硬盘的操作,就一定可以提高执行效率

3.1 缓冲流

缓冲流是套接在响应的节点流之上,对续写的数据提供缓冲的功能,提高读写的效率,同时增加了一些新方法

以介质是硬盘为例,字节流和字符流的弊端:在每一次读写的时候,都会访问硬盘。

如果读写的频率比较高的时候,其性能表现不佳。为了解决以上弊端,采用缓存流。

缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。

3.2 构造方法

缓冲字符流

  • BufferedReader(Reader)不定义缓存大小,默认8192
  • BufferedReader(Reader in, int size)size为自定义缓冲区的大小
  • BufferedWriter(Writer)
  • BufferedWriter(Writer out, int size)size为自定义缓冲区的大小

缓冲字节流

  • BufferedInputStream(InputStream)
  • BufferedInputStream(InputStream in, int size)size为自定义缓冲区的大小
  • BufferedOutputStream(OutputStream)
  • BufferedOutputStream(OuputStream out, int size)size为自定义缓冲区的大小

3.2 缓冲输入流

对数据流进行整行读取

readLine():String 获取输入流的单行数据,会吃掉行未的换行符

键盘录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int age = 0;
while (true) {
    String ss = br.readLine();
    try {
        age = Integer.parseInt(ss);
        if (age < 18 || age > 150) {
            System.out.println("您输入的年龄不合法");
        } else {
            break;
        }
    } catch (Exception e) {
        System.out.println("您输入了非法字符");
    }

}
System.out.println("年龄为" + age);
为文本文件打上行标签
package com.yang4;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class T05 {
/*
 * 为文本文件打上行标签
 */
	public static void main(String[] args) throws FileNotFoundException, IOException {
		try (BufferedReader rb = new BufferedReader(new FileReader("data/Test01.java"));
				BufferedWriter bw = new BufferedWriter(new FileWriter("data/output01.txt"))) {
			int hang = 0;
			while (true) {
				String ss = rb.readLine();
				if (ss == null) {
					break;
				}
				bw.write((++hang + "\t"));
				bw.write(ss);
				bw.newLine();

			}
		}
	}

}

4. 数据流

只有字节流,没有对应的字符流

DataInputStream和DataOutputStream两个类创建的对象分别被称为数据输入流和数据输出流。所以比较适合于网络上的数据传 输。这两个流也是过滤器流,常以其它流如InputStream或OutputStream作为它们的输入或输出 DataInputStram和DataOutputStream分别继承自InputStream和OuputStream,属于过滤流,需要分别套接在InputStream和OutputStream类型的节点流上

DataInputStream和DataOutputStream提供了可以存取与机器无关的Java原始类型数据的方法

4.1 一些方法

数据存取方法

  • 有各种针对java中的基本数据类型的读写操纵

构造方法

  • DataInputStream(InputStream)
  • DataOutputStream(OutputStream)

size():int 获取当前操作的位置

4.2 操作字符串

就用这俩,其他的反正就是不合适

readUTF

writeUTF


/*
 * 针对字符串的操作
 */
public class Test83 {
	public static void main(String[] args) throws Exception {
		DataOutputStream dos = new DataOutputStream(new FileOutputStream("data/out3.dat"));
		System.out.println(dos.size());//可以获取当前的输出位置
		dos.writeInt(123);//写出一个整型数
		System.out.println(dos.size());
		dos.writeDouble(12.34);
		System.out.println(dos.size());
		String ss="abcdef";
//		dos.writeBytes(ss);
		dos.writeUTF(ss);  //操作字符串的方法
//		dos.writeChars(ss);
		dos.close();
		
		DataInputStream dis=new DataInputStream(new FileInputStream("data/out3.dat"));
//		dis.skip(4);//跳过4个字节开始读取数据
//		double dd=dis.readDouble();
//		System.out.println(dd);
		dis.skip(12);
//		byte[] data=dis.readAllBytes(); // 读取效果如下图所示存在乱码
		String s1=dis.readUTF();
		System.out.println(s1);
	}
}

在这里插入图片描述

6. 打印流

PrintStream和PrintWriter都属于输出流,分别针对字节和字符 PrintWriter和

PrintStream都提供了重载的print和println方法用于输出多种类型数据

print(Object):void

public void println(Object x) {
    String s = String.valueOf(x); //调用String类中的静态方法将object类型的数据转换为字符串
    synchronized (this) {
            print(s);
            newLine(); //print('\n')
        }
    }
    //String中的valueOf方法的定义
    public static String valueOf(Object obj) {
    	return (obj == null) ? "null" : obj.toString(); //如果输出对象非空,则调用对象的toString方法
}

println表示输出后自动换行

  • PrintWriter和PrintStream的输出操作不会抛出异常,用户通过检测错误状态获取错误信息
  • PrintWriter和PrintStream有自动的flush功能 textOut.flushBuffer();

PrintWriter(Writer)

PrintWriter(Writer out, boolean autoFlush)自动刷新----println

PrintWriter(OutputStream out) //参数是一个字节流,但是不需要通过桥接处理
PrintWriter(OutputStream out, boolean autoFlush)
PrintStream(OutputStream)
PrintStream(OutputStream out, boolean autoFlush)

扩展小芝士

  • 图片文件格式
    • png
    • gif
    • jpg:控制文件大小
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值