参考:

在Java中,把这些不同类型的输入、输出源抽象为流(Stream),其中输入或输出的数据称为数据流(Data Stream),用统一的接口来表示。

IO流的分类

数据流是指一组有顺序的、有起点和终点的字节集合。

输入流与输出流

按照流的流向分,可以分为输入流和输出流。注意:这里的输入、输出是针对程序来说的。
输出:把程序(内存)中的内容输出到磁盘、光盘、显示器等设备中。
输入:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。

字节流与字符流

按处理数据单位不同分为字节流和字符流。
字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码。
字符流:每次读取(写出)两个字节,有中文时,使用该流就可以正确传输显示中文。

1字符 = 2字节; 1字节(byte) = 8位(bit); 一个汉字占两个字节长度。

节点流与处理流

按照流的角色划分为节点流和处理流。
节点流:从或向一个特定的地方(节点)读写数据。如FileInputStream。
处理流(包装流):是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。

注意:一个IO流可以既是输入流又是字节流又或是以其他方式分类的流类型,是不冲突的。比如FileInputStream,它既是输入流又是字节流还是文件节点流。

字节流与字符流的区别

字节流在操作时本身不会用到缓冲区(内存),是文件本身直接操作的;而字符流在操作时使用了缓冲区,通过缓冲区再操作文件。
image.png
image.png

字节流与字符流的使用场景

字节流一般用来处理图像,视频,以及PPT,Word类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等。字节流可以用来处理纯文本文件,但是字符流不能用于处理图像视频等非文本类型的文件。

IO 流总览

Java IO 流有4个抽象基类:

字节流 字符流
输入流 InputStream 字节输入流 Reader 字符输入流
输出流 OutputStream 字节输出流 Writer 字符输出流

其他流都是继承于这四大基类的。下图是Java IO 流的整体架构图:

Java IO流总结 - 图3

字符流

Writer:字符输出流

Java IO流总结 - 图4

Writer 是字符输出流的基类,Writer 的主要方法如下:

  1. Writer append (char c) //将指定的字符附加到此输出流
  2. Writer append (CharSequence csq) //将指定的字符序列附加到此输出流
  3. Writer append (CharSequence csq, int start, int end) //将指定字符序列的子序列附加到此输出流
  4. abstract void close () //关闭流,先刷新
  5. abstract void flush () //刷新流
  6. void write (char[] cbuf) // 写入(输出)一个字符数组。
  7. abstract void write (char[] cbuf, int off, int len) 写入(输出)字符数组的一部分
  8. void write (int c) //写一个字符
  9. void write (String str) //写一个字符串
  10. void write (String str, int off, int len) //写一个字符串的一部分

我们知道 IO 流主要是用于操作文件的,但是从上图中我们发现 Writer 的直接子类中好像并没有直接操作文件,但是细心的你注意到,在 Writer 的子类 OutputStreamWriter 的子类中有一个类叫做 FileWriter,这个类是可以用于操作文件的。

FileWriter

FileWriter 的构造方法

  1. public class FileWriter extends OutputStreamWriter {
  2. /**
  3. * Constructs a FileWriter object given a file name.
  4. *
  5. * @param fileName String The system-dependent filename.
  6. * @throws IOException if the named file exists but is a directory rather
  7. * than a regular file, does not exist but cannot be
  8. * created, or cannot be opened for any other reason
  9. */
  10. public FileWriter(String fileName) throws IOException {
  11. super(new FileOutputStream(fileName));
  12. }
  13. /**
  14. * Constructs a FileWriter object given a file name with a boolean
  15. * indicating whether or not to append the data written.
  16. *
  17. * @param fileName String The system-dependent filename.
  18. * @param append boolean if <code>true</code>, then data will be written
  19. * to the end of the file rather than the beginning.
  20. * @throws IOException if the named file exists but is a directory rather
  21. * than a regular file, does not exist but cannot be
  22. * created, or cannot be opened for any other reason
  23. */
  24. public FileWriter(String fileName, boolean append) throws IOException {
  25. super(new FileOutputStream(fileName, append));
  26. }
  27. /**
  28. * Constructs a FileWriter object given a File object.
  29. *
  30. * @param file a File object to write to.
  31. * @throws IOException if the file exists but is a directory rather than
  32. * a regular file, does not exist but cannot be created,
  33. * or cannot be opened for any other reason
  34. */
  35. public FileWriter(File file) throws IOException {
  36. super(new FileOutputStream(file));
  37. }
  38. /**
  39. * Constructs a FileWriter object given a File object. If the second
  40. * argument is <code>true</code>, then bytes will be written to the end
  41. * of the file rather than the beginning.
  42. *
  43. * @param file a File object to write to
  44. * @param append if <code>true</code>, then bytes will be written
  45. * to the end of the file rather than the beginning
  46. * @throws IOException if the file exists but is a directory rather than
  47. * a regular file, does not exist but cannot be created,
  48. * or cannot be opened for any other reason
  49. * @since 1.4
  50. */
  51. public FileWriter(File file, boolean append) throws IOException {
  52. super(new FileOutputStream(file, append));
  53. }
  54. /**
  55. * Constructs a FileWriter object associated with a file descriptor.
  56. *
  57. * @param fd FileDescriptor object to write to.
  58. */
  59. public FileWriter(FileDescriptor fd) {
  60. super(new FileOutputStream(fd));
  61. }
  62. }

FileWriter 的方法列表

  1. Writer append (CharSequence csq); //将指定的字符序列附加到此输出流。
  2. Writer append (CharSequence csq, int start, int end); 将指定字符序列的子序列附加到此输出流。
  3. void close (); // 关闭流,先刷新。
  4. void flush (); // 刷新流。
  5. String getEncoding (); //返回此流使用的字符编码的名称。
  6. void write (char[] cbuf, int off, int len); //写入字符数组的一部分。
  7. void write (int c); //写一个字符
  8. void write (String str, int off, int len); //写一个字符串的一部分。

FileWriter 方法使用

例 1:创建一个文件 demo.txt,然后向里面写入字符串 abcde

  1. package com.hanliukui.example;
  2. import java.io.FileWriter;
  3. import java.io.IOException;
  4. public class FileWriterDemo {
  5. public static void main(String[] args) {
  6. FileWriter fileWriter = null;
  7. try {
  8. //(1) 创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。
  9. //(2) 而且该文件会被创建到指定目录下。如果该目录下已有同名文件,将被覆盖。
  10. //(3) 如果不存在,会创建一个新文件。
  11. //(4) 第二个参数为true时,表示追加写入,默认false
  12. fileWriter = new FileWriter("D://111.txt",true);
  13. // 获取流使用的编码格式
  14. String encoding = fileWriter.getEncoding();
  15. System.out.println("此FileWriter使用的编码格式是:"+encoding);
  16. // 写入字符串
  17. fileWriter.write("1111111111");
  18. fileWriter.flush();
  19. // 写入字符
  20. fileWriter.write('c');
  21. fileWriter.flush();
  22. // 写入字符数组
  23. fileWriter.write(new char[]{'1','2','3','4'});
  24. fileWriter.flush();
  25. // 写入字符串子串
  26. fileWriter.write("0123456789",1,6);
  27. fileWriter.flush();
  28. // 写入字符数组子数组
  29. fileWriter.write(new char[]{'1','2','3','4','5','6','7','8','9'},1,6);
  30. // 刷新缓存区
  31. // 刷新流对象中的缓冲中的数据。
  32. // 将数据刷到目的地中
  33. fileWriter.flush();
  34. } catch (IOException e) {
  35. e.printStackTrace();
  36. }finally {
  37. try {
  38. if (fileWriter!=null) {
  39. // 关闭流,但是关闭之前会刷新一次内部的缓冲中的数据。
  40. // 将数据刷到目的地中。
  41. // 和flush区别:flush刷新后,流可以继续使用,close刷新后,会将流关闭。
  42. fileWriter.close();
  43. }
  44. } catch (IOException e) {
  45. e.printStackTrace();
  46. }
  47. }
  48. }
  49. }

BufferedWriter

BufferedWriter 是缓冲字符输出流。它继承于 Writer。
BufferedWriter 的作用是为其他字符输出流添加一些缓冲功能,使用 BufferedWriter 可以提高我们写入文件的效率。
BufferedWriter 属于处理流。

BufferedWriter 的构造方法

  1. private static int defaultCharBufferSize = 8192;
  2. // 创建使用默认大小的输出缓冲区的缓冲字符输出流。
  3. public BufferedWriter(Writer out) {
  4. this(out, defaultCharBufferSize);
  5. }
  6. // 创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。
  7. BufferedWriter (Writer out, int sz);

BufferedWriter 的方法列表

  1. void close(); 关闭流,先刷新。
  2. void flush(); 刷新流。
  3. void newLine(); 写一行行分隔符。
  4. void write(char[] cbuf, int off, int len); 写入字符数组的一部分。
  5. void write(int c); 写一个字符
  6. void write(String s, int off, int len); 写一个字符串的一部分。

BufferedWriter 的方法使用

  1. package com.hanliukui.example.charstream.writer;
  2. import java.io.BufferedWriter;
  3. import java.io.FileWriter;
  4. import java.io.IOException;
  5. public class BufferedWriterDemo {
  6. public static void main(String[] args) {
  7. FileWriter fileWriter = null;
  8. BufferedWriter bufferedWriter = null;
  9. try {
  10. fileWriter = new FileWriter("D://111.txt");
  11. // 为了提高字符写入流效率。加入了缓冲技术。
  12. bufferedWriter = new BufferedWriter(fileWriter);
  13. char[] c={'a','b','c','d','e'};
  14. bufferedWriter.append("f");
  15. bufferedWriter.write(c);
  16. bufferedWriter.flush();
  17. bufferedWriter.newLine();
  18. bufferedWriter.flush();
  19. bufferedWriter.append("123456789");
  20. bufferedWriter.flush();
  21. } catch (IOException exception) {
  22. exception.printStackTrace();
  23. }finally {
  24. if (fileWriter!=null){
  25. try {
  26. fileWriter.close();
  27. } catch (IOException e) {
  28. e.printStackTrace();
  29. }
  30. }
  31. if (bufferedWriter!=null){
  32. try {
  33. bufferedWriter.close();
  34. } catch (IOException e) {
  35. e.printStackTrace();
  36. }
  37. }
  38. }
  39. }
  40. }

CharArrayWriter

CharArrayReader 用于写入字符,它继承于 Writer。操作的数据是以字符为单位。

该类实现了一个可用作字符输出流的字符缓冲区,当数据写入流时,缓冲区自动增长,请注意在此类上调用close()无效,并且可以在流关闭后调用此类的方法而不生成IOException。

CharArrayWriter 的构造函数

  1. public class CharArrayWriter extends Writer {
  2. /**
  3. * The buffer where data is stored.
  4. */
  5. protected char buf[];
  6. /**
  7. * The number of chars in the buffer.
  8. * 这里count = 0, 基本数据类型 int 默认值0
  9. */
  10. protected int count;
  11. /**
  12. * 创造默认缓冲区大小的CharArrayWriter对象
  13. */
  14. public CharArrayWriter() {
  15. this(32);
  16. }
  17. /**
  18. * 创造指定缓冲区大小的CharArrayWriter对象
  19. */
  20. public CharArrayWriter(int initialSize) {
  21. if (initialSize < 0) {
  22. throw new IllegalArgumentException("Negative initial size: "
  23. + initialSize);
  24. }
  25. buf = new char[initialSize];
  26. }
  27. ......
  28. }

CharArrayWriter 的方法列表

  1. CharArrayWriter append(char c); 将指定的字符附加到此流
  2. CharArrayWriter append(CharSequence csq); 将指定的字符序列附加到此流。
  3. CharArrayWriter append(CharSequence csq, int start, int end); 将指定字符序列的子序列附加到此流。
  4. void close(); 关闭流。
  5. void flush(); 冲洗流。
  6. void reset(); 重置缓冲区,以便您可以再次使用它,而不会丢弃已经分配的缓冲区。
  7. int size(); 返回缓冲区的当前大小。
  8. char[] toCharArray(); 返回输入数据的副本。
  9. String toString(); 将输入数据转换为字符串。
  10. void write(char[] c, int off, int len); 将字符写入缓冲区。
  11. void write(int c); 将一个字符写入缓冲区。
  12. void write(String str, int off, int len); 将一部分字符串写入缓冲区。
  13. void writeTo(Writer out); 将缓冲区的内容写入另一个字符流。
  1. 写一个字符到缓存区 void write(int c)

    1. /**
    2. * Writes a character to the buffer.
    3. */
    4. public void write(int c) {
    5. // 加锁
    6. synchronized (lock) {
    7. int newcount = count + 1;
    8. // 判定写入的下个元素是否超出缓冲区长度
    9. if (newcount > buf.length) {
    10. // 进行扩容
    11. buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
    12. }
    13. buf[count] = (char)c;
    14. count = newcount;
    15. }
    16. }
  2. 从字符数组中写len个字符到缓冲区中

    1. /**
    2. * 将字符数组的一部分写入到缓冲区中,自动扩容增长
    3. */
    4. public void write(char c[], int off, int len) {
    5. if ((off < 0) || (off > c.length) || (len < 0) ||
    6. ((off + len) > c.length) || ((off + len) < 0)) {
    7. throw new IndexOutOfBoundsException();
    8. } else if (len == 0) {
    9. return;
    10. }
    11. synchronized (lock) {
    12. int newcount = count + len;
    13. //判定缓冲区写入len个字符后长度是否超出限制
    14. if (newcount > buf.length) {
    15. buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
    16. }
    17. System.arraycopy(c, off, buf, count, len);
    18. count = newcount;
    19. }
    20. }
  3. 将字符串的一部分写入缓存区 ```java

    /**

    • Write a portion of a string to the buffer.
    • @param str String to be written from
    • @param off Offset from which to start reading characters
    • @param len Number of characters to be written */ public void write(String str, int off, int len) { synchronized (lock) {
      1. int newcount = count + len;
      2. // 判断是否需要扩容
      3. if (newcount > buf.length) {
      4. buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
      5. }
      6. str.getChars(off, off + len, buf, count);
      7. count = newcount;
      } }
  1. 4. 将缓存中的内容写入到另一个字符流中
  2. ```java
  3. /**
  4. * Writes the contents of the buffer to another character stream.
  5. *
  6. * @param out the output stream to write to
  7. * @throws IOException If an I/O error occurs.
  8. */
  9. public void writeTo(Writ
  10. er out) throws IOException {
  11. synchronized (lock)
  12. //本质理解为将缓冲区的内容给写了出去,给了另外一个输出流
  13. out.write(buf, 0, count);
  14. }
  15. }
  1. /**
  2. * 将缓冲区中的数据转成字符串
  3. * @return the string.
  4. */
  5. public String toString() {
  6. synchronized (lock) {
  7. return new String(buf, 0, count);
  8. }
  9. }
  10. /**
  11. * 将缓冲区的数据转成字符数组
  12. */
  13. public char[] toCharArray()[] {
  14. synchronized (lock) {
  15. return Arrays.copyOf(buf, count);
  16. }
  17. }
  1. /**
  2. * 刷新流--无效
  3. */
  4. public void flush() { }
  5. /**
  6. * 关闭流--无效
  7. */
  8. public void close() { }

FilterWriter

FilterWriter 是字符类型的过滤输出流。

1、FilterWriter 的构造函数:

  1. protected FilterWriter(Writer out) 创建一个新的过滤的作者。

2、FilterWriter 的方法列表:

  1. void close() 关闭流,先刷新。
  2. void flush() 刷新流。
  3. void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
  4. void write(int c) 写一个字符
  5. void write(String str, int off, int len) 写一个字符串的一部分。

PrintWriter

PrintWriter 是字符类型的打印输出流,它继承于 Writer。
1、PrintWriter 的构造方法:

  1. PrintWriter(File file) 使用指定的文件创建一个新的PrintWriter,而不需要自动的线路刷新。
  2. PrintWriter(File file, String csn) 使用指定的文件和字符集创建一个新的PrintWriter,而不需要自动进行线条刷新。
  3. PrintWriter(OutputStream out) 从现有的OutputStream创建一个新的PrintWriter,而不需要自动线路刷新。
  4. PrintWriter(OutputStream out, boolean autoFlush) 从现有的OutputStream创建一个新的PrintWriter
  5. PrintWriter(Writer out) 创建一个新的PrintWriter,没有自动线冲洗。
  6. PrintWriter(Writer out, boolean autoFlush) 创建一个新的PrintWriter
  7. PrintWriter(String fileName) 使用指定的文件名创建一个新的PrintWriter,而不需要自动执行行刷新。
  8. PrintWriter(String fileName, String csn) 使用指定的文件名和字符集创建一个新的PrintWriter,而不需要自动线路刷新。

2、PrintWriter 的方法列表:

  1. PrintWriter append(char c) 将指定的字符附加到此作者。
  2. PrintWriter append(CharSequence csq) 将指定的字符序列附加到此作者。
  3. PrintWriter append(CharSequence csq, int start, int end) 将指定字符序列的子序列附加到此作者。
  4. boolean checkError() 如果流未关闭,请刷新流并检查其错误状态。
  5. protected void clearError() 清除此流的错误状态。
  6. void close() 关闭流并释放与之相关联的任何系统资源。
  7. void flush() 刷新流。
  8. PrintWriter format(String format, Object... args) 使用指定的格式字符串和参数将格式化的字符串写入此写入程序。
  9. PrintWriter format(Locale l, String format, Object... args) 使用指定的格式字符串和参数将格式化的字符串写入此写入程序。
  10. void print(boolean b) 打印布尔值。
  11. void print(char c) 打印一个字符
  12. void print(char[] s) 打印字符数组。
  13. void print(double d) 打印双精度浮点数。
  14. void print(float f) 打印浮点数。
  15. void print(int i) 打印一个整数。
  16. void print(long l) 打印一个长整数。
  17. void print(Object obj) 打印一个对象。
  18. void print(String s) 打印字符串。
  19. PrintWriter printf(String format, Object... args) 使用指定的格式字符串和参数将格式化的字符串写入该writer的方便方法。
  20. PrintWriter printf(Locale l, String format, Object... args) 使用指定的格式字符串和参数将格式化的字符串写入该writer的方便方法。
  21. void println() 通过写入行分隔符字符串来终止当前行。
  22. void println(boolean x) 打印一个布尔值,然后终止该行。
  23. void println(char x) 打印一个字符,然后终止该行。
  24. void println(char[] x) 打印字符数组,然后终止行。
  25. void println(double x) 打印双精度浮点数,然后终止行。
  26. void println(float x) 打印一个浮点数,然后终止该行。
  27. void println(int x) 打印一个整数,然后终止该行。
  28. void println(long x) 打印一个长整型,然后终止行。
  29. void println(Object x) 打印一个对象,然后终止该行。
  30. void println(String x) 打印一个字符串,然后终止行。
  31. protected void setError() 表示发生错误。
  32. void write(char[] buf) 写入一个字符数组。
  33. void write(char[] buf, int off, int len) 写一个字符数组的一部分。
  34. void write(int c) 写一个字符
  35. void write(String s) 写一个字符串
  36. void write(String s, int off, int len) 写一个字符串的一部分。

Reader:字符输入流

Java IO流总结 - 图5

有输出流那么当然就有输入流,Reader 是字符输入流的基类,Reader 的方法列表如下:

  1. abstract void close() 关闭流并释放与之相关联的任何系统资源。
  2. void mark(int readAheadLimit) 标记流中的当前位置。
  3. boolean markSupported() 告诉这个流是否支持mark()操作。
  4. int read() 读一个字符
  5. int read(char[] cbuf) 将字符读入数组。
  6. abstract int read(char[] cbuf, int off, int len) 将字符读入数组的一部分。
  7. int read(CharBuffer target) 尝试将字符读入指定的字符缓冲区。
  8. boolean read() 告诉这个流是否准备好被读取。
  9. void reset() 重置流。
  10. long skip(long n) 跳过字符

FileReader

FileReader 的构造方法

  1. FileReader(File file) 创建一个新的 FileReader ,给出 File读取。
  2. FileReader(FileDescriptor fd) 创建一个新的 FileReader ,给予 FileDescriptor从中读取。
  3. FileReader(String fileName) 创建一个新的 FileReader ,给定要读取的文件的名称。

FileReader 的具体使用

例 1:

  1. import java.io.*;
  2. class FileReaderDemo
  3. {
  4. public static void main(String[] args) throws IOException
  5. {
  6. //创建一个文件读取流对象,和指定名称的文件相关联。
  7. //要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
  8. FileReader fr = new FileReader("demo.txt");
  9. //调用读取流对象的read方法。
  10. //read():一次读一个字符。而且会自动往下读。
  11. int ch = 0;
  12. while((ch=fr.read())!=-1)
  13. {
  14. System.out.println("ch="+(char)ch);
  15. }
  16. //关闭流
  17. fr.close();
  18. }
  19. }

例 2:

  1. /*
  2. 第二种方式:通过字符数组进行读取。
  3. */
  4. import java.io.*;
  5. class FileReaderDemo2
  6. {
  7. public static void main(String[] args) throws IOException
  8. {
  9. FileReader fr = new FileReader("demo.txt");
  10. //定义一个字符数组。用于存储读到字符。
  11. //该read(char[])返回的是读到字符个数。
  12. char[] buf = new char[1024];
  13. int num = 0;
  14. while((num=fr.read(buf))!=-1)
  15. {
  16. System.out.println(new String(buf,0,num));
  17. }
  18. fr.close();
  19. }
  20. }

BufferedReader

BufferedReader 的构造方法

  1. BufferedReader(Reader in) 创建使用默认大小的输入缓冲区的缓冲字符输入流。
  2. BufferedReader(Reader in, int sz) 创建使用指定大小的输入缓冲区的缓冲字符输入流。

BufferedReader 的方法列表

  1. void close() 关闭流并释放与之相关联的任何系统资源。
  2. Stream lines() 返回一个 Stream ,其元素是从这个 BufferedReader读取的行。
  3. void mark(int readAheadLimit) 标记流中的当前位置。
  4. boolean markSupported() 告诉这个流是否支持mark()操作。
  5. int read() 读一个字符
  6. int read(char[] cbuf, int off, int len) 将字符读入数组的一部分。
  7. String readLine() 读一行文字。
  8. boolean ready() 告诉这个流是否准备好被读取。
  9. void reset() 将流重置为最近的标记。
  10. long skip(long n) 跳过字符

BufferedReader 的具体使用:

例 1:

  1. /*
  2. 字符读取流缓冲区:
  3. 该缓冲区提供了一个一次读一行的方法 readLine,方便于对文本数据的获取。
  4. 当返回null时,表示读到文件末尾。
  5. readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
  6. */
  7. import java.io.*;
  8. class BufferedReaderDemo
  9. {
  10. public static void main(String[] args) throws IOException
  11. {
  12. //创建一个读取流对象和文件相关联。
  13. FileReader fr = new FileReader("buf.txt");
  14. //为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
  15. BufferedReader bufr = new BufferedReader(fr);
  16. String line = null;
  17. while((line=bufr.readLine())!=null)
  18. {
  19. System.out.print(line);
  20. }
  21.           //关闭流
  22. bufr.close();
  23. }
  24. }

例 2:通过缓冲区复制文件:

  1. /*
  2. 通过缓冲区复制一个.java文件。
  3. */
  4. import java.io.*;
  5. class CopyTextByBuf
  6. {
  7. public static void main(String[] args)
  8. {
  9. BufferedReader bufr = null;
  10. BufferedWriter bufw = null;
  11. try
  12. {
  13. bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
  14. bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
  15. String line = null;
  16. while((line=bufr.readLine())!=null)
  17. {
  18. bufw.write(line);
  19. bufw.newLine();
  20. bufw.flush();
  21. }
  22. }
  23. catch (IOException e)
  24. {
  25. throw new RuntimeException("读写失败");
  26. }
  27. finally
  28. {
  29. try
  30. {
  31. if(bufr!=null)
  32. bufr.close();
  33. }
  34. catch (IOException e)
  35. {
  36. throw new RuntimeException("读取关闭失败");
  37. }
  38. try
  39. {
  40. if(bufw!=null)
  41. bufw.close();
  42. }
  43. catch (IOException e)
  44. {
  45. throw new RuntimeException("写入关闭失败");
  46. }
  47. }
  48. }
  49. }

字节流

字节流的基本操作和字符流类相同,但它不仅可以操作字符,还可以操作其他媒体文件

InputStream 字节输入流

InputStream 类是字节输入流的抽象类,是所有字节输入流的父类,InputStream 类具有层次结构如下图所示:

Java IO流总结 - 图6

InputStream 的常用方法:

  1. int available() 从下一次调用此输入流的方法返回可从该输入流读取(或跳过)的字节数,而不会阻塞。
  2. void close() 关闭此输入流并释放与流相关联的任何系统资源。
  3. void mark(int readlimit) 标记此输入流中的当前位置。
  4. boolean markSupported() 测试此输入流是否支持 mark reset方法。
  5. abstract int read() 从输入流读取数据的下一个字节。
  6. int read(byte[] b) 从输入流中读取一些字节数,并将它们存储到缓冲器阵列 b
  7. int read(byte[] b, int off, int len) 从输入流读取最多 len个字节的数据到字节数组。
  8. byte[] readAllBytes() 从输入流读取所有剩余字节。
  9. int readNBytes(byte[] b, int off, int len) 将所请求的字节数从输入流读入给定的字节数组。
  10. void reset() 将此流重新定位到最后在此输入流上调用 mark方法时的位置。
  11. long skip(long n) 跳过并丢弃来自此输入流的 n字节的数据。
  12. long transferTo(OutputStream out) 从该输入流中读取所有字节,并按读取的顺序将字节写入给定的输出流。

FileInputStream

FileInputStream 的构造方法:

  1. FileInputStream(File file) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的 File对象 file命名。
  2. FileInputStream(FileDescriptor fdObj) 通过使用文件描述符 fdObj创建 FileInputStream ,该文件描述符表示与文件系统中的实际文件的现有连接。
  3. FileInputStream(String name) 通过打开与实际文件的连接来创建一个 FileInputStream ,该文件由文件系统中的路径名 name命名。

FileInputStream 的方法列表:

  1. int available() 返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
  2. void close() 关闭此文件输入流并释放与流相关联的任何系统资源。
  3. protected void finalize() 已过时。
  4. finalize方法已被弃用。 为了执行清理而覆盖finalize子类应该修改为使用替代清理机制,并删除覆盖的finalize方法。 当覆盖finalize方法时,其实现必须明确确保按照super.finalize()所述调用super.finalize() 有关迁移选项的更多信息,请参阅Object.finalize()的规范。
  5. FileChannel getChannel() 返回与此文件输入流相关联的唯一的FileChannel对象。
  6. FileDescriptor getFD() 返回表示与此 FileInputStream正在使用的文件系统中的实际文件的连接的 FileDescriptor对象。
  7. int read() 从该输入流读取一个字节的数据。
  8. int read(byte[] b) 从该输入流读取最多 b.length个字节的数据到一个字节数组。
  9. int read(byte[] b, int off, int len) 从该输入流读取最多 len个字节的数据到字节数组。
  10. long skip(long n) 跳过并从输入流中丢弃 n字节的数据。

FileInputStream 的具体使用:

  1. import java.io.*;
  2. class FileStream
  3. {
  4. public static void main(String[] args) throws IOException
  5. {
  6. readFile_3();
  7. }
  8. //打开文件,一次读取刚刚好内容的字节
  9. public static void readFile_3()throws IOException
  10. {
  11. FileInputStream fis = new FileInputStream("fos.txt");
  12. //available()返回从此输入流中可以读取(或跳过)的剩余字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
  13. byte[] buf = new byte[fis.available()];//定义一个刚刚好的缓冲区。不用在循环了。
  14. fis.read(buf);java
  15. System.out.println(new String(buf));
  16. fis.close();
  17. }
  18. //打开文件,一次读取多个字节
  19. public static void readFile_2()throws IOException
  20. {
  21. FileInputStream fis = new FileInputStream("fos.txt");
  22. byte[] buf = new byte[1024];
  23. int len = 0;
  24. while((len=fis.read(buf))!=-1)
  25. {
  26. System.out.println(new String(buf,0,len));
  27. }
  28. fis.close();
  29. }
  30. //打开文件,一次读取一个字节
  31. public static void readFile_1()throws IOException
  32. {
  33. FileInputStream fis = new FileInputStream("fos.txt");
  34. int ch = 0;
  35. while((ch=fis.read())!=-1)
  36. {
  37. System.out.println((char)ch);
  38. }
  39. fis.close();
  40. }
  41. }

OutputStream 字节输出流

Java IO流总结 - 图7

OutputStream 字节输出流的方法:

  1. void close() 关闭此输出流并释放与此流相关联的任何系统资源。
  2. void flush() 刷新此输出流并强制任何缓冲的输出字节被写出。
  3. void write(byte[] b) b.length字节从指定的字节数组写入此输出流。
  4. void write(byte[] b, int off, int len) 从指定的字节数组写入 len字节,从偏移量 off开始输出到此输出流。
  5. abstract void write(int b) 将指定的字节写入此输出流。

FileOutPutStream

FileOutPutStream 的构造方法:

  1. FileOutputStream(File file) 创建文件输出流以写入由指定的 File对象表示的文件。
  2. FileOutputStream(FileDescriptor fdObj) 创建文件输出流以写入指定的文件描述符,表示与文件系统中实际文件的现有连接。
  3. FileOutputStream(File file, boolean append) 创建文件输出流以写入由指定的 File对象表示的文件。
  4. FileOutputStream(String name) 创建文件输出流以指定的名称写入文件。
  5. FileOutputStream(String name, boolean append) 创建文件输出流以指定的名称写入文件。

FileOutPutStream 的方法列表:

  1. void close() 关闭此文件输出流并释放与此流相关联的任何系统资源。
  2. protected void finalize() 已过时。
  3. finalize方法已被弃用。 为了执行清理,覆盖finalize子类应被修改为使用替代的清理机制,并删除覆盖的finalize方法。 当覆盖finalize方法时,其实现必须明确确保按照super.finalize()中所述调用super.finalize() 有关迁移选项的更多信息,请参阅Object.finalize()的规范。
  4. FileChannel getChannel() 返回与此文件输出流相关联的唯一的FileChannel对象。
  5. FileDescriptor getFD() 返回与此流相关联的文件描述符。
  6. void write(byte[] b) b.length字节从指定的字节数组写入此文件输出流。
  7. void write(byte[] b, int off, int len) len字节从指定的字节数组开始,从偏移量 off开始写入此文件输出流。
  8. void write(int b) 将指定的字节写入此文件输出流。

FileOutPutStream 的具体使用

  1. import java.io.*;
  2. public class FileStreamTest {
  3. private static final String FileName = "file.txt";
  4. public static void main(String[] args) {
  5. testWrite();
  6. }
  7. /**
  8. * FileOutputStream 演示函数
  9. *
  10. * 运行结果:
  11. * 在源码所在目录生成文件"file.txt",文件内容是“abcdefghijklmnopqrstuvwxyz0123456789”
  12. *
  13. * 加入,我们将 FileOutputStream fileOut2 = new FileOutputStream(file, true);
  14. * 修改为 FileOutputStream fileOut2 = new FileOutputStream(file, false);
  15. * 然后再执行程序,“file.txt”的内容变成"0123456789"。
  16. * 原因是:
  17. * (01) FileOutputStream fileOut2 = new FileOutputStream(file, true);
  18. * 它是以“追加模式”将内容写入文件的。即写入的内容,追加到原始的内容之后。
  19. * (02) FileOutputStream fileOut2 = new FileOutputStream(file, false);
  20. * 它是以“新建模式”将内容写入文件的。即删除文件原始的内容之后,再重新写入。
  21. */
  22. public static void testWrite() {
  23. try {
  24. // 创建文件“file.txt”对应File对象
  25. File file = new File(FileName);
  26. // 创建文件“file.txt”对应的FileOutputStream对象,默认是关闭“追加模式”
  27. FileOutputStream fileOut1 = new FileOutputStream(file);
  28. // 创建FileOutputStream对应的PrintStream,方便操作。PrintStream的写入接口更便利
  29. PrintStream out1 = new PrintStream(fileOut1);
  30. // 向“文件中”写入26个字母
  31. out1.print("abcdefghijklmnopqrstuvwxyz");
  32. out1.close();
  33. // 创建文件“file.txt”对应的FileOutputStream对象,打开“追加模式”
  34. FileOutputStream fileOut2 = new FileOutputStream(file, true);
  35. // 创建FileOutputStream对应的PrintStream,方便操作。PrintStream的写入接口更便利
  36. PrintStream out2 = new PrintStream(fileOut2);
  37. // 向“文件中”写入"0123456789"+换行符
  38. out2.println("0123456789");
  39. out2.close();
  40. } catch(IOException e) {
  41. e.printStackTrace();
  42. }
  43. }
  44. }

File

JavaIo 流中还有一个非常常用的类:File。

File 是 “文件” 和 “目录路径名” 的抽象表示形式。
File 直接继承于 Object,实现了 Serializable 接口和 Comparable 接口。实现 Serializable 接口,意味着 File 对象支持序列化操作。而实现 Comparable 接口,意味着 File 对象之间可以比较大小;File 能直接被存储在有序集合 (如 TreeSet、TreeMap 中)。

File 的构造方法

  1. File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例。
  2. File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例。
  3. File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例。
  4. File(URI uri) 通过将给定的 file: URI转换为抽象路径名来创建新的 File实例。

File 的方法列表

  1. boolean canExecute() 测试应用程序是否可以执行此抽象路径名表示的文件。
  2. boolean canRead() 测试应用程序是否可以读取由此抽象路径名表示的文件。
  3. boolean canWrite() 测试应用程序是否可以修改由此抽象路径名表示的文件。
  4. int compareTo(File pathname) 比较两个抽象的路径名字典。
  5. boolean createNewFile() 当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。
  6. static File createTempFile(String prefix, String suffix) 在默认临时文件目录中创建一个空文件,使用给定的前缀和后缀生成其名称。
  7. static File createTempFile(String prefix, String suffix, File directory) 在指定的目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。
  8. boolean delete() 删除由此抽象路径名表示的文件或目录。
  9. void deleteOnExit() 请求在虚拟机终止时删除由此抽象路径名表示的文件或目录。
  10. boolean equals(Object obj) 测试此抽象路径名与给定对象的相等性。
  11. boolean exists() 测试此抽象路径名表示的文件或目录是否存在。
  12. File getAbsoluteFile() 返回此抽象路径名的绝对形式。
  13. String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串。
  14. File getCanonicalFile() 返回此抽象路径名的规范形式。
  15. String getCanonicalPath() 返回此抽象路径名的规范路径名字符串。
  16. long getFreeSpace() 通过此抽象路径名返回分区 named中未分配字节的数量。
  17. String getName() 返回由此抽象路径名表示的文件或目录的名称。
  18. String getParent() 返回此抽象路径名的父目录的路径名字符串,如果此路径名未命名为父目录,则返回 null
  19. File getParentFile() 返回此抽象路径名的父目录的抽象路径名,如果此路径名不指定父目录,则返回 null
  20. String getPath() 将此抽象路径名转换为路径名字符串。
  21. long getTotalSpace() 通过此抽象路径名返回分区 named的大小。
  22. long getUsableSpace() 通过此抽象路径名返回分区 named上此虚拟机可用的字节数。
  23. int hashCode() 计算此抽象路径名的哈希码。
  24. boolean isAbsolute() 测试这个抽象路径名是否是绝对的。
  25. boolean isDirectory() 测试此抽象路径名表示的文件是否为目录。
  26. boolean isFile() 测试此抽象路径名表示的文件是否为普通文件。
  27. boolean isHidden() 测试此抽象路径名命名的文件是否为隐藏文件。
  28. long lastModified() 返回此抽象路径名表示的文件上次修改的时间。
  29. long length() 返回由此抽象路径名表示的文件的长度。
  30. String[] list() 返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。
  31. String[] list(FilenameFilter filter) 返回一个字符串数组,命名由此抽象路径名表示的目录中满足指定过滤器的文件和目录。
  32. File[] listFiles() 返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件。
  33. File[] listFiles(FileFilter filter) 返回一个抽象路径名数组,表示由此抽象路径名表示的满足指定过滤器的目录中的文件和目录。
  34. File[] listFiles(FilenameFilter filter) 返回一个抽象路径名数组,表示由此抽象路径名表示的满足指定过滤器的目录中的文件和目录。
  35. static File[] listRoots() 列出可用的文件系统根。
  36. boolean mkdir() 创建由此抽象路径名命名的目录。
  37. boolean mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。
  38. boolean renameTo(File dest) 重命名由此抽象路径名表示的文件。
  39. boolean setExecutable(boolean executable) 为此抽象路径名设置所有者的执行权限的便利方法。
  40. boolean setExecutable(boolean executable, boolean ownerOnly) 设置该抽象路径名的所有者或每个人的执行权限。
  41. boolean setLastModified(long time) 设置由此抽象路径名命名的文件或目录的最后修改时间。
  42. boolean setReadable(boolean readable) 一种方便的方法来设置所有者对此抽象路径名的读取权限。
  43. boolean setReadable(boolean readable, boolean ownerOnly) 设置此抽象路径名的所有者或每个人的读取权限。
  44. boolean setReadOnly() 标记由此抽象路径名命名的文件或目录,以便只允许读取操作。
  45. boolean setWritable(boolean writable) 一种方便的方法来设置所有者对此抽象路径名的写入权限。
  46. boolean setWritable(boolean writable, boolean ownerOnly) 设置此抽象路径名的所有者或每个人的写入权限。
  47. Path toPath() 返回从此抽象路径构造的一个java.nio.file.Path对象。
  48. String toString() 返回此抽象路径名的路径名字符串。
  49. URI toURI() 构造一个表示此抽象路径名的 file: URI
  50. URL toURL() 已过时。 此方法不会自动转义URL中非法的字符。 建议在新的代码转换的抽象路径到URL通过先转换成URI,经由toURI方法,然后经由转换URIURL URI.toURL方法。

1|_0_3、File 的具体使用:

例 1:

  1. import java.io.*;
  2. /*
  3. File类常见方法:
  4. 1,创建。
  5. boolean createNewFile():在指定位置创建文件,如果该文件已经存在,则不创建,返回false。
  6. 和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
  7. boolean mkdir():创建文件夹。
  8. boolean mkdirs():创建多级文件夹。
  9. 2,删除。
  10. boolean delete():删除失败返回false。如果文件正在被使用,则删除不了返回falsel。
  11. void deleteOnExit();在程序退出时删除指定文件。
  12. 3,判断。
  13. boolean exists() :文件是否存在.
  14. isFile():
  15. isDirectory();
  16. isHidden();
  17. isAbsolute();
  18. 4,获取信息。
  19. getName():
  20. getPath():
  21. getParent():
  22. getAbsolutePath()
  23. long lastModified()
  24. long length()
  25. */
  26. class FileDemo
  27. {
  28. public static void main(String[] args) throws IOException
  29. {
  30. method_5();
  31. }
  32. public static void method_5()
  33. {
  34. File f1 = new File("c:\\Test.java");
  35. File f2 = new File("d:\\hahah.java");
  36. sop("rename:"+f2.renameTo(f1));
  37. }
  38. public static void method_4()
  39. {
  40. File f = new File("file.txt");
  41. sop("path:"+f.getPath());
  42. sop("abspath:"+f.getAbsolutePath());
  43. //该方法返回的是绝对路径中的父目录。如果获取的是相对路径,返回null。
  44. //如果相对路径中有上一层目录那么该目录就是返回结果。
  45. sop("parent:"+f.getParent());
  46. }
  47. public static void method_3()throws IOException
  48. {
  49. File f = new File("d:\\java1223\\day20\\file2.txt");
  50. //f.createNewFile();
  51. //f.mkdir();
  52. //记住在判断文件对象是否是文件或者目的时,必须要先判断该文件对象封装的内容是否存在。
  53. //通过exists判断。
  54. sop("dir:"+f.isDirectory());
  55. sop("file:"+f.isFile());
  56. sop(f.isAbsolute());
  57. }
  58. public static void method_2()
  59. {
  60. File f = new File("file.txt");
  61. //sop("exists:"+f.exists());
  62. //sop("execute:"+f.canExecute());
  63. //创建文件夹
  64. File dir = new File("abc\\kkk\\a\\a\\dd\\ee\\qq\\aaa");
  65. sop("mkdir:"+dir.mkdirs());
  66. }
  67. public static void method_1()throws IOException
  68. {
  69. File f = new File("file.txt");
  70. sop("create:"+f.createNewFile());
  71. //sop("delete:"+f.delete());
  72. }
  73. //创建File对象
  74. public static void consMethod()
  75. {
  76. //将a.txt封装成file对象。可以将已有的和为出现的文件或者文件夹封装成对象。
  77. File f1 = new File("a.txt");
  78. File f2 = new File("c:\\abc","b.txt");
  79. File d = new File("c:\\abc");
  80. File f3 = new File(d,"c.txt");
  81. sop("f1:"+f1);
  82. sop("f2:"+f2);
  83. sop("f3:"+f3);
  84. File f4 = new File("c:"+File.separator+"abc"+File.separator+"zzz"+File.separator+"a.txt");
  85. }
  86. public static void sop(Object obj)
  87. {
  88. System.out.println(obj);
  89. }
  90. }

例 2:递归列出指定目录下的文件或者文件夹

  1. /*
  2. 列出指定目录下文件或者文件夹,包含子目录中的内容。
  3. 也就是列出指定目录下所有内容。
  4. 因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
  5. 在列出过程中出现的还是目录的话,还可以再次调用本功能。
  6. 也就是函数自身调用自身。
  7. 这种表现形式,或者编程手法,称为递归。
  8. 递归要注意:
  9. 1,限定条件。
  10. 2,要注意递归的次数。尽量避免内存溢出。
  11. */
  12. import java.io.*;
  13. class FileDemo3
  14. {
  15. public static void main(String[] args)
  16. {
  17. File dir = new File("E:\\Book");
  18. showDir(dir,0);
  19. }
  20. public static String getLevel(int level)
  21. {
  22. StringBuilder sb = new StringBuilder();
  23. sb.append("|--");
  24. for(int x=0; x