Io of Javase Part2

IO包中的其他类

打印流

  • PrintWriter与PrintStream:可以直接操作输入流和文件,都属于输出流,分别针对字符和字节。
  • 调用 println 方法有自动 flush 功能
  • PrintWriter 和 PrintStream 重载的 print()和 println()用于多种数据类型的输出。
  • print()里的参数不能为空;println()可以

PrintStream:

  1. 提供了打印方法可以对多种数据类型值进行打印,并保持数据的表示形式
  2. 它不抛IOException
  3. 打印的所有字符都使用平台的默认字符编码转换为字节。

    说明:在需要输出字符而不是输出字节的情况下,应该使用PrintWriter类。

  • 构造函数,接收三种类型的值:
  1. 字符串路径
  2. File对象
  3. 字节输出流
  • 常见方法:

    • void write(int b) 将指定的字节写入此流。
    • void write(byte[] buf, int off, int len) 将 len 字节从指定的初始偏移量为 off 的 byte 数组写入此流。
    • print方法,可以输出多种数据类型
    //write(int b)方法只写最低8位
    out.write(97); //a
    //print方法将97先变成字符串保持原样将数据打印到目的地
    out.print(97); //97
    
  • 格式化输出:

    • PrintStream format(String format, Object… args) 使用指定格式字符串和参数将格式化字符串写入此输出流中。

    • PrintStream printf(String format, Object… args) 使用指定格式字符串和参数将格式化的字符串写入此输出流的便捷方法。

      String name = "小明";
      int age = 13;
      char score = 'A';
      
      String format = "姓名 = %s,年龄 = %d,成绩 = %c";
      System.out.printf(format, name, age, score);//姓名 = 小明,年龄 = 13,成绩 = A
      
字符描述
%s表示内容是字符串
%d表示内容是整数
%f表示内容是小数
%c表示内容是字符
注:使用“%s”来表示所有的数据类型!

PrintWriter:字符打印流

  • 构造函数参数:
  1. 字符串路径

  2. File对象

  3. 字节输出流

    PrintWriter(OutputStream out, boolean autoFlush) 通过现有的 OutputStream 创建新的 PrintWriter。autoFlush * boolean 变量,如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区

  4. 字符输出流

    PrintWriter(Writer out, boolean autoFlush) 创建新 PrintWriter。autoFlush * boolean 变量,如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区

文件的分割和合并操作

序列流(合并)

SequenceInputStream(InputStream的子类): 表示其他输入流的逻辑串联,可对多个流进行合并。

  • 构造方法

    • SequenceInputStream(Emueration<? extends InputStream > e) 通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。
    • SequenceInputStream(InputStream s1, InputStream s2) 通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
  • 基本方法:

    • int available() 返回不受阻塞地从当前底层输入流读取(或跳过)的字节数的估计值,方法是通过下一次调用当前底层输入流的方法。
    • void close() 关闭此输入流并释放与此流关联的所有系统资源。
    • int read() 从此输入流中读取下一个数据字节。
    • int read(byte[] b, int off, int len) 将最多 len 个数据字节从此输入流读入 byte 数组。
  • 代码示例:

import java.io.*;
import java.util.*;
/*
需求:将1.txt、2.txt、3、txt文件中的数据合并到一个文件中。
分析:使用SequenceInputStream的构造方法 + Vector集合
*/
class SequenceDemo {
	public static void main(String[] args) throws IOException{
		/*
		//定义一个Vector集合
		Vector<FileInputStream> v = new Vector<FileInputStream>();

		//向集合中添加文件读取流元素
		v.add(new FileInputStream("D:\\Java\\Day20\\SequenceDemo\\1.txt"));
		v.add(new FileInputStream("D:\\Java\\Day20\\SequenceDemo\\2.txt"));
		v.add(new FileInputStream("D:\\Java\\Day20\\SequenceDemo\\3.txt"));

		//通过elements方法返回一个文件读取流元素的枚举
		Enumeration<FileInputStream> en =v.elements();
		*/

		//改进后的方法:使用ArrayList比Vector效率更高
		ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
		for(int x = 1; x <= 3; x++){
			al.add( new FileInputStream("D:\\Java\\Day20\\SequenceDemo\\"+ x + ".txt" ));
		}

		//使用集合工具类Collections的enumeration方法返回一个文件读取流元素的枚举
		Enumeration<FileInputStream> en = Collections.enumeration(al);

		//通过传入的文件读取流元素来初始化新创建 SequenceInputStream
		SequenceInputStream sis = new SequenceInputStream(en);

		//将合并的数据输出到新的文件中
		FileOutputStream fos = new FileOutputStream("D:\\Java\\Day20\\SequenceDemo\\4.txt");
		byte[] buf = new byte[1024];
		int len =0;
		while ((len =sis.read(buf))!=*1) {
			fos.write(buf,0,len);
		}

		fos.close();
		sis.close();
	}
}

操作对象流

ObjectInputStream与ObjectOutputStream

  • 特点:
    • 被操作的对象需要实现Serializable。类通过实现java.io.Serializable接口以启用序列化功能,Serializable只是一个标记接口。
    • writeObject方法不能写入类及其所有超类型的瞬态(transient关键字修饰)和静态字段的值。

RandomAccessFile

随机访问文件,自身具备读写的方法。不是io体系中的子类。直接继承自Object。通过skipBytes(int x),seek(int x)等方法来达到随机访问。

  • 构造函数:

    • RandomAccessFile(File file, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件由 File 参数指定。
    • RandomAccessFile(String name, String mode) 创建从中读取和向其中写入(可选)的随机访问文件流,该文件具有指定名称。
  • 特点:

    1. 该对象即能读,又能写。
    2. 该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素。
    3. 可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置。
    4. 其实该对象就是将字节输入流和输出流进行了封装。
    5. 该对象的源或者目的只能是文件。通过构造函数就可以看出。而且操作文件模式:只读r, 读写rw等。

      如果模式为只读r ,不会创建文件,会去读一个已存在的文件,如果该文件不存在,则会出现异常;
      如果模式为rw,操作的文件不存在,会自动创建。如果存在不会覆盖。

管道流

简介

  • PipedInputStream(InputStream子类)和PipedOutputStream:(OutputStream)输入输出可以直接进行连接,通过结合线程使用。
  • 管道输入流应该连接到管道输出流;管道输入流提供要写入管道输出流的所有数据字节。

代码示例:

import java.io.*;
//实现Runnable接口,覆盖run方法
class Read implements Runnable {
	private PipedInputStream in;
	Read(PipedInputStream in) {
		this.in = in;
	}
	public void run() {
		try {
			byte[] buf = new byte[1024];

			System.out.println("读取前。。。没有数据阻塞");
			int len = in.read(buf);
			System.out.println("读到数据。。。阻塞结束");

			String s = new String(buf,0,len);
			System.out.println(s);
			in.close();
		}
		catch (IOException e) {
			throw new RuntimeException("管道流读取失败");
		}
	}
}

//实现Runnable接口,覆盖run方法
class Write implements Runnable {
	private PipedOutputStream out;
	Write(PipedOutputStream out) {
		this.out = out;
	}
	public void run() {
		try {
			System.out.println("开始写入,等待6s后");
			Thread.sleep(6000);

			out.write("piped come!".getBytes());
		}
		catch (Exception e) {
			throw new RuntimeException("管道输出流失败");
		}
	}
}

class PipedStreamDemo {
	public static void main(String[] args) throws IOException{
		PipedInputStream in = new PipedInputStream();
		PipedOutputStream out = new PipedOutputStream();
		//将此管道输入流和输出流相连输入流和输出流相连
		in.connect(out);

		Read r = new Read(in);
		Write w = new Write(out);

		//分别建立写和读的线程
		new Thread(r).start();
		new Thread(w).start();
	}
}

操作基本数据类型

简介

  • DataInputStream(FilterInputStream子类)与DataOutputStream(FilterOutputStream子类),可以用于操作基本数据类型的数据的流对象

操作字节数组

简介

  • ByteArrayInputStream(InputStream子类):

    • 在构造的时候,需要接收数据源,而且数据源是一个字节数组。
  • ByteArrayOutputStream(OutputStream子类):

    • 在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。这就是数据目的地。
  • 因为这两个流对象都操作的数组,并没有使用系统资源。所以,不用进行close关闭。

编码表

简介

  • 将各个国家的文字用数字来表示,并一一对应,形成一张表,这就是编码表。
  • 字符串**>字节数组:编码
  • 字符数组**>字符串:解码

常见的编码表

  • ASCII:美国标准信息交换码,用一个字节的7位表示。
  • ISO8859*1:拉丁码表。欧洲码表,用一个字节的8位表示。
  • GB2312:中国的中文编码表。
  • GBK:中国的中文编码表升级,融合了更多的中文文字符号。
  • Unicode:国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言使用的就是unicode
  • UTF*8:最多用三个字节来表示一个字符。 ……

两种情况

  • 如果编码编错了,解不出来。
  • 如果编对了,解错了,可能有救,也可能没救了。