Java基础(十一) Stream I/O and Files

时间:2023-03-08 21:30:39

Java基础(十一) Stream I/O and Files

1. 流的概念

程序的主要任务是操纵数据。在Java中,把一组有序的数据序列称为流。

依据操作的方向,能够把流分为输入流和输出流两种。程序从输入流读取数据,向输出流写出数据。

     文件    输入流                     输出流           文件
内存 -------------> Java程序 ------------------> 内存
键盘 控制台
| |
数据源 数据目的地

Java I/O系统负责处理程序的输入和输出。I/O类库位于java.io包中,它对各种常见的输入流和输出流进行了抽象。

假设数据流中最小的数据单元是字节,那么称这样的流为字节流。假设数据流中最小的数据单元是字符,那么称这样的流为字符流。

  • 在I/O类库中。java.io.InputStream和java.io.OutputStream分别表示字节输入流和字节输出流;
  • java.io.Reader和java.io.Writer分别表示字符输入流和字符输出流。
  • 注意:它们四个都是抽象类(Reader/Writer/InputStream/OutStream)

2. 字节输入流和输出流

在java.io包中,java.io.InputStream表示字节输入流,java.io.OutputStream表示字节输出流。它们都是抽象类,不能被实例化。

InputStream类提供了一系列和读取数据有关的方法:

  • read(): 从输入流读取数据:有三种重载形式: 

    • int read(): 从输入流读取一个8位的字节(1字节是8位),把它转换为0-255之间的整数。并返回这一整数。

      假设遇到输入流的结尾,则返回-1;

    • int read(byte[] b): 从输入流读取若干个字节,把它们保存到參数b指定的字节数组中。

      返回的整数表示读取的字节数。假设遇到输入流的结尾,则返回-1;

    • int read(byte[] b, int off, int len): 从输入流读取若干个字节。把它们保存到參数b指定的字节数组中。

      返回的整数表示读取的字节数。參数off指定在字节数组中開始保存数据的起始下标,參数len指定读取的字节数目。返回的整数表示实现读取的字节数。假设遇到输入流的结尾,则返回-1;

    以上第一个read方法从输入流读取一个字节,而其余两个read方法从输入流批量读取若干字节。在从文件或键盘读数据时,採用后面两个read方法能够降低进行物理读文件或键盘的次数,因此能提高I/O操作的效率。

  • void close(): 关闭输入流,InputStream类本身的close()方法不运行不论什么操作。

    它的一些子类覆盖了close()方法,在close()方法中释放和流有关的系统资源。

  • int available(): 返回能够从输入流中读取的字节数目;
  • skip(long): 从输入流中跳过參数n指定数目的字节。
  • boolean markSupported(),void mark(int)。void reset(): 假设要从流中反复读入数据,
    • 先用markSupported()方法来推断这个流是否支持反复读入数据,假设返回true,则表明能够在流上设置标记。
    • 接下来调用mark(int readLimit)方法从流的当前位置開始设置标记。
    • 最后调用reset()方法。该方法使输入流又一次定位到刚才做了标记的起始位置。这样就能够反复读取做过标记的数据了。

OuputStream类提供了一系列和写数据有关的方法:

  • write(): 向输出流写入数据:有三种重载形式:

    • void write(int b): 向输出流写入一个字节;
    • void write(byte[] b): 把參数b指定的字节数组中的全部字节写到输出流;
    • void write(byte[] b, int off, int len): 把參数b指定的字节数组中的全部字节写到输出流,參数off指定字节数组的起始下标,从这个位置開始输出由參数len指定数目的字节;

    以上第一个write方法从输出流写入一个字节,而其余两个write方法从输出流批量写出若干字节。在向文件或控制台写数据时。採用后面两个write方法能够降低进行物理读文件或键盘的次数,因此能提高I/O操作的效率。

  • void close(): 关闭输出流。OutputStream类本身的close()方法不运行不论什么操作。

    它的一些子类覆盖了close()方法,在close()方法中释放和流有关的系统资源。

  • void flush(): OutputStream类本身的flush()方法不运行不论什么操作,它的一些带有缓冲区的子类(比方BufferedOutputStream和PrintStream类)覆盖了flush()方法。

    通过带缓冲区的输出流写数据时,数据先保存在缓冲区中。积累到一定程度才会真正写到输出流中。

    缓冲区通经常使用字节数组实现,实际上是指一块内存空间。flush()方法强制把缓冲区内的数据写到输出流中。

3. 经常使用到的字节输入流和输出流

  • in:输入流

    • ByteArrayInputStream: 读取byte类型的数组中的数据
    • FileInputStream: 从文件里读取数据。
    • PipedInputStream: (管道流)连接一个PipedOutputStream;
    • ObjectInputStream: 对象输入流;
    • StringBufferInputStream: 能够读取一个字符串,在API中已经过时
  • out: 输出流

    • ByteArrayOutputStream:
    • FileOutputStream
    • PipedoutputStream:
    • ObjectoutputStream

4. BufferedInputStream类

BufferedInputStream类覆盖了被过滤的输入流的读数据行为。利用缓冲区来提高读数据的效率。

BufferedInputStream类先把一批数据读入到缓冲区,接下来 read()方法仅仅须要从缓冲区内获取数据,就能降低物理性读取数据的次数。

  • BufferedInputStream(InputStream in)——參数in指定须要被过滤的输入流。
  • BufferedInputStream(InputStream in, int size)——參数in指定须要被过滤的输入流。參数size指定缓冲区的大小,以字节为单位。

5. DataInputStream 类

DataInputStream 实现了DataInput接口,用于读取基本类型数据,如int, float, long, double和boolean等。

  • readByte()——从输入流中读取1个字节,指它转换为byte类型的数据;
  • readLong()——从输入流中读取8个字节,指它转换为long类型的数据;
  • readFloat()——从输入流中读取4个字节,指它转换为float类型的数据。
  • readUTF()—— 从输入流中读取1到3个字节,指它转换为UTF-8字符编码的字符串。

6. 管道输入类:PipedInputStream 类

管道输入流从一个管理输出流中读取数据。通常由一个线程向管理输出流写数据,由还有一个线程从管理输入流中读取数据。两个线程能够用管道来通信。

7. Reader and Writer概述

InputStream和OutputStream类处理的是字节流。也就是说,数据流中的最小单元为一个字节,它包含8个二进制位。在很多应用场合,Java应用程序须要读写文本文件。在文本文件里存放了採用特定字符编码的字符。为了便于读于各种字符编码的字符。java.io包中提供Reader/Writer类。它们分别表示字符输入流和字符输出流。

在处理字符流时,最基本的问题是进行字符编码的转换。Java语言採用Unicode字符编码。对于每个字符,Java虚拟机会为其分配两个字节的内存。而在文本文件里,字符有可能採用其它类型的编码,比方GBK和UTF-8字符编码等。

Reader类能够将输入流中採用其它编码类型的字符转换为Unicode字符,然后在内存中为这些Unicode字符分配内存。Writer类能够把内存中的Unicode字符转换为其它编码类型的字符,再写到输出流中。

在默认情况下,Reader和Writer会在本地平台的字符编码和Unicode字符编码之间进行编码转换。


Writer的write()方法
使用Unicode字符编码的字 ------------> 使用本地平台的字符编码的字符串
符串(内存中) <------------ (数据源/数据目的地)
Reader的read()方法

假设要输入或输出採用特定类型编码的字符串。能够使用InputStreamReader类和OutputStreamWriter类。

在它们的构造方法中能够指定输入流或输出流的字符编码。

                    OutputStreamWriter的write()方法
使用Unicode字符编码的字 ---------------> 使用本地平台的字符编码的字符串
符串(内存中) <-------------- (数据源/数据目的地)
InputStreamReader的read()方法

因为Reader和Writer採用了字符编码转换技术。Java I/O系统能够正确地訪问採用各种字符编码的文本文件,还有一方面。在为字符分配内存时,虚拟机对字符统一採用Unicode字符编码,因此Java程序处理字符具有平*立性。

  • CharArrayReader : 把字符数组转换为Reader,从字符数组中读取字符;
  • BufferedReader : 过滤器,为其它Reader提供读缓冲区。此外,它的readLine()方法能够读入一行字符串;
  • StringReader : 把字符串转换为Reader。从字符串中读取字符;
  • PipedReader : 连接一个PipedWriter;
  • PushBackReader : 能把读到的字符压回到缓冲区中,通经常使用做编译器的扫描器,在程序中一般非常少使用它。
  • InputStreamReader : 过滤器。把InputStream转换为Reader,能够指定字符编码。
  • FileReader : 从文件里读取字符;

8. InputStreamReader类

InputStreamReader类把InputStream类型转换为Reader类型,构造方法:

  • InputStreamReader(InputStream in): 依照本地平台的字符编码读取输入流中的字符;
  • InputStreamReader(InputStream in, String charsetName): 依照指定的字符编码读取输入流中的字符;

9. FileReader类

InputStreamReader的一个子类,用于从文件里读取字符数据。该类仅仅能依照本地平台的字符编码来读取数据,用户不能指定其它字符编码类型。

  • FileReader(File file): 參数file指定须要读取的文件;
  • FileReader(String name): 參数name指定须要读取的文件的路径;

10. BufferedReader类

  1. Reader类的read()方法每次都从数据源读入一个字符。BufferedReader带有缓冲区,它能够先把一批数据读到缓冲区内,
  2. 接下来的操作都从缓冲区内获取数据,避免每次都从数据源读取数据并进行字符编码转换,从而提高读操作的效率。

    • BufferedReader的readLine()方法能够一次读入一行字符,以字符形式返回。
    • BufferedReader(Reader in): 指定被修饰的Reader类;
    • BufferedReader(Reader in, int sz): 參数in指定被装饰的Reader类,參数sz指定缓冲区的大小,以字符为单位。

11. File类

File类提供管理文件或文件夹的方法。File实例表示真实文件系统中的一个文件或者文件夹。

  1. 构造方法

    • File(String pathname): 參数pathname表示文件路径或者文件夹路径。
    • File(String parent, String child): 參数parent表示根路径,參数child表示子路径;
    • File(File parent, String child): 參数parent表示根路径,參数child表示子路径。

    仅仅处理一个文件,使用第一个构造方法;如处理一个公共文件夹的若干子文件夹或文件。那么使用第二个或者第三个更方便。

  2. 普通方法

    • boolean createNewFile():创建一个新的文件,假设文件已经存在。则创建失败(返回false),否则创建成功(返回true)。
    • boolean delete():删除文件或者空文件夹
    • boolean mkdir()/mkdirs():创建一个或者多个文件夹(连续创建)->假设该文件夹的父文件夹不存在话,那么还会创建全部的父文件夹。
    • boolean renameTo(File destination):文件的改名
    • boolean canRead()/canWrite():推断指定的文件能否读取或者写入数据
    • boolean exists():推断指定的文件或者文件夹是否存在
    • String[] list():返回指定文件夹下全部文件名称或者子文件夹名所组成的字符串数组
    • long lastModified():返回指定文件最后一次被改动的时间(从1970年1月1日凌晨12点到这个文件的改动时间之间所经历的毫秒数)
    • String getPath()/getAbsolutePath():返回指定文件或者文件夹的路径和绝对路径
    • String getCanonicalPath(): 获取该File对象所代表的文件或者文件夹的正规路径
    • String getParent()/getName():返回指定文件或者文件夹的父文件夹(没有返回null)和名字
   File f = new File(".\\test.txt"));
System.out.println(f.getCanonicalPath()); //c:\mypath\test.txt
System.out.println(f.getAbsolutePath()); //c:\mypath\ .\test.txt
System.out.println(f.getPath()); //.\test.txt
if(!f.exists()) f.createNewFile());

12. FileInputStream and FileOutputStream

  • 当创建一个FileInputStream对象的时候,文件必须存在以及是可读的
    • FileInputStream(File file)
    • FileInputStream(String name)
  • 当创建一个FileOutputStream对象的时候。能够创建一个新的文件,也能够覆盖一个已经存在的同名文件。

    • FileOutputStream(File file)
    • FileOutputStream(File file, boolean append)

假设要创建的文件已经存在。能够选择向旧文件加入新的内容(append为true)或者新的内容覆盖旧文件的内容(append为false)。

注意:在这里写个com.briup.ch14.CopyTime.java

13. FileReader and FileWriter

  • 读写字符文件方便
  • 构造器
    • FileReader(File file)
    • FileReader(String name)
    • FileWriter(File file)
    • FileWriter(String filename)
FileReader:new FileReader(“d:/back/string.txt”) =
new InputStreamReader(new FileInputStream(“d:/back/string.txt”));
FileWriter:new FileWriter(“d:/back/string.txt”) =
new InputStreamWriter(new FileOutputStream(“d:/back/string.txt”));

14. PrintWriter

能够输出基本数据类型、对象、字符(字符数组)和字符串,可是不能输出字节流。

  • PrintWriter类能够取代桥和BufferedWriter
  • PrintStream类既能够输出字节流也能够输出字符流或者字符串

15. Reading and Writing with RandomAccessFile

  • 实现数据的输入和输出
  • 用它能够提供读写文件的功能
  • 提供通过一个文件指针从文件的某一个断点開始读写数据的功能
  • 构造器
    • RandomAccessFile(File file, String mode)
    • RandomAccessFile(String filename, String mode)
    • mode能够选择读、写和读写的方式
  • 方法:
    • read()/write()
    • seek(long pointer) 定位到文件的断点

16. 对象的序列化和反序列化

对象的序列化: 把对象写到一个输出流;

对象的反序列化:从一个输入流中读取一个对象。

要点:

  • 对象的持久化
  • 仅仅是一个对象的数据被序列化(将对象的数据序列化成字节流)
  • 标识为transit的数据不能被序列化 比如:transit 类名 表示该类不能被序列化 或者transit 字段
  • 要序列化的对象必须实现java.io.Serializable接口

对象的序列化主要用于:

  • 网络中传输的是字节流的数据,网络中对象的传输,是将对象的数据经过序列化后转换成字节流。
  • 将对象数据序列化到文件里。将对象数据转换成字节流存储到文件里。
  • 将对象转换为字节流叫做对象的序列化,将字节流转换为对象叫做对象的反序列化。

ObjectInputStream 和 ObjectOutputStream(对象输入和输出流。能够读写基本数据类型和对象)

  • ObjectInputStream 和 ObjectOutputStream为应用程序提供对象的持久化存储
  • 一个ObjectInputStream 能够反序列化通过ObjectOutputStream写入的基本数据类型和对象
  • 构造器
    • ObjectInputStream(InputStream in)
    • ObjectOutputStream(OutputStream out)
  • 方法
    • readObject()/writeObject() 将对象写入到输出流中或者从输入流中读取对象