java IO流 之 其他流

时间:2021-07-23 19:26:56

一、内存操作流(ByteArrayInputStream、ByteArrayOutputStream)

(一)、   public class ByteArrayInputStream extends InputStream;

ByteArrayInputSteam:该类是InputStream的子类,它从内存中的字节数组中读取数据,因此它的数据源是一个字节数组。这个类的构造方法包括: 
     ByteArrayInputStream(byte[] buf)--------参数buf指定字节数组类型的数据源。 
     ByteArrayInputStream(byte[] buf, int offset, int lenght)-----参数buf指定字节数组类型数据源,参数offset指定从数组中开始读取数据的起始下标位置,lenght指定从数组中读取的字节数。 
     ByteArrayInputStream类本身采用了适配器设计模式,它把字节数组类型转换为输入流类型,使得程序能够对字节数组进行读操作。

public static void byteArrTest() throws IOException{
ByteArrayInputStream bis=new ByteArrayInputStream("abcd".getBytes());
int len=;
while((len=bis.read())!=-){
System.out.println((char)len+"<=>"+len);
}
bis.close();
}

(二)、public class ByteArrayOutputStream extends OutputStream

ByteArrayOutputStream:此类实现了一个输出流,其中的数据被写入一个 byte 数组。缓冲区会随着数据的不断写入而自动增长。可使用 toByteArray()toString() 获取数据。关闭 ByteArrayOutputStream 无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException

1、public byte[] toByteArray()创建一个新分配的 byte 数组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中

    public static void byteArrOut() throws IOException{
ByteArrayOutputStream bos=new ByteArrayOutputStream();
bos.write(97);
bos.write(new byte[]{98,99,100});
//public byte[] toByteArray()创建一个新分配的 byte 数组。其大小是此输出流的当前大小,并且缓冲区的有效内容已复制到该数组中。
byte [] bys=bos.toByteArray();
for(byte b:bys){
System.out.println(b+"<==>"+(char)b);
}
}

2、public String toString()使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。新 String 的长度是字符集的函数,因此可能不等于缓冲区的大小。

public static void byteArrOut2() throws IOException{
ByteArrayOutputStream bos=new ByteArrayOutputStream();
bos.write(97);
bos.write(new byte[]{98,99,100});
//public String toString()使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串。新 String 的长度是字符集的函数,因此可能不等于缓冲区的大小。
String str=bos.toString();
System.out.println(str);//abcd
}

(三)、ByteArrayInputStream、ByteArrayOutputStream一起使用

public static void byteArrOut() throws IOException{
ByteArrayOutputStream bos=new ByteArrayOutputStream();
bos.write(97);
bos.write(new byte[]{98,99,100});
byte [] bys=bos.toByteArray();
ByteArrayInputStream bis=new ByteArrayInputStream(bys);
int len=0;
while((len=bis.read())!=-1){
System.out.print((char)len);//abcd
}
}

二、打印流(PrintStream,PrintWriter)

PrintStream是FilterOutputStream的子类。

PrintWriter 是 Writer的子类。

打印流的特点:
 *   A:只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。打印流只有字节打印流PrintStream 与字符打印流PrintWriter
 *   B:可以操作任意类型的数据。他们的print()系列方法与println()系列方法可以操作任意类型数据。
 *   C:如果启动了自动刷新,能够自动刷新。但必须调用println()方法

PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);

PrintStream ps=new PrintStream(new FileOutputStream("a.txt"),true);
 *   D:该流是可以直接操作文本文件的。

public PrintStream(File file)  throws FileNotFoundException

public PrintWriter(File file)  throws FileNotFoundException

1、使用PrintStream实现文件的copy

public static void streamCopy() throws IOException{
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("a.txt"));
//public PrintStream(OutputStream out,boolean autoFlush)使用该够造函数 开启自动刷新功能
PrintStream ps=new PrintStream(new FileOutputStream("Copy.java"),true);
byte [] bys=new byte[1024];
int line =0;
while((line=bis.read(bys))!=-1){
ps.println(new String(bys,0,line));
}
ps.close();
bis.close();
}

2、使用 PrintWriter实现文件的copy

public static void copy() throws IOException{
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
// 封装目的地
//public PrintWriter(OutputStream out,boolean autoFlush);使用该够造函数 开启自动刷新功能
PrintWriter pw =new PrintWriter(new FileWriter("Copy.java"), true);
String line = null;
while((line=br.readLine())!=null){
pw.println(line);
}
pw.close();
br.close();
}

三、标准输入输出流(public final class System)

System类中的三个成员变量

        //“标准”输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。
public final static InputStream in = null;
//“标准”输出流。此流已打开并准备接受输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。
public final static PrintStream out = null;
//“标准”错误输出流。此流已打开并准备接受输出数据。 通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标
public final static PrintStream err = null;

由System.out变量我们可以:

       // 有这里的讲解我们就知道了,这个输出语句其本质是IO流操作,把数据输出到控制台。
System.out.println("helloworld");
// 获取标准输出流对象
PrintStream ps = System.out;
ps.println("helloworld");

System.in 标准输入流。是从键盘获取数据的。

获取键盘输入数据的方式:

1、Scanner(JDK5以后的)

Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
int x = sc.nextInt()

2、System.in
System.in返回的类型是InputStream,而它是一个字节流,如果我们以此获取键盘输入的数据每次获取一个字节,输入的数据是我们看不懂的编码数据。所以我们把该流转换为字符流。

private static void systemInTest() throws IOException {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String str=br.readLine();
System.out.println(str);
}

四、合并流 SequenceInputStream

  SequenceInputStream :表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。(JDK)

够造函数一、 public SequenceInputStream(InputStream s1,  InputStream s2)

通过记住这两个参数来初始化新创建的 SequenceInputStream(将按顺序读取这两个参数,先读取 s1,然后读取 s2),以提供从此 SequenceInputStream 读取的字节。
     参数:
s1 - 要读取的第一个输入流。
s2 - 要读取的第二个输入流。
 //将 a.txt+b.txt=c.txt(将a、b文件中的内容合并到c中)
private static void gzOne() throws IOException {
InputStream s1 = new FileInputStream("a.txt");
InputStream s2 = new FileInputStream("b.txt");
SequenceInputStream sis = new SequenceInputStream(s1, s2);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("c.txt"));
// 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写
byte[] bys = new byte[1024];
int len = 0;
while ((len = sis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
sis.close();
}

够造函数二、public SequenceInputStream(Enumeration<? extends InputStream> e)

通过记住参数来初始化新创建的 SequenceInputStream,该参数必须是生成运行时类型为 InputStream 对象的 Enumeration 型参数。将按顺序读取由该枚举生成的输入流,以提供从此 SequenceInputStream 读取的字节。在用尽枚举中的每个输入流之后,将通过调用该流的 close 方法将其关闭。

参数:e - 输入流的一个枚举。

 private static void multiInput() throws IOException {
// 需求:把下面的三个文件的内容复制到d.txt中
// Enumeration是Vector中的一个方法的返回值类型。
// Enumeration<E> elements()
Vector<InputStream> v = new Vector<InputStream>();
InputStream s1 = new FileInputStream("a.txt");
InputStream s2 = new FileInputStream("b.txt");
InputStream s3 = new FileInputStream("c.txt");
v.add(s1);
v.add(s2);
v.add(s3);
Enumeration<InputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("d.txt"));
// 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写
byte[] bys = new byte[1024];
int len = 0;
while ((len = sis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
sis.close();
}

 五、序列化流(ObjectOutputStream)与反序列化流(ObjectInputStream)

1、public class ObjectOutputStream  extends OutputStream implements ObjectOutput, ObjectStreamConstants

ObjectOutputStream:把对象按照流一样的方式存入文本文件或者在网络中传输,通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。

示例:先构建一个person对象且实现Serializable接口(该接口是标记接口)

public class Person implements Serializable {
private static final long serialVersionUID = 6722268977065149350L;
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
get() ...
  set()...
}
private static void writer() throws IOException {
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("oos.txt"));
Person person=new Person("张三",12);
//public final void writeObject(Object obj)throws IOException
//将指定的对象写入 ObjectOutputStream。对象的类、类的签名,以及类及其所有超类型的非瞬态和非静态字段的值都将被写入。
//可以使用 writeObject 和 readObject 方法重写类的默认序列化
oos.writeObject(person);
oos.flush();
oos.close();
}

oos.txt的内容:
java IO流 之 其他流

2、反序列化:public class ObjectInputStream extends InputStream implements ObjectInput, ObjectStreamConstants。

ObjectInputStream:把文本文件中的流对象数据或者网络中的流对象数据还原成对象,ObjectInputStream 用于恢复那些以前序列化的对象。其他用途包括使用套接字流在主机之间传递对象,或者用于编组和解组远程通信系统中的实参和形参。

    private static void reader() throws IOException, ClassNotFoundException{
ObjectInputStream ois=new ObjectInputStream(new FileInputStream("oos.txt"));
//public final Object readObject( throws IOException, ClassNotFoundException
//从 ObjectInputStream 读取对象。对象的类、类的签名和类及所有其超类型的非瞬态和非静态字段的值都将被读取。
Object obj=ois.readObject();
System.out.println(obj);
ois.close();
}

输出结果:Person [name=张三, age=12]
注意:1、我们在实际开发中,可能还需要使用以前写过的数据,即如果我们更改了person类的内容而oos.txt 没有重新生成,则会出现异常类型id值不一致异常,我们可以在person类中提供一个标识来控制这个问题加入一个属性private static final long serialVersionUID = 6722268977065149350L;

2、如果某个人属性我们不想被序列化可以为该属性添加一个关键字transient,类如:private transient int age;

六、随机访问流(RandomAccessFile)

public class RandomAccessFile  extends Object  implements DataOutput, DataInput, Closeable。该类RandomAccessFile类不属于流,是Object类的子类。  但它融合了InputStream和OutputStream的功能。 支持对文件的随机访问读取和写入。

  够造函数:public RandomAccessFile(String name, String mode)throws FileNotFoundException;

第一个参数是文件路径,第二个参数是操作文件的模式。模式有四种("r""rw""rws""rwd"),我们最常用的一种叫"rw",这种方式表示我既可以写数据,也可以读取数据

private static void read() throws IOException {
// 创建随机访问流对象
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); int i = raf.readInt();
System.out.println(i);
// 该文件指针可以通过 getFilePointer方法读取,并通过 seek 方法设置。
System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); char ch = raf.readChar();
System.out.println(ch);
System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); String s = raf.readUTF();
System.out.println(s);
System.out.println("当前文件的指针位置是:" + raf.getFilePointer()); // 我不想重头开始了,我就要读取a,怎么办呢?
raf.seek(4);
ch = raf.readChar();
System.out.println(ch);
} private static void write() throws IOException {
// 创建随机访问流对象
RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw"); // 怎么玩呢?
raf.writeInt(100);
raf.writeChar('a');
raf.writeUTF("中国"); raf.close();
}