JAVA基础再回首(二十三)——操作基本数据类型的流、内存操作流、打印流、随机访问流、合并流、序列化流

时间:2023-02-15 18:09:53

JAVA基础再回首(二十三)——操作基本数据类型的流、内存操作流、打印流、随机访问流、合并流、序列化流

版权声明:转载必须注明本文转自程序员杜鹏程的博客:http://blog.csdn.net/m366917

有些日子没写博客了,当然这段时间也比较忙,大家见谅,好了,话不多说,开始学习吧。

我们继续学习IO流,还有几个知识点没有学。

操作基本数据类型的流

  • 操作基本数据类型

    • DataInputStream
    • DataOutputStream

    操作基本数据类型的流可以读写基本数据类型的数据,我们来写一个简单的读写例子

public class DataStreamDemo {
public static void main(String[] args) throws IOException {
// 写
write();

// 读
read();
}

private static void read() throws IOException {
// DataInputStream(InputStream in)
// 创建数据输入流对象
DataInputStream dis = new DataInputStream(new FileInputStream("dos.txt"));

// 读数据
byte b = dis.readByte();
short s = dis.readShort();
int i = dis.readInt();
long l = dis.readLong();
float f = dis.readFloat();
double d = dis.readDouble();
char c = dis.readChar();
boolean bb = dis.readBoolean();

// 释放资源
dis.close();

System.out.println(b);
System.out.println(s);
System.out.println(i);
System.out.println(l);
System.out.println(f);
System.out.println(d);
System.out.println(c);
System.out.println(bb);
}

private static void write() throws IOException {
// DataOutputStream(OutputStream out)
// 创建数据输出流对象
DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt"));

// 写数据
dos.writeByte(10);
dos.writeShort(100);
dos.writeInt(1000);
dos.writeLong(10000);
dos.writeFloat(12.34F);
dos.writeDouble(12.56);
dos.writeChar('a');
dos.writeBoolean(true);

// 释放资源
dos.close();
}
}

我们先写数据,然后再读数据。可以看到读写基本数据类型的数据都是ok的。

内存操作流


  • 操作字节数组
    • ByteArrayInputStream
    • ByteArrayOutputStream
  • 操作字符数组
    • CharArrayReader
    • CharArrayWrite
  • 操作字符串
    • StringReader
    • StringWriter

内存操作流一般用于处理临时信息,因为临时信息不需要保存,使用后就可以删除。
public class ByteArrayStreamDemo {
public static void main(String[] args) throws IOException {
// 写数据 --字节数组输出流
ByteArrayOutputStream baos = new ByteArrayOutputStream();

// 写数据
for (int x = 0; x < 10; x++) {
baos.write(("hello" + x).getBytes());
}

// 释放资源
// 通过查看源码我们知道这里什么都没做,所以根本需要close()
// baos.close();

// public byte[] toByteArray()
byte[] bys = baos.toByteArray();

// 读数据
// ByteArrayInputStream(byte[] buf)
ByteArrayInputStream bais = new ByteArrayInputStream(bys);

int by = 0;
while ((by = bais.read()) != -1) {
System.out.print((char) by);
}

// bais.close();
}
}

上面我们写英文字符数据可以运用字节数组的输出流ByteArrayOutputStream,如果我们写入中文数据的话就要用操作字符数组的流CharArrayWrite了。那么,剩下的操作字符数组和操作字符串的例子就不做演示了,大家可以自己练练。

打印流

打印流分为两类

  • 字节流打印流 PrintStream
  • 字符打印流 PrintWriter

打印流的特点:

  • 只有写数据的,没有读取数据。只能操作目的地,不能操作数据源。
  • 可以操作任意类型的数据。
  • 如果启动了自动刷新,能够自动刷新。
  • 该流是可以直接操作文本文件的。

我们来回忆一下哪些流对象是可以直接操作文本文件的呢?


  • FileInputStream
  • FileOutputStream
  • FileReader
  • FileWriter
  • PrintStream
  • PrintWriter
  • 看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的。
    JAVA基础再回首(二十三)——操作基本数据类型的流、内存操作流、打印流、随机访问流、合并流、序列化流

打印流的特点有一条是可以操作任意类型的数据,可是我们看方法,他的write方法不可以写boolean类型的,所以我们就去看看他的api,看有什么新方法,当然是有的,我们就直接来学习他的新方法吧。

可以操作任意类型的数据。有两种方法,他们就什么区别呢?

  • print() 不会换行,不会自动刷新数据。
  • println() 不仅仅自动刷新了数据,还实现了数据的换行。
  • public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
    // 创建打印流对象
    PrintWriter pw = new PrintWriter("pw2.txt");

    pw.print(true);
    pw.print(100);
    pw.print("hello");
    pw.close();
    }
    }

    public class PrintWriterDemo {
    public static void main(String[] args) throws IOException {
    // 创建打印流对象
    PrintWriter pw = new PrintWriter(new FileWriter("pw2.txt"), true);

    pw.println("hello");
    pw.println(true);
    pw.println(100);

    pw.close();
    }
    }

    分别运行上面的两个demo,你就会很明显的看出我们上面总结的区别了。
    因此我们还可以总结:
    println()方法,其实等价于: bw.write(); bw.newLine(); bw.flush();三个方法

    我们用打印流来复制一个文件,我们先来分析

    • 需求:1.txt复制到Copy.txt中(首先你要确认有1.txt,并有内容)
    • 数据源:1.txt – 读取数据 –> FileReader –高效,所以用–> BufferedReader
    • 目的地:Copy.txt – 写出数据 –> FileWriter –> BufferedWriter –> PrintWriter
    public class CopyFileDemo {
    public static void main(String[] args) throws IOException {
    // 封装数据源
    BufferedReader br = new BufferedReader(new FileReader(
    "DataStreamDemo.java"));
    // 封装目的地
    PrintWriter pw = new PrintWriter(new FileWriter("Copy.java"), true);

    String line = null;
    while((line=br.readLine())!=null){
    pw.println(line);
    }

    pw.close();
    br.close();
    }
    }

    这样比以前的那种写法简单多了吧,什么,以前的那种写法你别告诉我你又忘记了,那好吧,我来给你写写吧

            // 以前的版本
    // 封装数据源
    BufferedReader br = new BufferedReader(new FileReader("1.txt"));
    //封装目的地

    BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.txt"));

    String line = null;
    while ((line = br.readLine()) != null) {
    bw.write(line);
    bw.newLine();
    bw.flush();

    好了,这下get到了吧。

    随机访问流

    RandomAccessFile

    概述:RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。支持对随机访问文件的读取和写入。

    这个类我以前写视频断点上传的时候就用到了,很强大的一个类,我们下面来学习下。

    public RandomAccessFile(String name,String mode):
    第一个参数是文件路径,第二个参数是操作文件的模式。
    模式有四种,我们最常用的一种叫”rw”,这种方式表示我既可以写数据,也可以读取数据
    下面我们就用这个类来写一个简单的读写操作的例子

    public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {

    // 创建随机访问流对象
    RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");

    // 写入数据
    raf.writeInt(100);
    raf.writeChar('a');
    raf.writeUTF("中国");

    raf.close();
    }

    }

    运行程序,然后我们继续来写读的方法

    public class RandomAccessFileDemo {
    public static void main(String[] args) 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);
    }

    }

    这是随机访问流的简单操作,后面我有空会把之前项目中做过的断点上传一个文件,用到了这个类,做一总结。

    合并流

    SequenceInputStream

    概述:SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。

    • SequenceInputStream的构造方法
      • SequenceInputStream(InputStream s1, InputStream s2)
      • SequenceInputStream(Enumeration < ? extends InputStream> e)
      • 把多个文件的内容写入到一个文本文件

    以前我们只是将一个文件的内容复制到另外一个文件中,现在这个合并流可以实现将两个及多个文件的内容复制到一个文件中了,我们来实现以下吧

    // 需求:把ByteArrayStreamDemo.java和DataStreamDemo.java的内容复制到Copy.java中

    public class SequenceInputStreamDemo {
    public static void main(String[] args) throws IOException {
    InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");
    InputStream s2 = new FileInputStream("DataStreamDemo.java");
    SequenceInputStream sis = new SequenceInputStream(s1, s2);
    BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Copy.java"));

    // 读写操作
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = sis.read(bys)) != -1) {
    bos.write(bys, 0, len);
    }

    bos.close();
    sis.close();
    }
    }

    运行程序你会在Copy.java文件中看到ByteArrayStreamDemo.java和DataStreamDemo.java文件的内容都复制到了Copy.java文件中。

    那么怎么合并3个或者三个以上的文件操作呢?

    // 需求:把下面的三个文件的内容(ByteArrayStreamDemo.java,CopyFileDemo.java,DataStreamDemo.java)复制到Copy.java中

    public class SequenceInputStreamDemo2 {
    public static void main(String[] args) throws IOException {

    // SequenceInputStream(Enumeration e)
    // 通过简单的回顾我们知道了Enumeration是Vector中的一个方法的返回值类型。
    // Enumeration<E> elements()
    Vector<InputStream> v = new Vector<InputStream>();
    InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");
    InputStream s2 = new FileInputStream("CopyFileDemo.java");
    InputStream s3 = new FileInputStream("DataStreamDemo.java");
    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("Copy.java"));

    // 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写
    byte[] bys = new byte[1024];
    int len = 0;
    while ((len = sis.read(bys)) != -1) {
    bos.write(bys, 0, len);
    }

    bos.close();
    sis.close();
    }
    }

    运行程序,我们会在Copy.java文件中看到那三个文件的内容,我们要是想合并四个或者以上的文件,只需要继续将文件创建输入流对象然后添加在Vector集合中就可以实现了。

    序列化流

    • 序列化流
      • ObjectOutputStream
    • 反序列化流
      • ObjectInputStream

    序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 –> 流数据(ObjectOutputStream)

    反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 –>对象(ObjectInputStream)

    //我们先写一个实体类,并实现序列化接口
    public class Person implements Serializable {

    private String name;

    private int age;

    public Person() {
    super();
    }

    public Person(String name, int age) {
    super();
    this.name = name;
    this.age = age;
    }

    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;
    }

    @Override
    public String toString() {
    return "Person [name=" + name + ", age=" + age + "]";
    }
    }

    //写入数据
    public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException{
    // 创建序列化流对象
    ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt"));

    // 创建对象
    Person p = new Person("阿杜", 25);

    // public final void writeObject(Object obj)
    oos.writeObject(p);

    // 释放资源
    oos.close();
    }
    }
    //读取数据
    public class ObjectStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException{
    // 创建反序列化对象
    ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
    "oos.txt"));

    // 还原对象
    Object obj = ois.readObject();

    // 释放资源
    ois.close();

    // 输出对象
    System.out.println(obj);
    }
    }

    输出结果:Person [name=阿杜, age=25]

    我们也可以这样理解

    对象序列化是将对象状态转换为可保持或传输的过程。一般的格式是与平台无关的二进制流,可以将这种二进制流持久保存在磁盘上,也可以通过网络将这种二进制流传输到另一个网络结点。
    对象反序列化,是指把这种二进制流数据还原成对象。

    好了,IO流我们就学到这里了。大家没事了多练习练习。

    欢迎有兴趣的同学加我朋友的QQ群:点击直接加群555974449 请备注:java基础再回首我们一起来玩吧。