欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java IO

程序员文章站 2022-06-13 22:28:55
...

一. 输入和输出
  可将Java库的IO类分割为输入与输出两个部分。通过继承,从InputStream(输入流)衍生的所有类都拥有名为read()的基本方法,用于读取单个字节或者字节数组。类似地,从OutputStream衍生的所有类都拥有基本方法write(),用于写入单个字节或者字节数组。Java类库的设计者将所有与输入有关的类都从InputStream继承,而与输出有关的所有类都从OutputStream继承。

*1.InputStream的类型

  InputStream的作用是标志那些从不同起源地产生输入的类。这些起源地包括(每个都有一个相关的InputStream子类):
  (1) 字节数组
  (2) String对象
  (3) 文件
  (4) “管道”。
  (5) 一系列其他流,以便我们将其统一收集到单独一个流内。
  (6) 其他起源地,如Internet连接等。

  除此之外,FilterInputStream 也属于InputStream 的一种类型,用它可为“破坏器”类提供一个基础类,以便将属性或者有用的接口同输入流连接到一起。

功能 构造器参数 / 如何使用
ByteArrayInputStream 允许内存中的一个缓存区作为InputStream使用 缓冲区,字节将从中取出 / 作为一种数据源:将其同一个FilterInputStream对象相连以提供一个有用的接口。
StringBufferInputStream 将String 转换成InputStream 字符串。底层实现实际使用StringBuffer / 作为一种数据源:通过将其同一个FilterInputStream 对象相连以提供一个有用的接口
FileInputStream 用于从文件读取信息 字符串,表示文件名、文件或FileDescriptor对象 / 作为一种数据源:将其同一个FilterInputStream对象相连以提供一个有用的接口。
PipedInputStrem 产生用于写入相关PipleOutputStream的数据。实现“管道化”概念 PipleOutputStream / 作为多线程中的数据源:将其与FilterInputStream 对象相连以提供一个有用的接口
SequenceInputStream 将两个或更多的InputStream 对象转换成单个InputStream 两个InputStream 对象或一个容纳InputStream对象的容器Enumeration / 作为一种数据源:将其与FilterInputStream 对象相连以提供一个有用的接口
FilterInputSTream 抽象类,作为“装饰器”的接口。其中“装饰器”为其他的InputStream类提供有用功能,见下表FilterInputStream 见下表FilterInputStream

*2.OutputStream的类型

  这一类别包括的类决定了我们的输入往何处去:一个字节数组(但没有String;假定我们可用字节数组创建一个);一个文件;或者一个“管道”。

功能 构造器参数 / 如何使用
ByteArrayInputStream 在内存中创建缓冲区。所有送往“流”的数据都要放置在此缓存区 缓冲区初始化尺寸(可选的) / 用于指定数据的目的地:将其与FilterInputStream对象相连以提供有用接口
FileOutputStream 用于将信息写至文件 字符串,表示文件名、文件或FileDescription对象 / 用于指定数据的目的地:将其与FilterInputStream对象相连以提供有用接口
PipleOutputStream 任何写入其中的信息都会自动作为相关PipedInputStrem 的输出。实现管道化的概念 PipedInputStrem / 用于指定数据的目的地:将其与FilterInputStream对象相连以提供有用接口
FilterOutStream 抽象类,作为“装饰器”的接口。其中,“装饰器”为其他OutputStream提供有用功能 见下表FilterOutStream

二.增添属性和有用的接口

  FilterInputStream 和FilterOutputStream 提供了相应的装饰器接口,用于控制一个特定的输入流(InputStream)或者输出流(OutputStream)。它们分别是从InputStream 和OutputStream 衍生出来的。此外,它们都属于抽象类,在理论上为我们与一个流的不同通信手段都提供了一个通用的接口。事实上,FilterInputStream 和FilterOutputStream 只是简单地模仿了自己的基础类,它们是一个装饰器的基本要求。

1.通过FilterInputStream从InputStream里读入数据

  FilterInputStream 类要完成两件全然不同的事情。其中,DataInputStream 允许我们读取不同的基本类型数据以及String 对象(所有方法都以“read”开头,比如readByte()readFloat()等等)。伴随对应的DataOutputStream,我们可通过数据“流”将基本类型的数据从一个地方搬到另一个地方。这些“地方”是由下表那些类决定的。

  其他FilterInputStream类则在内部修改InputStream的行为方式:是否缓冲,是否保留它所读过的行(允许我们查询行数或设置行数),以及是否把单一字符推回输入流等等。最后两个类看起来更像是为了创建一个编译器(它们被添加进来可能是为了对“用Java构建编译器”实验提供支持),因此我们一般编程中不会用到它们。

FilterInputStream类型

功能 构造器参数 / 如何使用
DataInputStream 与DatatOutputStream搭配使用,因此我们可以按照可移植方式从流读取基本数据类型(int 、char、long等) InputStream / 包含用于读取基本类型数据的全部接口
BufferedInputStream 使用它可以防止每次读取时都得进行实际写操作。代表“使用缓冲区” InputStream,可以指定缓冲区的大小(可选的)/ 本质上不提供接口,只不过向进程中添加缓冲区所必须的。与接口对象搭配。
LineNumberInputStream 跟踪输入流中的行号,可用getLineNumber()和SetLineNumber(int) InputStream / 仅增加了行号,因此可能要与接口对象搭配使用
PushbackInputStream 具有“能弹出一个字节的缓冲区”。因此可以将读到的最后一个字符回退。 InputStream / 通常作为编译器的扫描器,之所以包含在内是因为Java编译器的需要,我们可能永远用不到

2. 通过FilterOutputStream向OutputStream写入

  与DataInputStream对应的是DataOutputStream,它可以将各种基本数据类型以及String对象格式化输出“流”中,这样以来,任何机器上的任何DataInputStream都能够读取它们。所有方法都以“write”开头,例如writeByte()、writeFloat()等。
  PrintStream最初的目的表示为了可视化格式打印所有的基本数据类型以及String对象。这和DataOutpuStream不同,后者的目的是将数据元素置入“流”中,使DataOutputStream能够可移植地重构它们。
  PrintStream可能会有些问题,因为它捕捉了所有IOException(因此,我们必须使用checkError()自行测试错误状态,如果出现错误它返回true)。另外,PrintStream也未完全国际化,不能以平台无关的方式处理换行动作(这些问题在printWrite中得到了解决)。
  BufferOutputStream是一个修改过的OutputStream,它对数据流使用缓冲技术;因此当我们每次向流写入时,不必每次都进行实际的物理写动作。所以在进行输出时,我们可能更经常的是使用它。

FilterOutputStream:

功能 构造器参数 / 如何使用
DataOutputStream 与DatatOutputStream搭配使用,因此我们可以按照可移植方式向流中写入基本数据类型(int 、char、long等) OutputStream / 包含用于写入基本数据类型的全部接口
PrintStream 用于产生格式化输出。其中DataOutputStream处理数据的存储,PringStream处理显示 OutputStream / 可以用boolean指示是否在每次换行时清空缓冲区(可选的)应该是对OutputStream对象的“final”封装。可能会经常使用它。
BufferedOutputStream 使用它以避免每次发送数据时都要进行实际的写操作。代表“使用缓冲区”。 OutputStream,可以指定缓冲区的大小(可选的) / 本质上并不提供接口,只不过是向进程中添加缓冲区所必须的。与接口对象搭配

Java IO

三.Reader和Writer

   InputStreamOutputStream在以面向字节形式的I/O中仍可以提供极有价值的功能,ReaderWriter则提供兼容Unicode与面向字符的I/O功能。另外:

1) Java1.1向InputStreamOutputStream的继承层次结构中添加了一些新类,所以显然这两个类是不会被取代的。
2)有时我们必须把来自于“字节”层次结构中的类和“字符”层次结构中的类结合起来使用。我了实现这个目的,要用到“适配器”(adapter)类:InputStreamReader可以把InputStream转换为Reader,而OutputStreamWriter可以把OutputStream转换为Writer。
  设计ReaderWriter继承层次结构主要是为了国际化。老的I/O流继承层次结构仅支持8位字节流,并且不能很好的处理16位的Unicode字符。由于Unicode用于字符国际化(Java本身的char也是16位的Unicode),所以添加ReaderWriter继承层次结构就是为了在所有的I/O操作中都支持Unicode。

补充:字符编码

编码表的由来
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。

常见的编码表

ASCII 码

ASCII 码总共有128个,用1个字节的低七位表示,0~31 是控制字符如换行、回车、删除等,32~126 是打印字符,可以通过键盘输入并且能够显示出来。

ISO-8859-1

128个字符显然是不够用的,于是ISO组织在ASCII 码基础上又制定了一系列标准来拓展 ASCII 编码,它们是ISO-8859-1 至 ISO-8859-15,其中 ISO-8859-1 涵盖了大多数西欧语言字符,所以应用的最广泛。ISO-8859-1 仍然是单字节编码,它总共能表示 256 个字符。

GB2312

GB2312 的全称是 《信息技术 中文编码字符集》,它是双字节编码,总的编码范围是 A1~F7,其中A1 ~ A9 是符号区,总共包含682个字符; B0~F7 是汉字区,包含6763个汉字。

GBK

全称是《汉字内码扩展规范》,它的出现是为了拓展 GB2312 ,并加入更多的汉字。它的编码是和GB2312 兼容的,也就是说用GB2312 编码的汉字可以用GBK 来解码,并且不会有乱码。

UTF-16

说到UTF 必须提到 Unicode ,ISO 试图创建一个全新的超语言字典,世界上所有的语言都可以通过这个字典来相互翻译。UTF-16 具体定义了Unicode 在计算中的存取方法。UTF-16 用两个字节来表示 Unicode 的转化格式,采用定长的表示方法,即不论什么字符都可以用两个字节表示。

UTF-8

UTF-16 存在存储空间浪费。UTF-8 采用了一种变长技术,每个编码区域有不同的字码长度。不同类型的字符可以由1~6 个字节组成。如果是一个字节,最高位为0,则表示这是 1 个 ASCII 字符,可见,所有ASCII 编码已经是UTF-8了。

编码:字符串à字节数组
解码:字节数组à字符串
转换流的编码应用
可以将字符按指定编码格式存储。
可以对文本数据按指定编码格式来解读。
指定编码表的动作由构造器完成。

1.数据的来源和去处

  下面的表展示了在两个继承层次结构中,信息的来源和去处之间的对应关系。

字节 字符
InputStream Reader,适配器InputStreamReader
OutputStream Writer, 适配器OutStreamReader
FileInputStream FileReader
FileOutputStream FileWriter
StringBufferInputStream(已弃用) StringReader
无相应的类 StringWriter
ByteArrayInputStream CharArrayReader
ByteArrayOutputStream CharArrayWriter
PipedInputStream PipleReader
PipedOutputStream PipedWriter

2.更改流的行为

  对于InputStreamOutputStream来说,我们会使用FilterInputStream
和FilterOutputStream的装饰器子类来修改“流”以满足特殊要求。Reader和Writer的类继承层次结构继续沿用相同的思想———但是并不完全相同。

  在下表中,相对于前一个表格来说,左右之间的对应关系的近似程度更加粗略一些。造成这种差别的原因是因为类的组织形式不同;尽管BufferedOutputStream是FilterOutputStream的子类,但是BufferedWriter并不是FilterWriter的子类(尽管FilterWriter是抽象类,没有任何子类,把它放在那里也只是把它作为一个占位符,或仅仅让我们不会对他所在的地方产生疑惑)。然而,这些类的接口却十分相似。

字节过滤器 字符过滤器
FilterOutputStream FilterReader
FilterIntputStream FilterWriter(抽象类,没有子类)
BufferedIntputStream BufferedWriter
BufferedOutputStream BufferedWriter
DataInputStream 使用DataInputStream(除了当需要使用readLine()时以外,这时应该使用BufferedReader)
PrintStream PrintWriter
LineNumberInputStream(已弃用) LineNumberReader
StreamTokenzier StreamTokenzier(使用接受Reader的构造器)
PushbackInputStream PushbackReader

  有一点很清楚,无论我们何时使用readLine(),都不应该使用DataInputStream(这会遭到编译器的强烈反对),而应该使用BufferedReader。除了这一点外,DataInputStream仍是I/O类库的首选成员。

  为了更容易的过度到使用PrintWriter,它提供了一个既能接受Writer对象又能接受任何OutputStream对象的构造器。PrintWriter的格式化接口实际上是与PrintStream相同。
Java IO

四.自我独立的类:RandomAccessFile

  RandomAccessFile适用于由大小已知的记录组成的文件,以便我们能用seek()从一条记录移至另一条;然后读取或修改那些记录。各记录的长度并不一定相同;只要知道它们有多大以及置于文件何处即可。
有用。
  首先,我们有点难以相信RandomAccessFile 不属于InputStream 或者OutputStream 分层结构的一部分。除了恰巧实现了DataInput 以及DataOutput(这两者亦由DataInputStream 和DataOutputStream 实现)接口之外,它们与那些分层结构并无什么关系。它甚至没有用到现有InputStream 或OutputStream 类的功能——采用的是一个完全不相干的类。该类属于全新的设计,含有自己的全部(大多数为固有)方法。之所以要这样做,是因为RandomAccessFile 拥有与其他IO 类型完全不同的行为,因为我们可在一个文件里向前或向后移动。不管在哪种情况下,它都是独立运作的,作为Object 的一个“直接继承人”使用。从根本上说,RandomAccessFile 类似DataInputStream 和DataOutputStream 的联合使用。其中,getFilePointer()用于了解当前在文件的什么地方,seek()用于移至文件内的一个新地点,而length()用于判断文件的最大长度。此外,构建器要求使用另一个自变量(与C 的fopen()完全一样),指只是随只是随机读(”r”),还是读写兼施(”rw”)。这里没有提供对“只写文件”的支持。也就是说,假如是从DataInputStream 继承的,那么RandomAccessFile 也有可能能很好工作。还有更难对付的。很容易想象我们有时要在其他类型的数据流中搜索,比如一个ByteArrayInputStream,但搜索方法只有RandomAccessFile 才会提供。而后者只能针对文件才能操作,不能针对数据流操作。此时,BufferedInputStream 确实允许我们标记一个位置(使用mark(),它的值容纳于单个内部变量中),并用reset()重设那个位置。但这些做法都存在限制,并不是特别有用。

五.Java IO中常用的类

Java IO

Java IO

以上图片来源:https://www.cnblogs.com/ylspace/p/8128112.html

六 .File类

  • java.io.File类:文件和目录路径名的抽象表示形式,与平台无关
  • File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。
  • File对象可以作为参数传递给流的构造函数
  • File类的常见构造方法:public File(String pathname)

以pathname为路径创建File对象,可以是绝对路径或者相对路径,如果pathname是相对路径,则默认的当前路径在系统属性user.dir中存储。

public File(String parent,String child)
以parent为父路径,child为子路径创建File对象。

File的静态属性String separator存储了当前系统的路径分隔符。
在UNIX中,此字段为’/’,在Windows中,为’\’
Java IO
此节内容转载自:https://www.cnblogs.com/baixl/p/4170599.html

七.IO流的典型应用

1.缓冲输入文件.
   如果想要打开一个文件用于字符输入,可以使用String或File对象作为文件名的FileReader。为了提高速度,我么希望对那个文件进行缓冲,那么我们将所产生的引用传给一个BufferedReader构造器,由于BufferedReader也提供readLine()方法,所以这是我们的最终对象和进行读取的接口。当readLine()返回null时,你就打到了文件的末尾。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class BufferedReaderFile {

    public static String read(String fileName) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        String s;
        StringBuffer buffer = new StringBuffer();
        while ((s = reader.readLine()) != null) {
            buffer.append(s + "\n");
        }
        reader.close();
        return buffer.toString();
    }

    public static void main(String[] args) throws IOException {
        System.out.println(read("BufferedReaderFile.java"));
    }
}

2.从内存输入
  在下面的示例中,从上面的BuffereredInputFile.read()读入的String结果被用来创建一个StringReader。然后调用read()每次读取一个字符,并把它发送到控制台。

public static String read(String fileName) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        String s;
        StringBuffer buffer = new StringBuffer();
        while ((s = reader.readLine()) != null) {
            buffer.append(s + "\n");
        }
        reader.close();
        return buffer.toString();
    }

    public static void main(String[] args) throws IOException {
        StringReader buffer = new StringReader(read("MemoryInput.java"));
        int c;
        while ((c = buffer.read()) != -1) {
            System.out.println((char) c);
        }
    }
}

注意read()是以int形式返回下一字节,因此必须类型转换为char才能正确打印。

3.格式化内存输入
  要读取格式化数据,可以使用DataInputStream,它是一个面向自己的I/O类(不是面向字符的)。因此我们必须使用InputStream类而不是Reader类。当然,我们可以用InputStream以字节的形式读取任何数据(例如一个文件),不过,在这里使用的是字符串。

public class FormattedMemoryInput {

    public static String read(String fileName) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        String s;
        StringBuffer buffer = new StringBuffer();
        while ((s = reader.readLine()) != null) {
            buffer.append(s + "\n");
        }
        reader.close();
        return buffer.toString();
    }

    public static void main(String[] args)  throws IOException{
        try {
            DataInputStream input = new DataInputStream(
                new ByteArrayInputStream(read("FormattedMemoryInput.java").getBytes()));
            while (true)
                System.out.println((char) input.readByte());
        } catch (EOFException e) {
            System.out.println("End of stream");  //  读到文件结尾时会抛出异常
        }
    }
}

  必须为ByteArrayInputStream提供字节数组,为了产生该数组String包含了一个可以实现此项工作的getBytes()方法。所产生的ByteArrayInpuStream是一个适合传递给DataInputStream的InputStream。
  如果我们从DataInputStream用readByte()一次一个字节的读取,那么任何字节的值都是合法的结果,因此返回值不能用来检测输入是否结束。相反,我们可以使用available()方法查看还有多少可供存取的字符。下面这个例子演示了怎样一次一个字节地读取文件:

public class TestEOF {

    public static void main(String[] args) throws IOException {
        DataInputStream in = new DataInputStream(
            new BufferedInputStream(new FileInputStream("TestEOF.java")));
        while (in.available() != 0)  
            System.out.println((char) in.readByte());
    }
}

  注意,available()的工作方式会随着所读取的媒介类型的不同而有所不同,字面意思就是“在没有阻塞的情况下所能读取的字节数”。对于文件,这意味着整个文件;但是对于不同类型的流,可能就不是这样的,因此要谨慎使用。

  我们来看看哪些地方可以用available()方法来获取文件大小,进而用来定义缓冲数组的长度

1.在本地文件文件中,这里我一般是直接使用的。

2.网络中的文件

  a.比如web 中http 里面的文件流里面,第一种情况有content-length,那么小文件的情况,我们是直接可以通过request 获取该属性,也就知道文件的大小了。

   b.在某些情况下,比如文件比较大,采用采用分段方式,长连接的方式发送,不能一次知道文件大小,http 的header 里面就没有上面的content-length 属性,而是变成了Transfer-Encoding: chunked属性,这表示分段发送信息,但是对整个文件的接受,可以通过一些标志位,或者一些超时限制等方法处理,这里不具体研究了。

   c.socket 传输文件,是没重写available方法的,也就是说我们不能通过这个知道流的字节数,一般情况下,我们可以先发送一段自定义的header 过去,描述文件大小,然后再循环持续获取流信息。

  我们也可以通过捕获异常(EOFException)来检测输入的末尾。但是,使用异常进行流控制,被认为是对异常特性的错误使用。

4.基本的文件输出

  FileWriter对象可以向文件写入数据。首先,创建一个与指定文件连接的FileWriter。实际上,我们通常会用BufferedWriter将其包装起来用以缓冲输出(尝试移除此包装来感受对性能的影响——缓冲往往能显著地增加IO操作的性能)

public class BasicFileOutput {

    static final String file = "BasicFileOutput.java";

    public static String read(String fileName) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        String s;
        StringBuffer buffer = new StringBuffer();
        while ((s = reader.readLine()) != null) {
            buffer.append(s + "\n");
        }
        reader.close();
        return buffer.toString();
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new StringReader(read(file)));

        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
        int lineCount = 1;

        String s;

        while ((s = reader.readLine()) != null) {
            out.println(lineCount++ + ":" + s);
        }
        out.close();
        System.out.println(read(file));
    }
}

  一旦读完输入数据流,readLine()会返回null。我们可以看到要为out显示调用close()如果我们不为所有的输出文件调用close(),就会发现缓冲区内容不会被刷新清空,那么它们也就不完整。

文本文件输出的快捷方式

JavaSE5 在PrintWriter中添加了一个辅助构造器,使得你不必在每次希望创建文本文件并向其中写入时,都去执行所有的装饰工作。下面是这种快捷方式重写的BasicFileOutput.java

public class BasicFileOutput {

    static final String file = "BasicFileOutput.java";

    public static String read(String fileName) throws IOException {
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        String s;
        StringBuffer buffer = new StringBuffer();
        while ((s = reader.readLine()) != null) {
            buffer.append(s + "\n");
        }
        reader.close();
        return buffer.toString();
    }

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new StringReader(read(file)));

        PrintWriter out = new PrintWriter(file);  // 这地方未执行所有的装饰工作
        int lineCount = 1;

        String s;

        while ((s = reader.readLine()) != null) {
            out.println(lineCount++ + ":" + s);
        }
        out.close();
        System.out.println(read(file));
    }
}

查看PrintWriter的带有String类型的参数的构造函数,源码如下:

public PrintWriter(String fileName) throws FileNotFoundException {
        this(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))),
             false);
    }

通过源码可知装饰工作已在源码中完成了。

5.存储和恢复数据

  PrintWriter可以对数据进行格式化(既根据数据的实际类型输出和或写入),以便人们的阅读。但是为了输出可供一个“流”恢复的数据,我们需要用DatatOutputStream写入数据,并用DataInputStream恢复数据。当然,这些流可以是任何形式,但在下面的示例中使用的是一个文件,并且对于读和写都进行了缓存处理。注意DataOutputStream和DataInputStream是面向字节的,因此要使用InputStream和OutputStream

public class StoringAndRecoveringData {

    public static void main(String[] args) throws IOException {
        DataOutputStream out = new DataOutputStream(
            new BufferedOutputStream(new FileOutputStream("D:\\xx.txt")));

        out.writeDouble(2423.343);
        out.writeInt(1314);
        out.writeChars("d");
        out.writeUTF("utf-8");
        out.writeDouble(4545.5656);
        out.close();

        DataInputStream in = new DataInputStream(
            new BufferedInputStream(new FileInputStream("D:\\xx.txt")));
        System.out.println(in.readDouble());
        System.out.println(in.readInt());
        System.out.println(in.readChar());
        System.out.println(in.readUTF());
        System.out.println(in.readDouble());
        // 下面读取的顺序必须和上面写入的顺序一样
    }
}

  如果我们使用DataOutputStream写入数据,Java保证我们可以使用DataInputStream准确地读取数据——无论读和写数据的平台多么不同。

6.读写随机访问文件

   使用RandomAccessFile,类似于组合使用了DatInpuStream和DataOutputStream(因为它实现了相同的接口:DataInput和DataOutput)。另外我们可以看到,利用seek()可以在文件中到处移动,并修改文件中的某个值。
   在使用RandomAccessFile时,你必须知道文件排版,这样才能准确地操作它。RandomAccessFile拥有读取基本类型和UTF-8字符串的各种具体方法。

public class UsingRandomAccessFile {

    static String file = "rtest.dat";

    static void display() throws IOException {

        RandomAccessFile rf = new RandomAccessFile(file, "r");

        for (int i = 0; i < 7; i++) {
            System.out.println("Value " + i + " : " + rf.readDouble());
        }
        System.out.println(rf.readUTF());
        rf.close();
    }

    public static void main(String[] args) throws IOException {
        RandomAccessFile rf = new RandomAccessFile(file, "rw");
        for (int i = 0; i < 7; i++) {
            rf.writeDouble(i * 1.44);
        }
        rf.writeUTF("the end of the file");

        rf.close();
        display();
        rf = new RandomAccessFile(file, "rw");
        rf.seek(5 * 8);
        rf.writeDouble(47.0001);
        rf.close();
        display();
    }
}

   display()方法打开了一个文件,并以double值的形式显示了其中的七个元素。在main()中,首先创建了文件,然后打开并修改了它。因为double总是8字节长,所以为了用seek()查找第5个双精度值,你只需5*8来产生查找位置。

   正如先前所指,RandomAccessFile除了实现DataInput和DataOutput接口之外,有效地与I/O继承层次结构的其他部分实现了分离。因为它不支持装饰,所以不能将其与InputStream及OutputStream子类的任何部分组合起来。

   可以自行选择的是第二个构造器参数:我们可指定以“只读”(r)方式或“读写”(rw)方式打开一个RandomAccessFile文件重点内容

相关标签: Java I/O