三、AVA IO流 中的功能性质的流(可以理解为根据核心部分拓展出来的功能流)

本文详细介绍了Java IO流中的基础数据类型流,如DataInputStream和DataOutputStream,用于处理基本类型数据。内存操作流包括ByteArrayOutputStream和ByteArrayInputStream,用于临时文件处理。打印流PrintStream和PrintWriter提供了方便的数据输出。RandomAccessFile允许高效随机访问文件,而SequenceInputStream则能合并多个输入流。最后,序列化流ObjectInputStream和ObjectOutputStream实现了对象的序列化和反序列化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



一、操作基本数据类型的流

       在我们使用 IO 流中的字符流和字节流实现数据的读取和写入操作时会发现,我们可以操作的其实只有字节、字符以及byte数组,无法操作基本数据类型的数据。
       JAVA 提供了操作基本数据类型的流,使用这个流就可以操作基本数据类型的数据了。使用的方式和之前的字节流字符流是一样的,只是提供了一些方法专门读取和写入基础类型的数据。
       这里需要注意一点:因为文本不能识别基础数据类型,所以打开文本会乱码。
       并且这个流其实我没 get 到点,如果只是作为文本来使用的话不需要使用基础数据类型,文本无法编译。而如果作为数据传输通道完全可以使用集合或者数组来代替。(个人感觉,如果有人有不同的看法欢迎讨论)
  • 操作基本数据类型的流
    • DataInputStream 类:可以操作基本数据类型的输入流

    • DataOutputStream 类:可以操作基本数据类型的输出流

      • Demo代码示例:
        public class DataStreamDemo {
        
            public static void main(String[] args) throws IOException{
        
                //写入数据
                write();
                //读取数据
                read();
        
            }
        
            private static void write() throws IOException {
                // DataOutputStream(OutputStream out)
                // 创建数据输出流对象
                DataOutputStream dos = new DataOutputStream(new FileOutputStream("dos.txt"));
        
                // 写入整数
                dos.writeByte(100);
                dos.writeShort(10000);
                dos.writeInt(1000000000);
                dos.writeLong(1000000000000000000L);
        
                // 写入小数
                dos.writeFloat(10.12F);
                dos.writeDouble(10.10789D);
        
                // 写入字符
                dos.writeChar('s');
        
                // 写入字符串
                dos.writeChars("今年是2022年");
        
                // 写入Boolean类型
                dos.writeBoolean(true);
        
                // 释放资源
                dos.close();
            }
        
        
            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 值
                boolean bo = dis.readBoolean();
        
                // 释放资源
                dis.close();
        
                System.out.println("byte:"+b);
                System.out.println("short:"+s);
                System.out.println("int:"+i);
                System.out.println("long:"+l);
                System.out.println("float:"+f);
                System.out.println("double:"+d);
                System.out.println("char:"+c);
                System.out.println("boolean:"+bo);
            }
        
        }
        
        运行结果:
        在这里插入图片描述



二、内存操作流(处理临时文件的流)

       内存操作流一般用于处理临时信息,因为临时信息不需要保存,使用后就可以删除。
  • 内存操作流 - 操作字节数组

    • ByteArrayOutputStream:输出流

    • ByteArrayInputStream : 输入流

      • Demo代码示例:

           public class ByteArrayDemo {
                public static void main(String[] args) throws IOException {
                    // 写数据 --字节数组输出流:相当于创建了一个临时空间
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
        
                    // 写数据,将数据放到临时空间中
                    for (int x = 0; x < 10; x++) {
                        baos.write(("HelloWord"+"\t" + x).getBytes());
                        baos.write("\n".getBytes());
                    }
        
                    // 释放资源
                    // 通过查看源码我们知道这里什么都没做,所以根本需要close()
                    // baos.close();
        
                    // 将临时空间转换成byte数组
                    byte[] bys = baos.toByteArray();
        
                    // 读数据: 只能读取byte数组的数据
                    // ByteArrayInputStream(byte[] buf)
                    ByteArrayInputStream bais = new ByteArrayInputStream(bys);
        
                    int by = 0;
                    while ((by = bais.read()) != -1) {
                        System.out.print((char) by);
                    }
        
                    // bais.close();
                }
            }
        

        运行结果:
        在这里插入图片描述


  • 内存操作流 - 操作字符数组

    • CharArrayReader:输出流

    • CharArrayWrite: 输入流

      • Demo代码示例:

            public class CharArrayDemo {
                public static void main(String[] args) throws IOException {
                    // 写数据 --字节数组输出流:相当于创建了一个临时空间
                    CharArrayWriter caw = new CharArrayWriter();
        
                    // 写数据,将数据放到临时空间中
                    for (int x = 0; x < 10; x++) {
                       caw.write("HelloWord"+"\t"+ x);
                       caw.write("\n");
                    }
        
                    // 释放资源
                    // 通过查看源码我们知道这里什么都没做,所以根本需要close()
                    // baos.close();
        
                    // 将临时空间转换成byte数组
                    char[] chars = caw.toCharArray();
        
                    // 读数据: 只能读取char数组的数据
                    // CharArrayInputStream(byte[] buf)
                    CharArrayReader car = new CharArrayReader(chars);
        
                    int by = 0;
                    while ((by = car.read()) != -1) {
                        System.out.print((char) by);
                    }
        
                    // bais.close();
                }
            }
        

        运行结果:
        在这里插入图片描述





三、打印流(不能操作数据源的流)

  • 打印流一共分为两种

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

  • 打印流的特点:

    • 只有输出流,没有输入流,所以打印流只能写入数据不能读取数据。但是可以和其他流搭配使用,以此来实现复制功能。方法是一样的,用打印流代替原本的输出流即可。
    • 可以操作任意类型的数据。
    • 该流可以直接操作文本文件。


  • 打印流独有的方法:

    • print() 不会换行,不会自动刷新数据。
    • println() 不仅仅自动刷新了数据,还实现了数据的换行。
      • Demo代码示例:
      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");
              
              //println()方法,等价于: bw.write(); bw.newLine(); bw.flush();三个方法
              pw.println("hello");
              pw.println(true);
              pw.println(100);
              pw.close();
      
          }
      }
      
      运行结果:
      在这里插入图片描述

字符打印流和字节打印流使用方法一样。




四、随机访问流:RandomAccessFile(速度和效率超级快的流)

RandomAccessFile 概述:

       RandomAccessFile类并不在 Java.IO 包下,所以严格意义上讲,这个类其实不属于流,该类是Object类的子类。但它融合了InputStream和OutputStream的功能,同时还支持对随机访问文件的读取和写入。

       其实这个类和其他流的使用方式和功能都差不多,但是随机访问流和其他流相比更有优先级,比缓冲流还快。
  • 构造方法 :

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

  • Demo代码示例:

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

       write();//写
       read();//读

   }

   public static void write() throws IOException{
       try {
           // 创建随机访问流对象
           RandomAccessFile raf = new RandomAccessFile("raf.txt", "rw");

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

           raf.close();
       } catch (IOException e) {
           e.printStackTrace();
       }

   }

   public static void read() throws IOException{
       try {
           // 创建随机访问流对象
           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());

           System.out.println("==========================================");

           // 我就要读取a,怎么办呢? 
           raf.seek(4);
           ch = raf.readChar();
           System.out.println(ch);
       } catch (IOException e) {
           e.printStackTrace();
       }
   }

}

运行结果:
在这里插入图片描述

文件指针:

       在Java开发中用一个指针变量指向一个文件,这个指针称为文件指针。通过文件指针就可对它所指的文件进行各种操作。



五、合并流(可以将多个数据源一起写入同一个封装地文件中的流)

概述:

        SequenceInputStream 类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。
       通俗点讲就是在实现文件复制功能的时候,可以将多个数据源的数据一起存储到同一个封装地文件中。
  • SequenceInputStream 的构造方法
    • SequenceInputStream(InputStream s1, InputStream s2)
    • SequenceInputStream(Enumeration < ? extends InputStream> e)

  • Demo代码示例:

    public class SequenceInputStreamDemo {
    
        public static void main(String[] args) throws IOException {
            //设置多数据源
            InputStream s1 = new FileInputStream("aaa.txt");
            InputStream s2 = new FileInputStream("bbb.txt");
    
            // 将多个数据源存储进合并流对象中
            SequenceInputStream sis = new SequenceInputStream(s1, s2);
            
            // 设置文件封装地
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("Copy.txt"));
    
            // 读写操作
            byte[] bys = new byte[1024];
            int len = 0;
            while ((len = sis.read(bys)) != -1) {
                bos.write(bys, 0, len);
            }
    
            bos.close();
            sis.close();
        }
    }
    

    运行结果:
    在这里插入图片描述




六、序列化流 (操作对象的流)

概述:

        序列化流是 JAVA IO 中专门操作对象的流。 有序列化流和反序列化流两种。
  • 序列化流 :ObjectOutputStream
    • 把对象按照流一样的方式存入文本文件或者在网络中传输。对象 –> 流数据
      • 成员方法:public final void writeObject(Object obj) :将对象转换成流数据,并写入序列化流中(文本或者网络等等地方,俗称封装地文件)

  • 反序列化流:ObjectInputStream
    • 把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 –>对象
      • 成员方法:readObject():用这个方法就可以将流中的对象重新还原成对象

既然是对象转换流,那首先整个实体类,咱 new 个对象(程序猿从不缺对象!!!)

  • 实体类 Demo 代码示例:
//创建实体类
public class Person implements Serializable {

    private String name;//姓名

    private int age;//年龄

    // 构造1
    public Person() {
        super();
    }

    // 构造2
    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 + "]";
    }
}
  • 将对象转换成流数据 Demo 代码示例:
//序列化流写入数据
public class ObjectOutputStreamDemo{
    public static void main(String[] args) throws IOException {
        // 创建序列化流对象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("copy.txt"));

        // 创建实体类对象
        Person p = new Person("小丸子", 23);

		//将对象写入流中
        oos.writeObject(p);

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

运行结果:

在这里插入图片描述
根据结果可以看不来,这个数据并不能直接使用,呈现乱码状态,因为文本并不能编译 Java 的对象。但是可以看出来对象的路径和对象中存储的部分内容。

  • 将流中的对象数据转换回对象 Demo 代码示例:
//反序列化流 读取数据
public class ObjectInputStreamDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException{

        // 创建反序列化对象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                "copy.txt"));

        // 将流中的对象重新还原成对象
        Object obj = ois.readObject();

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

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

运行结果:

在这里插入图片描述

        这里需要注意一点:当我们在使用反序列化流转换对象时,需要保证正在反序列化的文件中的对象是没被动过的,这里必须要保证该文件中的对象是被序列化过的,否则报错。
        具体的报错信息会根据情况的不同而产生变化,出现此类问题,请联系一下度妈,886。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值