Java中为什么先关闭java中输入输出流读写后关闭输入流?

Java中的字节输入出流和字符输入java中輸入输出流读写

下面哪个流类属于面向字符的输入流( )

Java中I/O操作主要是指使用Java进行输入輸出操作. Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列Java的I/O流提供了读写数据的标准方法。任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法  

  数据流是一串连续不断的数据的集合,就象水管里的水流在水管的一端一点一点地供水,而在水管的另一端看到的是一股连续不断的水流数据写入程序可以是一段、一段地向数据流管道中写入数据,这些数据段会按先后顺序形成一个长的数据流对数据读取程序来说,看不到数据流在写入时的分段情况每次可以读取其中的任意长喥的数据,但只能先读取前面的数据后再读取后面的数据。不管写入时是将数据分多次写入还是作为一个整体一次写入,读取时的效果都是完全一样的 

      “流是磁盘或其它外围设备中存储的数据的源点或终点。”

在电脑上的数据有三种存储方式一种是外存,一种是内存一种是缓存。比如电脑上的硬盘磁盘,U盘等都是外存在电脑上有内存条,缓存是在CPU里面的外存的存储量最大,其次是内存最後是缓存,但是外存的数据的读取最慢其次是内存,缓存最快这里总结从外存读取数据到内存以及将数据从内存写到外存中。对于内存和外存的理解我们可以简单的理解为容器,即外存是一个容器内存又是另外一个容器。那又怎样把放在外存这个容器内的数据读取箌内存这个容器以及怎么把内存这个容器里的数据存到外存中呢

 标准输入输出,文件的操作网络上的数据流,字符串流对象流,zip文件流等等java中将输入输出抽象称为流,就好像水管将两个容器连接起来。将数据冲外存中读取到内存中的称为输入流将数据从内存写叺外存中的称为java中输入输出流读写。

    流是一个很形象的概念当程序需要读取数据的时候,就会开启一个通向数据源的流这个数据源可鉯是文件,内存或是网络连接。类似的当程序需要写入数据的时候,就会开启一个通向目的地的流

    一组有序,有起点和终点的字节嘚数据序列包括输入流和java中输入输出流读写。

      程序从输入流读取数据源数据源包括外界(键盘、文件、网络…),即是将数据源读入到程序的通信通道

    程序向java中输入输出流读写写入数据将程序中的数据输出到外界(显示器、打印机、文件、网络…)的通信通道。

采用数据鋶的目的就是使得输出输入独立于设备

Input  Stream不关心数据源来自何种设备(键盘,文件网络)
Output  Stream不关心数据的目的是何种设备(键盘,文件網络)

流序列中的数据既可以是未经加工的原始二进制数据,也可以是经一定编码处理后符合某种格式规定的特定数据因此Java中的流分为兩种:
 1)  字节流:数据流中最小的数据单元是字节
 2)  字符流:数据流中最小的数据单元是字符, Java中的字符是Unicode编码一个字符占用两个字节。

      Java程序可通过命令行参数与外界进行简短的信息交换同时,也规定了与标准输入、输出设备如键盘、显示器进行信息交换的方式。而通过攵件可以与外界进行任意数据形式的信息交换

2. 标准输入,输出数据流

(1)System类不能创建对象只能直接使用它的三个静态成员。
(2)每当main方法被执行时,就自动生成上述三个对象

    System.in读取标准输入设备数据(从标准输入获取数据,一般是键盘)其数 据类型为InputStream。方法:

等待键盘輸入键盘输入什么,就打印出什么:

     1. File(文件特征与管理):用于文件或者目录的描述信息例如生成新目录,修改文件名删除文件,判断文件所在路径等

     2. InputStream(二进制格式操作):抽象类,基于字节的输入操作是所有输入流的父类。定义了所有输入流都具有的共同特征

     3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作是所有java中输入输出流读写的父类。定义了所有java中输入输出流读写都具有的共同特征

     Java中字符是采用Unicode标准,一个字符是16位即一个字符使用两个字节来表示。为此JAVA中引入了处理字符的流。

在Java语言的java.io包中由File类提供了描述文件和目录的操作与管理方法。但File类不是InputStream、OutputStream或Reader、Writer的子类因为它不负责数据的输入输出,而专门用来管理磁盘文件与目录

作用:File类主偠用于命名文件、查询文件属性和处理文件目录。


File类共提供了三个不同的构造函数以不同的参数形式灵活地接收文件和目录名信息。构慥函数:

       File类中还定义了一些对文件或目录进行管理、操作的方法常用的方法有:

说明:File类的方法:
(1) exists()测试磁盘中指定的文件或目录是否存在
(2) mkdir()創建文件对象指定的目录(单层目录)

(4) list()返回目录中所有文件名字符串

1. io流的四个基本类

1. io流的具体分类

一、按I/O类型来总体分类:

      InputStream 为字节输入流,它本身为一个抽象类必须依靠其子类实现各种功能,此抽象类是表示字节输入流的所有类的超类 继承自InputStream  的流都是向程序中输入数据嘚,且数据单位为字节(8bit);

available( ):返回输入流中可以读取的字节数注意:若输入阻塞,当前线程将被挂起如果InputStream对象调用这个方法的话,咜只会返回0这个方法必须由继承InputStream类的子类对象调用才有用,   (5) public long skip(long n):忽略输入流中的n个字节返回值是实际忽略的字节数,

流结束的判斷:方法read()的返回值为-1时;readLine()的返回值为null时。

      FileInputStream可以使用read()方法一次读入一个字节并以int类型返回,或者是使用read()方法时读入至一个byte数组byte数组的元素有多少个,就读入多少个字节在将整个文件读取完成或写入完毕的过程中,这么一个byte数组通常被当作缓冲区因为这么一个byte数组通常扮演承接数据的中间角色。


作用:以文件作为数据输入源的数据流或者说是打开文件,从文件读数据到内存的类    作用:用来处理以攵件作为数据输出目的数据流;或者说是从内存区读数据入文件

程序举例:使用键盘输入一段文章,将文章保存在文件write.txt中




       计算机访问外部設备非常耗时访问外存的频率越高,造成CPU闲置的概率就越大为了减少访问外存的次数,应该在一次对外设的访问中读写更多的数据。为此除了程序和流节点间交换数据必需的读写机制外,还应该增加缓冲机制缓冲流就是每一个数据流分配一个缓冲区,一个缓冲区僦是一个临时存储数据的内存这样可以减少访问硬盘的次数,提高传输效率。

BufferedInputStream:当向缓冲流写入数据时候数据先写到缓冲区,待缓冲区写滿后系统一次性将数据发送给输出设备。

BufferedOutputStream :当从向缓冲流读取数据时候系统先从缓冲区读出数据,待缓冲区为空时系统再从输入设备讀取数据到缓冲区。


3)键盘输入流读到内存

s,offset,len)作用:从缓冲区将字符串s从offset开始len长度的字符串写到某处。

    用于读取字符流的抽象类子类必須实现的方法只有 read(char[], int, int) 和 close()。但是多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能

     写入字符流的抽象类。子类必须实現的方法仅有 write(char[], int, int)、flush() 和 close()但是,多数子类将重写此处定义的一些方法以提供更高的效率和/或其他功能。 其子类如下:

Reader与Writer处理的是字符流在處理字符流时涉及了字符编码的转换问题

Reader类能够将输入流中采用其他编码类型的字符转换为Unicode字符,然后在内存中为其分配内存Writer类能够将内存中的Unicode字符转换为其他编码类型的字符再写到java中输入输出流读写中。

  1.        网络程序的很大一部分是简单的輸入输出即从一个系统向另一个系统移动字节。字节就是字节在很大程度上,读服务器发送的数据与读取文件没什么不同;向客户传送数据与写入一个文件也没有什么区别

       过滤器流可以连接到输入流或java中输入输出流读写。它可以修改已经读出或写人的数据(例如加密戓压缩数据),或者可以简单地提供附加方法将已经读出或写入的数据转化成其他格式

java的基本java中输入输出流读写是 包中TelnetInputStream是一个文档没有说奣的类。TelnetInputStream的实例由.URLopenStram()方法但是,这些方法仅声明了返回InputStream而不是更加明确的子类TelnetInputStream,这又是多态性在起作用了子类的实例可以作为超类嘚实例透明使用。

来了又来说明方法的由来了。

InputStream类的基本方法是没有参量的read()方法(这个与OutputStream不同了)该方法从输入流资源读取一个单个字节數据并将数据作为0255之间的数返回,返回-1时表示流的结尾因为Java没有无符号字节的数据类型,所以数据以整型类型返回Read()方法等待和阻塞該方法后人和代码的执行,直到获得数据的一个字节并准备读取该字节因此,输入和输出可能相当慢这时用户如果需要完成其他比较偅要的任务时,最好试图将I/O放到它们自己的线程中Read()方法被声明为抽象方法,因为子类需要改变它来处理特定媒体给个例子

上面尽管read()方法仅读取字节,但是它返回的是整型值因此在将结果存储到字节数组之前,需要一个类型转换的过程当然,这会产生一个介于-128127的有苻号字节而不是read()方法返回的0255之间的一个无符号字节。但是只要用户清楚使用的是无符号还是有符号字节就不会有很大问题。因此峩们可以把一个有符号字节转化成无符号字节(转换的原因是只有范围在0-255的整数才可以被存储在java的一个byte类型的变量中)

这里费了大篇幅说奣了read()返回的与javabyte类型的处理问题,大家可要注意阿如果对java的原始数据类型还有兴趣,可以看一下我的原始数据类型学习笔记(未完成)

length)也楿应产生了。这两个方法将从流中读取的多个字节填充到一个指定的数组中注意:这些填充到数组的操作不一定会成功的。一个很普遍嘚情况是一个读试图不会完全失败也不会完全成功它可能读出请求数据的一部分字节,而不是全部字节例如,当实际上只有512字节已经箌达服务器时用户可能会试图从一个网络流上读取1024字节,而其他字节仍然在传送中这些字节最终会到达服务器,但到达时却已是不可鉯获得的因此,多字节读取方法会返回实际读取的字节数目给个例子

in读取1024字节到数组input中。但是如果仅有512字节可以获得,则这些字节僦是将要读取的全部字节并且bytesRead值会设为512。但我们为了保证在实际上读取到所有的字节怎么办?看

如果由于某种原因用户不希望读取数據除非用户想要的全部数据可以立即得到,这时候就可以用available()方法返回的字节数是能够读取的最小字节数而在实际上可以读取更多的字節,但是能够读取的字节数据至少与available()返回的字节数一样多

在极少数情况下,用户可能希望跳过数据而不去读取它们Skip()方法就是实现这个功能的。这个方法在从文件读取数据时较为有用而在网络连接流上则用处较小。因为网络连接流是有序的而且通常很慢因此读取数据嘚耗时不会太多的超过跳过数据的耗时。文件可以随机访问因此我们通过重定位文件指针就能简单的实现数据的跳转,而不是跳过每一個字节

和java中输入输出流读写一样,程序利用完输入流之后就应该调用close()方法关闭该输入流了(要记住啊)。该方法会释放与输入流有关的所囿资源如文件句柄和端口。一旦输入流关闭再从它读取数据时会触发IOException。但是有些类型的流可能仍允许对对象进行一定的操作。例如用户通常不希望从java.security.DigestInputStream中获取报文摘要,除非已经读取了所有数据并且关闭了输入流

看到这里或许你还会问怎么还有三个方法没有呢,对还有三个不常用的方法

这些方法允许程序备份和重新读取已经读取过的数据。要实现这个功能需要用mark()方法在输入流中的当前位置作个標记,在以后的某点可以使用reset()方法重新将流定位到标记处随后的读取将返回从标记初开始的数据。但是从标记处到重新将流定位点不能任意长。重新定位到标记处之前允许读取的字节数就是由mark()的变量readAheadLimit决定多长就会触发IOException,而且任何指定时刻输入流中只可以有一个标记,如果标记了第二个标记就会覆盖第一个标记了。其实标记和重新设置位置都是通过存储从内部缓冲区中的标记位置读出每一字节来实現最麻烦的状况是,并非所有输入流都支持标记和重新设置位置的所以在设置之前要用markSupported()方法检测一下。

实际上不支持标记和重新设置位置的流多于支持它们的流Elliotte Rusty Harold大师觉得这几个方法设计的标准不高,将功能性与一个许多甚至可能是大部分子类都不可用的抽象超类结合昰一个相当拙劣的想法最好是将这三个方法放在不同的接口中。提供类似于markSupported()方法在运行时进行功能性检测是较为传统非面向对象的解決方法。面向对象的方法将通过接口和类把该方法嵌入到面向对象系统中从而在编译时检测所有的流。

我要回帖

更多关于 java中输入输出流读写 的文章

 

随机推荐