Java IO

一. 输入和输出
  可将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,可以指定缓冲区的大小(可选的) / 本质上并不提供接口,只不过是向进程中添加缓冲区所必须的。与接口对象搭配

这里写图片描述

三.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.数据的来源和去处

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

字节字符
InputStreamReader,适配器InputStreamReader
OutputStreamWriter, 适配器OutStreamReader
FileInputStreamFileReader
FileOutputStreamFileWriter
StringBufferInputStream(已弃用)StringReader
无相应的类StringWriter
ByteArrayInputStreamCharArrayReader
ByteArrayOutputStreamCharArrayWriter
PipedInputStreamPipleReader
PipedOutputStreamPipedWriter

2.更改流的行为

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

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

字节过滤器字符过滤器
FilterOutputStreamFilterReader
FilterIntputStreamFilterWriter(抽象类,没有子类)
BufferedIntputStreamBufferedWriter
BufferedOutputStreamBufferedWriter
DataInputStream使用DataInputStream(除了当需要使用readLine()时以外,这时应该使用BufferedReader)
PrintStreamPrintWriter
LineNumberInputStream(已弃用)LineNumberReader
StreamTokenzierStreamTokenzier(使用接受Reader的构造器)
PushbackInputStreamPushbackReader

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

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

四.自我独立的类: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中常用的类

这里写图片描述

这里写图片描述

以上图片来源: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中,为’\’
这里写图片描述
此节内容转载自: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文件重点内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值