博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

JavaEE - 13IO流2

Posted on 2020-12-08 13:36  Kingdomer  阅读(83)  评论(0)    收藏  举报

JavaEE - 13IO流2

(7)处理流之四: 打印流
  • 实现将基本数据类型的数据格式转化为字符串输出
  • 打印流: PrintStream 和 PrintWriter
    • 提供了一系列重载的print()和println()方法,用于多种数据类型的输出
    • PrintStream和PrintWriter的输出不会抛出 IOException 异常。
    • PrintStream和PrintWriter有自动flush 功能
    • PrintStream打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用PrintWriter类。
    • System.out返回的是PrintStream的实例。
    @Test
    public void test2(){
        PrintStream ps = null;
        try{
            FileOutputStream fos = new FileOutputStream(new File("tee.txt"));
            // 创建打印输出流,设置为自动刷新模式(写入换行符或字节'\n'时都会刷新输出缓冲区)
            ps = new PrintStream(fos, true);
            if(ps != null){
                System.setOut(ps);
            }
            for(int i =0; i<=255; i++){
                System.out.print((char)i);  // 输出ASCII字符
                if(i % 50 == 0){            // 每50个数据一行
                    System.out.println();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(ps != null){
                ps.close();
            }
        }
    }

 

 

 

(8)处理流之五:数据流

 

  • 为了方便地操作Java语言的基本数据类型和String的数据,可以使用数据流。
  • 数据流有两个类:(用于读取和写出基本数据类型、String类型的数据)
    • DataInputStream 和 DataOutputStream
    • 分别"套接"在 InputStrean 和 OutputStream 子类的流上
  • DataInputStream中的方法
    • boolean readBoolean()/ char readChar()/ String readUTF()/ void readFully(byte[] b)
    • byte readByte()/ short readShort()/ int readInt()/ long readLong()/ float readFloat()/ double readDouble()
  • DataOutputStream中的方法
    • 将上述的方法的read改成相应的write即可。
    • 将文件中存储的基本数据类型变量和字符串读取到内存中,保存在变量中。
    • 注意点: 读取不同类型的数据的顺序要与写入文件时保存的顺序一致。
    @Test
    public void test2() throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("hello4.txt"));
        dos.writeUTF("孙悟空");
        dos.flush();
        dos.writeInt(23);
        dos.flush();
        dos.writeBoolean(true);
        dos.flush();
        dos.close();

        DataInputStream dis = new DataInputStream(new FileInputStream("hello4.txt"));
        String name = dis.readUTF();
        int age = dis.readInt();
        boolean isMale = dis.readBoolean();
        System.out.println("name:" + name +",age: " + age +",isMale: "+ isMale); //name:孙悟空,age: 23,isMale: true
    }

 

(9)处理流之六:对象流

  • ObjectInputStreamObjectOutputStream
    • 用于存储和读取基本数据类型数据或对象的处理流。
    • 强大之处是可以把Java中的对象写入到数据库中,也能把对象从数据源中还原回来。
  • 序列化:   用 ObjectOutputStream类保存 基本数据类型 数据或对象的机制
  • 反序列化: 用 ObjectInputStream类读取 基本数据类型 数据或对象的机制
  • ObjectOutputStream和ObjectInputStream 不能序列化 statictransient 修饰的成员变量
(9.1)对象的序列化
  • 对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,
    • 从而允许把这种二进制流持久地保存在磁盘上,或通过网络将二进制流传输到另一个网络节点。
    • 当其它程序获取了这种二进制流,可以恢复成原来的Java对象。
  • 序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,使其在保存和传输时可被还原
  • 序列化是RMI(Remote Method Invoke - 远程方法调用)过程的参数和返回值都必须实现的机制,
    • 而RMI是JavaEE的基础。因此序列化机制是JavaEE平台的基础。
  • 如果需要让某个对象支持序列化机制,则必须让对象所属的类及其属性是可序列化的。
  • 为了让某个类是可序列化的,该类必须实现以下两个接口之一。否则会抛出NotSerializableException异常。
    • Serializable /  Externalizable
  • 凡是实现Serializable 接口的类都有一个表示序列化版本标识符的静态变量:
    • private static final long serialVersionUID = 8537212141160296410L;
    • serialVersionUID用来表明类的不同版本间的兼容性。其目的是以序列化对象进行版本控制,有关各版本反序列化时是否兼容。
    • 如果没有显式定义静态变量,它的值是Java运行时环境根据类的内部细节自动生成的,若类的实例变量做了修改,serialVersionUID可能发生变化。
  • Java序列化机制是通过运行时判断类的serialVersionUID来验证版本一致性的。
    • 在进行反序列化时,JVM会把传来的字节流中serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化。
    • 否则就会出现序列化版本不一致的异常。(InvalidCastException)。
  • 示例: Person类 序列化的要求: 
    • 实现Serializable接口
    • 提供全局常量serialVersionUID
    • Person内部所有属性都必须是可序列化的。(默认情况下,基本数据类型可序列化)
    @Test
    public void test3() throws IOException, ClassNotFoundException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hello5.txt"));
        oos.writeObject(new String("天安门"));
        oos.flush();
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hello5.txt"));
        Object obj = ois.readObject();
        String s = (String) obj;
        System.out.println(s); //天安门
    }

 

public class Person implements Serializable {

    private static final long serialVersionUID = -5015176660385488112L;
    private String name;
    private int age;
    private Pet pet;
    // 省略其他代码
}

 

    @Test
    public void test3() throws IOException, ClassNotFoundException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("hello5.txt"));
        oos.writeObject(new String("天安门"));
        //java.io.NotSerializableException: Person   java.io.NotSerializableException: Pet
        oos.writeObject(new Person("Tom",23, new Pet("猫猫"))); 
        oos.flush();
        oos.close();

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("hello5.txt"));
        Object obj = ois.readObject();
        String s = (String) obj;
        System.out.println(s); //天安门
        Object obj2 = ois.readObject();
        Person person = (Person) obj2;
        System.out.println(person);
    }

 

 
 

(10)随机存取文件流

  • RandomAccessFile声明在java.io包下,但直接继承于java.lang.Object类。
    • 并且它实现了DataInput、DataOutput这两个接口,意味着这个类可以读也可以写。
  • RandomAccessFile类支持"随机访问"的方法,程序可以直接跳到文件的任意地方来读、写文件。
    • 支持只访问文件的部分内容
    • 可以向已存在的文件后追加内容
  • RandomAccessFile对象包含一个记录指针,用以标示当前读写处的位置。对象可以自由移动记录指针:
    • long getFilePointer():  获得文件记录指针的当前位置。
    • long seek(long pos):    将文件记录指针定位到pos位置。
  • 构造器
    • public RandomAccessFile(File file, String mode)
    • public RandomAccessFile(String file, String mode)
  • 创建RandomAccessFile 类实例需要指定一个mode参数,该参数指定RandomAccessFile的访问模式:
    • r:   以只读方式打开
    • rw:  打开以便读取和写入
    • rwd: 打开以便读取和写入; 同步文件内容的更新
    • rws: 打开以便读取和写入; 同步文件内容和元数据的更新
  • 如果模式为只读r,则不会创建文件,而是去读取一个已经存在的文件,如果不存在会出现异常。
  • 如果模式为rw读写,如果文件不存在则会去创建文件,如果存在则不会创建。
    @Test
    public void test4() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile(new File("桌面壁纸.jpg"),"r");
        RandomAccessFile raf2 = new RandomAccessFile(new File("桌面壁纸2.jpg"),"rw");

        byte[] bytes = new byte[1024];
        int len;
        while((len = raf1.read(bytes)) != -1){
            raf2.write(bytes,0,len);
        }
    }

 

seek()方法
    @Test
    public void test5() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile(new File("hello.txt"),"rw");
        raf1.seek(3);
        raf1.write("xyz".getBytes());  // 123456789  -->  123xyz789
        raf1.close();
    }

 

 
  @Test
    public void test6() throws IOException {
        RandomAccessFile raf1 = new RandomAccessFile(new File("hello.txt"),"rw");
        raf1.seek(3);

        StringBuilder stringBuilder = new StringBuilder((int)new File("hello.txt").length());
        byte[] buffer = new byte[20];
        int len;
        while((len = raf1.read(buffer)) != -1){
            stringBuilder.append(new String(buffer,0,len));
        }
        System.out.println(stringBuilder);

        FileInputStream fis = new FileInputStream(new File("hello.txt"));
        BufferedReader reader = new BufferedReader(new InputStreamReader(fis));
        char[] buffer2 = new char[10];
        int len2;
        String str2 = "";
        while((len2 = reader.read(buffer2)) != -1){
           str2 += new String(buffer2,0, len2);
        }
        System.out.println(str2);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer3 = new byte[10];
        int len3;
        while((len3 = fis.read(buffer3)) != -1){
            baos.write(buffer3,0,len3);
        }
        System.out.println(baos.toString());
    }

 

断点续传:
使用RandomAccessFile这个类,来实现一个多线程断点下载的功能。
下载前建立两个临时文件,一个是与被下载文件大小相同的空文件,另一个是记录文件指针的位置文件,
每次暂停时,保存上一次的指针,断点下载时,从上一次的地方下载,实现断点下载或上传的功能。
 
 
 

(11)NIO.2中Path、Paths、Files类的使用

(11.1)Java NIO概述

  • Java NIO(New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新的IO API,可以代替标准的Java IO API。
    • NIO与原来的IO有同样的作用和目的,但使用的方法完全不同。
    • NIO支持面向缓冲区的(IO是面向流的)、基于通道的IO操作。 NIO以更加高效的方式进行文件的读写操作。
  • Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套是网络编程NIO
  • java.nio.channels.Channel
    • FileChannel:         处理本地文件
    • SocketChannel:       TCP网络编程的客户端的Channel
    • ServerSocketChannel: TCP网络编程的服务器端的Channel
    • DatagramChannel:     UDP网络编程中发送端和接收端的Channel

(11.2)NIO.2 中 Path、Paths、Files类

  • 随着JDK 7的发布,Java 对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,称为NIO.2。
  • 早期Java只提供了一个File类来访问文件系统,但File类功能比较有限,提供的方法性能也不高。
    • 大多数方法在出错时仅返回失败,并不会提供异常信息。
  • NIO.2为了弥补不足,引入了Path接口,代表一个平台无关的平台路径,描述了目录结构中文件的位置。
    • Path可以看成是File类的升级版本,实际引用的资源也可以不存在。
    • import java.io.File; File file = new File("index.html");
    • import java.nio.file.Paht; import java.nio.file.Paths; Path path = Paths.get("index.html");
  • NIO.2 在java.nio.file包下提供了Files、Paths工具类
    • Files包含了大量静态的工具方法来操作文件;Paths包含了两个返回Path的静态工厂方法。
  • Paths类提供的静态get()方法来获取Path对象:
    • static Path get(String first, String... more): 用来将多个字符串串连成路径
    • static Path get(URI uri): 返回指定uri对应的Path路径
  • org.apache.commons.io.FileUtils

(11.3)Path接口

  • Path常用方法
    • String toString():               返回调用Path对象的字符串表示形式
    • boolean startsWith(String path): 判断是否以path路径开始
    • boolean endsWith(String path):   判断是否以path路径结束
    • boolean isAbsolute():            判断是否是绝对路径
    • Path getParent():                返回Path对象包含整个路径,不包含Path对象指定的文件路径
    • Path getRoot():                  返回调用Path对象的根路径
    • Path getFileName():              返回与调用Path对象关联的文件名
    • int getName(int idx):            返回指定索引位置idx的路径名称
    • Path toAbsolutePath():           作为绝对路径返回调用Path对象
    • Path resolve(Path p):            合并两个路径,返回合并后的路径对应的Path对象
    • File toFile():                   将Path转化为File类的对象

(11.4)File类的方法

  • java.nio.file.Files 用于操作文件或目录的工具类
  • Files常用方法:
    • Path copy(Path src, Path dest, CopyOption ... how):        文件的复制
    • Path createDirectory(Path path, FileAttribute<?>... attr): 创建一个目录
    • Path createFile(Path path, FileAttribute<?>... atrr):      创建一个文件
    • void deleteIfExists(Path path):     删除一个文件/目录,如果不存在,执行报错
    • void deleteIfExists(Path path):     Path对应的文件/目录如果存在,执行删除
    • Path move(Path src, Path dest, CopyOption... how): 将src 移动到dest位置
    • long size(Path path):                            返回path 指定文件的大小