输入/输出流

  • 在Java API中,可以从其中读入一个字节序列的对象称做输入流,而可以向其中写入一个字节序列的对象称做输出流。这些字节序列的来源地和目的地可以是文件,而且通常都是文件,但是也可以是网络连接,甚至是内存块。抽象类InputStreamOutputStream构成了输入/输出(I/O)类层次结构的基础。
  • 因为面向字节的流不便于处理以Unicode形式存储的信息,所以从抽象类ReaderWriter中继承出来了一个专门用于处理Unicode字符的单独的类层次结构。这些类拥有的读入和写出操作都是基于两个字节的Char值的(即,Unicode码元),而不是基于byte值的。

一.读写字节

  • InputStream类有一个抽象方法:abstract int read() 这个方法读入一个字节,并返回读入的字节,或者在遇到输入源结尾时返回-1。在设计具体的输入流类时,必须覆盖这个方法以提供适用的功能,例如,在FileInputStream类中,这个方法将从某个文件中读入一个字节,而System.in(它是InputStream的一个子类的预定义对象)却是从标准输入中读入信息,即控制台或重定向的文件。

System.in 标准”输入流。 这个流已经存在打开并准备提供输入数据。 通常这个流对应于键盘输入或指定的其他输入源主机环境或用户。

  • InputStream类还有若干个非抽象的方法,它们可以读入一个字节数组,或者跳过大量的字节。这些方法都要调用抽象的read方法,因此,各个子类都只需覆盖这一方法。
  • 与此类似,OutputStream类定义了 abstract void write(int b)它可以向某个输出位置写出一个字节。readwrite方法在执行时都将阻塞。这使得在这两个方法等待指定的流变为可用的这段时间里,其他的线程就有机会去执行有用的工作。
  • available方法使我们可以去检查当前可读入的字节数量,并且保证代码不被阻塞。
try(FileInputStream in = new FileInputStream("C:\\Users\\whz\\Desktop\\岗位要求.txt")) {
            int bytesAvailable = in.available();
            if(bytesAvailable > 0){
                byte[] data = new byte[bytesAvailable];
                in.read(data);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
  • 当完成对输入/输出流的读写时,应该通过调用close方法来关闭它,这个调用会释放十分有限的操作系统资源。如果一个应用程序打开了过多的输入/输出流而没有关闭,那么系统资源将被耗尽。关闭一个输出流的同时还会冲刷用于该输出流的缓冲区:所有被临时置于缓冲区中,以便用更大的包的形式传递的字节在关闭输出流时都将被送出。特别是,如果不关闭文件,那么写出字节的最后一个包可能将永远也得不到传递。当然,我们还可以用flush方法来认为地冲刷这些输出。
  • 即使某个输入/输出流类提供了适用原生的read和write功能的某些具体方法,应用系统的程序员还是很少使用它们,因为大家感兴趣的数据可能包含数字、字符串和对象,而不是原生字节。
  • 我们可以使用众多的从基本的InputStreamOutputStream类导出的某个输入/输出类,而不只是直接使用字节。

二.完整的流家族

  • 把输入/输出流家族中的成员按照它们的使用方法来进行划分,这样就形成了处理字节和字符的两个单独的层次结构。
  • 首先来看InputStreamOutputStream的层次结构。
    输入流与输出流的层次结构
  • 要想读写字符串和数字,就需要功能更加强大的子类,例如,DataInputStreamDataOutputStream可以以二进制格式读写所有的基本Java类型。最后,还包含了多个有用的输入/输出流,例如,ZipInputStreamZipInputStream可以以常见的ZIP压缩格式读写文件。
  • 另一方面,对于Unicode文本,可以使用抽象类Reader和Writer的子类。
    Reader和Writer的层次结构
  • ReaderWriter类的基本方法与InputStreamOutputStream中的方法类似
abstract int read()
abstract void writer(int c)
  • read方法将返回一个Unicode码元(一个在 0 ~ 65535 之间的整数),或者在碰到文件结尾时返回-1。writer方法在被调用时,需要传递一个Unicode码元。

三.组合输入/输出流过滤器

  • FileInputStreamFileOutputStream可以提供附着在一个磁盘文件上的输入流和输出流,我们只需向其构造器提供文件名或文件的完整路径名。例如:
FileInputStream fin = new FileInputStream("C:\\Users\\whz\\Desktop\\岗位要求.txt");
  • 这里使用绝对路径的写法,读取文件。还可以使用相对路径的写法,通过System.getProperty("user.dir");获取当前用户工作目录。
  • 考录到不同系统的兼容性,文件路径中的分割符号可以使用File.separator来替换。如
FileInputStream fin = new FileInputStream("C:"+File.separator+"Users"
										+File.separator+"whz"+File.separator
										+"Desktop"+File.separator+"岗位要求.txt");
  • 如果只有DataInputStream,那么就只能读入数值类型,如:
DataInputStream din = ...;
double x = din.readDouble();
  • 但是正如FileInputStream没有任何读入数值类型的方法一样,DataInputStream也没有任何从文件中读取数据的方法。
  • Java使用了一种灵巧的机制来分离这两种职责。某些输入流(例如FileInputStream和由URL类的openStream方法返回的输入流)可以从文件和其他更外部的位置上获取字节,而其它的输入流(例如DataInputStream)可以将字节组装到更有用的数据类型中。Java程序员必须对二者进行组合。例如,为了从文件中读入数字,首先需要创建一个FileInputStream,然后将其传递给DataInputStream的构造器。
DataInputStream din = new DataInputStream(
				new FileInputStream("C:\\Users\\whz\\Desktop\\岗位要求.txt"));
char x = din.readChar();
  • InputStream/OutputStream结构图中有FilterInputStreamFilterOutStream类。这些文件的子类用于向处理字节的输入/输出流添加额外的功能。
  • 可以通过嵌套过滤器来添加多重功能。例如,输入流在默认情况下是不被缓冲区缓存的,也就是说,每个对read的调用都会请求操作系统再分发一个字节。相比之下,请求一个数据块并将置于缓冲区中会显得更加高效。如果想使用缓冲机制,以及用于文件的数据输入方法,那么就需要:
DataInputStream din = new DataInputStream(
                 new BufferedInputStream(
                     new FileInputStream("C:\\Users\\whz\\Desktop\\岗位要求.txt")));
  • 注意,这里把DataInputStream置于构造器链的最后,这是因为我们希望使用DataInputStream的方法,并且希望它们能够使用带缓冲机制的read方法。
  • 有时当多个输入流链接在一起时,需要跟踪各个中介输入流。例如,当读入输入时,经常需要预览下一个字节,以了解它是否是你想要的值。Java提供了用于此目的的PushbackInputStream:
PushbackInputStream pbin = new PushbackInputStream(
                    new BufferedInputStream(
                    new FileInputStream("C:\\Users\\whz\\Desktop\\岗位要求.txt")));
  • 现在可以预读下一个字节:
int b = pbin.read();
  • 并且在它并非你所期望的值时将其推回流中。
pbin.unread(b);
  • 但是读入和推回是可应用于可回推输入流的仅有的方法。入股希望能够预先浏览并且还可以读入数字,那么你就需要一个既是可回推输入流,又是一个数据输入流的引用。
PushbackInputStream pbin = null;
            BufferedInputStream bis = null;
            DataInputStream din = new DataInputStream(
                    pbin = new PushbackInputStream(
                    bis= new BufferedInputStream(
                         new FileInputStream("C:\\Users\\whz\\Desktop\\岗位要求.txt"))));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值