IO 复习笔记

输入流,从源到流中;输出流,从流到目的地。

1. 操作文件:

    1).写入:FileOutputStream或者FileWriter

    2).读取:FileInputStream或者FileReader

    3).随机读写:RandomAccessFile

    4).文件属性:File

2. 通过Java IO中的PipedOutputStream和PipedInputStream创建管道。一个PipedInputStream流应该和一个PipedOutputStream流相关联。一个线程通过PipedOutputStream写入

    的数据可以被另一个线程通过相关联的PipedInputStream读取出来。

    关联方式:

    1). PipedOutputStream fos = new PipedOutputStream();

         PipedInputStream fis = new PipedInputStream();

    2). fis.connect(fos);

    3). fos.connect(fis);

3. 请记得,当使用两个相关联的管道流时,务必将它们分配给不同的线程。read()方法和write()方法调用时会导致流阻塞,这意味着如果你尝试在一个线程中同时进行读和写,可能会导致线程死锁。

4. 用ByteArrayInputStream或者CharArrayReader封装字节或者字符数组从数组中读取数据。也可以把数据写到ByteArrayOutputStream或者CharArrayWriter中。

5. System.in, System.out, System.err这3个流同样是常见的数据来源和数据流目的地。JVM启动的时候通过Java运行时初始化这3个流,所以你不需要初始化它们(尽管你可以在运行时替换掉它们)。

6. 某些类似PushbackInputStream 流的实现允许你将数据重新推回到流中,以便重新读取。然而你只能把有限的数据推回流中,并且你不能像操作数组那样随意读取数据。流中的数据只能够顺序访问。

7. 字节流通常以“stream”命名,比如InputStream和OutputStream。除了DataInputStream 和DataOutputStream 还能够读写int, long, float和double类型的值以外,其他流在一个操作时间内只能

    读取或者写入一个原始字节。字符流通常以“Reader”或者“Writer”命名。字符流能够读写字符(比如Latin1或者Unicode字符)。(不一定是两字节)

8. Java IO流是既可以从中读取,也可以写入到其中的数据流。正如这个系列教程之前提到过的,流通常会与数据源、数据流向目的地相关联,比如文件、网络等等。

9. 请注意,InputStream的read()方法返回一个字节,意味着这个返回值的范围在0到255之间(当达到流末尾时,返回-1),Reader的read()方法返回一个字符,意味着这个返回值的范围在0到65535之间

    (当达到流末尾时,同样返回-1)。这并不意味着Reade只会从数据源中一次读取2个字节,Reader会根据文本的编码,一次读取一个或者多个字节。

10. 一个Reader可以和一个InputStream相结合。如果你有一个InputStream输入流,并且想从其中读取字符,可以把这个InputStream包装到InputStreamReader中。把InputStream传递到

      InputStreamReader的构造函数中:

      Reader reader = new InputStreamReader(inputStream);

      在构造函数中可以指定解码方式。

11. 与Reader和InputStream类似,一个Writer可以和一个OutputStream相结合。把OutputStream包装到OutputStreamWriter中,所有写入到OutputStreamWriter的字符都将会

       传递给OutputStream。这是一个OutputStreamWriter的例子:

       Writer writer = new OutputStreamWriter(outputStream);

12. 流与Reader和Writer在结束使用的时候,需要正确地关闭它们。通过调用close()方法可以达到这一点。如果代码出现了异常,会发生什么呢?没错,这个InputStream对象就不会被关闭。

13. Try-with-resources

      In Java 7 you can write the code from the example above using the try-with-resource construct like this:

             private static void printFileJava7() throws IOException {

                      try(FileInputStream input = new FileInputStream("file.txt")) {

                      int data = input.read();

                      while(data != -1){

                              System.out.print((char) data);

                              data = input.read();

                      }

                  }

           }

14. 如果read()方法返回-1,意味着程序已经读到了流的末尾,此时流内已经没有多余的数据可供读取了。-1是一个int类型,不是byte或者char类型,这是不一样的。当达到流末尾时,你就可以关闭流了。

15. InputStream包含了2个从InputStream中读取数据并将数据存储到缓冲数组中的read()方法,他们分别是:

      int read(byte[])

      int read(byte, int offset, int length)

      一次性读取一个字节数组的方式,比一次性读取一个字节的方式快的多,所以,尽可能使用这两个方法代替read()方法。

16. write(byte)方法用于把单个字节写入到输出流中。OutputStream的write(byte)方法将一个包含了待写入数据的int变量作为参数进行写入。只有int类型的第一个字节会被写入, 其余位会被忽略。

      (译者注:写入低8位,忽略高24位)。

17. OutputStream同样包含了将字节数据中全部或者部分数据写入到输出流中的方法,分别是write(byte[])和write(byte[], int offset, int length)。

      write(byte[])把字节数组中所有数据写入到输出流中。

      write(byte[], int offset, int length)把字节数据中从offset位置开始,length个字节的数据写入到输出流。

18. OutputStream的flush()方法将所有写入到OutputStream的数据冲刷到相应的目标媒介中。比如,如果输出流是FileOutputStream,那么写入到其中的数据可能并没有真正写入到磁盘中。

      即使所有数据都写入到了FileOutputStream,这些数据还是有可能保留在内存的缓冲区中。通过调用flush()方法,可以把缓冲区内的数据刷新到磁盘(或者网络,以及其他任何形式的目标媒介)中。

19. 当你创建了一个指向已存在文件的FileOutputStream,你可以选择覆盖整个文件,或者在文件末尾追加内容。通过使用不同的构造函数可以实现不同的目的

20. RandomAccessFile允许你来回读写文件,也可以替换文件中的某些部分。FileInputStream和FileOutputStream没有这样的功能。创建一个RandomAccessFile在使用RandomAccessFile之前,

      必须初始化它。这是例子:

      RandomAccessFile file = new RandomAccessFile("c:\\data\\file.txt", "rw");

      请注意构造函数的第二个参数:“rw”,表明你以读写方式打开文件。请查阅Java文档获知你需要以何种方式构造RandomAccessFile。

      在RandomAccessFile中来回读写。在RandomAccessFile的某个位置读写之前,必须把文件指针指向该位置。通过seek()方法可以达到这一目标。可以通过调用getFilePointer()获得当前

      文件指针的位置。

21. File:检测文件是否存在,文件长度,重命名或移动文件,删除文件,检测某个路径是文件还是目录,读取目录中的文件列表

22. ByteArrayInputStream允许你从字节数组中读取字节流数据。ByteArrayOutputStream允许你以数组的形式获取写入到该输出流中的数据。

23. BufferedInputStream能为输入流提供缓冲区,能提高很多IO的速度。你可以一次读取一大块的数据,而不需要每次从网络或者磁盘中一次读取一个字节。特别是在访问大量磁盘数据时,

      缓冲通常会让IO快上许多。你可以给BufferedInputStream的构造函数传递一个值,设置内部使用的缓冲区设置大小(译者注:默认缓冲区大小8 * 1024B),就像这样:

      InputStream input = new BufferedInputStream(new FileInputStream("c:\\data\\input-file.txt"), 8 * 1024);

      这个例子设置了8KB的缓冲区。最好把缓冲区大小设置成1024字节的整数倍,这样能更高效地利用内置缓冲区的磁盘。

24. BufferedOutputStream可以为输出流提供缓冲区。可以构造一个使用默认大小缓冲区的BufferedOutputStream(译者注:默认缓冲区大小8 * 1024B),也可以手动设置缓冲区大小,代码如下:

      OutputStream output = new BufferedOutputStream(new FileOutputStream("c:\\data\\output-file.txt"), 8 * 1024);

      为了更好地使用内置缓冲区的磁盘,同样建议把缓冲区大小设置成1024的整数倍。需要手动flush()方法确保写入到此输出流的数据真正写入到磁盘或者网络中。

25. DataInputStream可以使你从输入流中读取Java基本类型数据,而不必每次读取字节数据。你可以把InputStream包装到DataInputStream中,然后就可以从此输入流中读取基本类型数据。

      DataOutputStream可以往输出流中写入Java基本类型数据

26. 如果你希望类能够序列化和反序列化,必须实现Serializable接口。

      ObjectInputStream能够让你从输入流中读取Java对象,而不需要每次读取一个字节。你可以把InputStream包装到ObjectInputStream中,然后就可以从中读取对象了,然后强制转换为对应的类型。

      ObjectOutputStream能够让你把对象写入到输出流中,而不需要每次写入一个字节。你可以把OutputStream包装到ObjectOutputStream中,然后就可以把对象写入到该输出流中了。

27. Java内部使用UTF8编码表示字符串。输入流中一个字节可能并不等同于一个UTF8字符。如果你从输入流中以字节为单位读取UTF8编码的文本,并且尝试将读取到的字节转换成字符,

      你可能会得不到预期的结果。

28. Writer的write(int c)方法,会将传入参数的低16位写入到Writer中,忽略高16位的数据。

29. InputStreamReader和OutputStreamWriter,这两个类把字节流转换成字符流,中间做了数据的转换,类似适配器模式的思想。

      InputStreamReader同样拥有其他可选的构造函数,能够让你指定将底层字节流解释成何种编码的字符流。OutputStreamWriter同样拥有将输出字节流转换成指定编码的字符流的构造函数。

30. FileReader拥有其他可选的构造函数,能够让你使用不同的方式读取文件,更多内容请查看官方文档。FileReader会假设你想使用你所使用的JVM的版本的默认编码处理字节流,但是这通常不是你想要的,

      你可以手动设置编码方案。如果你想明确指定一种编码方案,利用InputStreamReader配合FileInputStream来替代FileReader(译者注:FileReader没有可以指定编码的构造函数)。InputStreamReader可

      以让你设置编码处理从底层文件中读取的字节。处理文件都会碰到的一个问题是,当前写入的数据是覆盖原文件内容还是追加到文件末尾。当你创建一个FileWriter之后,你可以通过使用不同构造函数实现

      你的不同目的。

31. BufferedReader、BufferedWriter

32. PushbackInputStream,SequenceInputStream,PrintStream,PushbackReader,LineNumberReader,StreamTokenizer,PrintWriter,StringReader,StringWriter

      LineNumberReader是记录了已读取数据行号的BufferedReader。默认情况下,行号从0开始,当LineNumberReader读取到行终止符时,行号会递增。你可以通过getLineNumber()方法获取当前行号,

      通过setLineNumber()方法设置当前行数。setLineNumber()仅仅改变LineNumberReader内的记录行号的变量值,不会改变当前流的读取位置。流的读取依然是顺序进行,意味着你不能通过

      setLineNumber()实现流的跳跃读取

      StreamTokenizer可以识别标示符,数字,引用的字符串,和多种注释类型。你也可以指定何种字符解释成空格、注释的开始以及结束等。在StreamTokenizer开始解析之前,所有的功能都可以进行配置。

      StringReader能够将原始字符串转换成Reader:Reader reader = new StringReader("input string...");

      StringWriter能够以字符串的形式从Writer中获取写入到其中数据:

      StringWriter writer = new StringWriter(); 

      String data = writer.toString();

      StringBuffer dataBuffer = writer.getBuffer(); 

 


posted @ 2015-10-25 10:52  Jtianlin  阅读(412)  评论(0编辑  收藏  举报