IO流

目录

IO(Input,Output)流

  • IO流用来处理设备之间的数据传输。
  • Java对数据的操作是通过流的方式。
  • Java用于操作流的对象都在IO包中。
  • 流按操作数据分为两种:
    • 字节流。
    • 字符流。
  • 流按流向分为
    • 输入流。
    • 输出流。

IO流常用基类

  • 字节流的抽象基类:
    • InputStream
    • OutputStream
  • 字符流的抽象基类:
    • Reader
    • Writer
  • 注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。
    • 如:InputStream的子类FileInputStream
    • 如:Reader的子类FileReader

字符流

Writer

用于写入字符流的抽象类。 子类必须实现的唯一方法是write(char [],int,int),flush()和close()。 然而,大多数子类将覆盖这里定义的一些方法,以便提供更高的效率,附加的功能或两者。

import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // 创建一个FileWriter对象。该对象一被初始化就必须要明确被操作的文件。
            // 而且该文件会被创建到指定目录下。如果已有同名文件,就会覆盖该文件。
            fw = new FileWriter("demo.txt");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fw != null;
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

write()

写一个字符

public void write(int c) throws IOException

写入一个字符串

public void write(String str) throws IOException

写入一个字符数组

public void write(char cbuf[]) throws IOException

写入字符数组的一部分。

public void write(char[] cbuf,int off, int len)  throws IOException

参数:
+ cbuf cbuf缓冲区
+ off 从中开始编写字符的偏移量
+ len 要写入的 len数

写一个字符串的一部分。

public void write(String str, int off, int len) throws IOException

参数:
+ str 一个字符串
+ off 开始写入字符的偏移量
+ len 要写入的 len数

用法:

import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw = new FileWriter("demo.txt");
            fw.write("Hello FileWriter");
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }
}

flush()

刷新流。使用该方法内容才会写入到文件中。

public void flush() throws IOException

用法:

import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw = new FileWriter("demo.txt");
            fw.write("Hello FileWriter");
            fw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }
}

close()

关闭流,先刷新。 一旦流已关闭,进一步的write()flush()调用将导致抛出IOException。 关闭以前关闭的流无效。

public void close() throws IOException

用法:

import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw = new FileWriter("demo.txt");
            fw.write("Hello FileWriter");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fw != null;
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

Reader

用于读取字符流的抽象类。 子类必须实现的唯一方法是read(char [],int,int)close()。 然而,大多数子类将覆盖这里定义的一些方法,以便提供更高的效率,附加的功能或两者。

用法:

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

public class IODemo {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            fr = new FileReader("demo.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

read()

读一个字符 该方法将阻塞,直到字符可用,发生I / O错误或达到流的结尾。

public int read() throws IOException

用法:

“`java
import java.io.FileReader;
import java.io.IOException;

public class IODemo {
public static void main(String[] args) {
FileReader fr = null;
try {
fr = new FileReader("demo.txt");
int ch = 0;
while ((ch = fr.read()) != -1) {
// Hello FileReader
System.out.print((char)ch);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

“`

将字符读入数组。 该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。

public int read(char[] cbuf) throws IOException

用法:

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

public class IODemo {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            fr = new FileReader("demo.txt");
            char[] chs = new char[1024];
            int num = 0;
            while ((num = fr.read(chs)) != -1) {
                // Hello FileReader
                System.out.println(new String(chs, 0, num));
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

将字符读入数组的一部分。 该方法将阻塞,直到某些输入可用,发生I / O错误或达到流的结尾。

public abstract int read(char[] cbuf, int off, int len) throws IOException

参数:
+ cbuf 目的缓冲区
+ off 开始存储字符的偏移量
+ len 要读取的最大字符数

练习:

把C盘的某一个文件复制到D盘。

“`java
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
* 复制原理:
* 其实就是将C盘下的文件数据存储到D盘的一个文件中。
*
* 步骤:
* 1. 在D盘创建一个文件。用于存储C盘文件中的数据。
* 2. 定义读取流和C盘关联。
* 3. 通过不断的读写完成数据存储。
* 4. 关闭资源。
*/
public class IODemo {
public static void main(String[] args) throws IOException {
String filename = "demo.txt";
copyFile("C:/" + filename, "D:/" + filename);
}

<pre><code>public static void copyFile(String startPath, String endPath) {
FileWriter fw = null;
FileReader fr = null;

try {
fr = new FileReader(startPath);
fw = new FileWriter(endPath);
char[] chars = new char[1024];
int ch = 0;
while ((ch = fr.read(chars)) != -1) {
fw.write(new String(chars, 0, ch));
}
System.out.println(endPath + "写入成功!");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
assert fr != null;
fr.close();
assert fw != null;
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}

}
</code></pre>

}

“`

BufferedWriter

  • 将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入。
  • 可以指定缓冲区大小,或者可以接受默认大小。 默认值足够大,可用于大多数用途。

用法:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            // 创建一个字符写入流对象
            fw = new FileWriter("buf.txt");
            // 为了提高字符写入流效率。加入了缓存技术。
            // 只要将需要被提高效率的流对象作为参数传递给缓存区的构造函数即可。
            BufferedWriter bw = new BufferedWriter(fw);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fw != null;
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

write()

写一个字符

public void write(int c) throws IOException

写入字符数组的一部分。

public void write(char[] cbuf, int off, int len) throws IOException

写一个字符串的一部分。

public void write(String s, int off, int len) throws IOException

用法:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw = new FileWriter("buf.txt");
            BufferedWriter bw = new BufferedWriter(fw);
            // 写入字符串
            bw.write("123456");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fw != null;
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

flush()

刷新流。

public void flush() throws IOException

用法:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        try {
            fw = new FileWriter("buf.txt");
            BufferedWriter bw = new BufferedWriter(fw);
            bw.write("123456");
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fw != null;
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

close()

关闭流,先刷新。 一旦流已关闭,进一步的write()或flush()调用将导致抛出IOException。 关闭以前关闭的流无效。

public void close() throws IOException

用法:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        BufferedWriter bw = null;
        try {
            fw = new FileWriter("buf.txt");
            bw = new BufferedWriter(fw);
            bw.write("123456");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                 assert bw != null;
                 bw.close();
                 fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

newLine()

写一行行分隔符。 行分隔符字符串由系统属性line.separator定义,并不一定是单个换行符(’\ n’)字符。

public void newLine() throws IOException

用法:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileWriter fw = null;
        BufferedWriter bw = null;
        try {
            fw = new FileWriter("buf.txt");
            bw = new BufferedWriter(fw);

            bw.write("123");
            bw.newLine();
            bw.write("456");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert bw != null;
                bw.close();
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

BufferedReader

  • 从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取。
  • 可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途。

用法:

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

public class IODemo {
    public static void main(String[] args) {
        FileReader fr = null;
        BufferedReader br = null;

        try {
            // 创建一个读取流对象和文件关联。
            fr = new FileReader("buf.txt");
            // 为了提高效率。加入了缓存技术。将字节读取流对象作为参数传递给缓存对象的构造方法函数。
            br = new BufferedReader(fr);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                assert fr != null;
                fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

readLine()

读一行文字。 一行被视为由换行符(’\ n’),回车符(’\ r’)中的任何一个或随后的换行符终止。

public String readLine() throws IOException

用法:

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

public class IODemo {
    public static void main(String[] args) {
        FileReader fr = null;
        BufferedReader br = null;

        try {
            fr = new FileReader("buf.txt");
            br = new BufferedReader(fr);
            // br.readLine() = 123
            System.out.println("br.readLine() = " + br.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert br != null;
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
/**
 * 读取全部内容
 */
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class IODemo {
    public static void main(String[] args) {
        FileReader fr = null;
        BufferedReader br = null;

        try {
            fr = new FileReader("buf.txt");
            br = new BufferedReader(fr);

            String line = "";
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert br != null;
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

练习

  • 通过缓存区复制一个文.java文件。
import java.io.*;

public class IODemo {
    public static void main(String[] args) {
        BufferedReader br = null;
        BufferedWriter bw = null;

        try {
            br = new BufferedReader(new FileReader("IODemo.java"));
            bw = new BufferedWriter(new FileWriter("IODemo_copy.java"));

            String line = null;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                assert br != null;
                br.close();
                assert bw != null;
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

LineNumberReader

缓冲字符输入流,跟踪行号。 该类定义方法setLineNumber(int)和getLineNumber()用于分别设置和获得当前行号。
默认情况下,线路编号从0开始。随着数据的读取,每个line terminator的数字递增,可以通过呼叫setLineNumber(int)进行更改。 但是请注意, setLineNumber(int)实际上并不改变流中的当前位置; 它只会更改getLineNumber()将返回的值 。

用法:

import java.io.*;

public class IODemo {
    public static void main(String[] args) {
        FileReader fr = null;
        LineNumberReader lnr = null;
        try {
            fr = new FileReader("demo.txt");

            lnr = new LineNumberReader(fr);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                assert lnr != null;
                lnr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

getLineNumber()

获取当前行号。

public int getLineNumber()

用法:

“`java
import java.io.*;

public class IODemo {
public static void main(String[] args) {
FileReader fr = null;
LineNumberReader lnr = null;
try {
fr = new FileReader("demo.txt");
lnr = new LineNumberReader(fr);

<pre><code> String line = null;
while ((line = lnr.readLine()) != null) {
System.out.println(lnr.getLineNumber() + ":" + line);
}

} catch (IOException e) {
e.printStackTrace();
} finally {
try {
assert lnr != null;
lnr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
</code></pre>

}

“`

setLineNumber()

设置当前行号。

public void setLineNumber(int lineNumber)

用法:

import java.io.*;

public class IODemo {
    public static void main(String[] args) {
        FileReader fr = null;
        LineNumberReader lnr = null;
        try {
            fr = new FileReader("demo.txt");
            lnr = new LineNumberReader(fr);

            lnr.setLineNumber(101);

            String line = null;
            while ((line = lnr.readLine()) != null) {
                System.out.println(lnr.getLineNumber() + ":" + line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert lnr != null;
                lnr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

练习:模拟一个带行号的LineNumberReader类

import java.io.*;

public class MyLineNumberReader {
    private Reader r;
    private int lineNumber;

    MyLineNumberReader(Reader r) {
        this.r = r;
    }

    public String myReadLine() throws IOException {
        lineNumber++;
        StringBuilder sb = new StringBuilder();
        int ch = 0;
        while ((ch = r.read()) != -1) {
            if (ch == '\r') {
                continue;
            }
            if (ch == '\n') {
                return sb.toString();
            }
            sb.append((char) ch);
        }
        if (sb.length() != 0) {
            return sb.toString();

        } else {
            return null;
        }
    }

    public void myClose() throws IOException {
        r.close();
    }

    public int getLineNumber() {
        return lineNumber;
    }

    public void setLineNumber(int lineNumber) {
        this.lineNumber = lineNumber;
    }

    public static void main(String[] args) {
        FileReader fr = null;
        MyLineNumberReader mlnr = null;
        try {
            fr = new FileReader("demo.txt");
            mlnr = new MyLineNumberReader(fr);

            mlnr.setLineNumber(100);
            String line = null;
            while ((line = mlnr.myReadLine()) != null) {
                System.out.println(mlnr.getLineNumber() + ":" + line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert mlnr != null;
                mlnr.myClose();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 优化代码(继承BufferedReader类)
import java.io.*;

public class MyLineNumberReader extends BufferedReader {
    private int lineNumber;

    MyLineNumberReader(Reader r) {
        super(r);
    }

    public String myReadLine() throws IOException {
        lineNumber++;
        return super.readLine();
    }


    public int getLineNumber() {
        return lineNumber;
    }

    public void setLineNumber(int lineNumber) {
        this.lineNumber = lineNumber;
    }

    public static void main(String[] args) {
        FileReader fr = null;
        MyLineNumberReader mlnr = null;
        try {
            fr = new FileReader("src/com/company/IODemo.java");
            mlnr = new MyLineNumberReader(fr);

            mlnr.setLineNumber(100);
            String line = null;
            while ((line = mlnr.myReadLine()) != null) {
                System.out.println(mlnr.getLineNumber() + "|" + line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert mlnr != null;
                mlnr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

字节流

需求:想要操作图片数据。这时就需要用到字节流。

OutputStream

  • 这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。
  • 这个抽象类是表示字节输出流的所有类的超类。 输出流接收输出字节并将其发送到某个接收器。
import java.io.FileOutputStream;
import java.io.IOException;

public class FileStream {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("fos.txt");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

write()

将指定的字节写入此输出流。 write的一般合同是将一个字节写入输出流。 要写入的字节是参数b的八个低位。 b的24个高位被忽略。

public abstract void write(int b) throws IOException

将b.length字节从指定的字节数组写入此输出流。 write(b)的一般合约是应该具有与电话write(b, 0, b.length)完全相同的效果。

public void write(byte[] b) throws IOException

从指定的字节数组写入len字节,从偏移off开始输出到此输出流。 write(b, off, len)的一般合同是数组b中的一些字节按顺序写入输出流; 元素b[off]是写入的第一个字节, b[off+len-1]是此操作写入的最后一个字节。

public void write(byte[] b, int off, int len) throws IOException

参数:
+ b 数据。
+ off 数据中的起始偏移量。
+ len 要写入的字节数。

用法:

import java.io.FileOutputStream;
import java.io.IOException;

public class FileStream {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream("fos.txt");
            fos.write("Hello FileOutputStream".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

InputStream

这个抽象类是表示输入字节流的所有类的超类。
需要定义InputStream子类的应用InputStream必须始终提供一种返回输入的下一个字节的方法。

import java.io.FileInputStream;
import java.io.IOException;

public class FileStream {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("fos.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

read()

从该输入流读取下一个数据字节。 值字节作为int返回为0到255 。 如果没有字节可用,因为流已经到达,则返回值-1 。 该方法阻塞直到输入数据可用,检测到流的结尾,或抛出异常。

public int read() throws IOException

从该输入流读取高达byte.length字节的数据到字节数组。 此方法将阻塞,直到某些输入可用。

public int read(byte[] b) throws IOException

从该输入流读取高达len字节的数据到字节数组。 如果len不为零,则该方法将阻塞,直到某些输入可用; 否则,不会读取字节,并返回0 。

public int read(byte[] b, int off, int len) throws IOException

参数
+ b 读取数据的缓冲区。
+ off 目标数组 b的起始偏移量
+ len 读取的最大字节数。

用法1:

import java.io.FileInputStream;
import java.io.IOException;

public class FileStream {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("fos.txt");

            int ch = 0;
            while ((ch = fis.read()) != -1) {
                System.out.print((char)ch);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

用法2:

import java.io.FileInputStream;
import java.io.IOException;

public class FileStream {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("fos.txt");

            byte[] b = new byte[1024];
            int len = 0;
            while ((len = fis.read(b)) != -1) {
                System.out.println(new String(b,0,len));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

available()

返回从该输入流中可以读取(或跳过)的字节数的估计,而不会被下一个调用者阻塞该输入流的方法。 下一个调用者可能是同一个线程或另一个线程。 这个多个字节的单个读取或跳过将不会被阻塞,但可以读取或跳过较少的字节。

public int available() throws IOException

用法:

import java.io.FileInputStream;
import java.io.IOException;

public class FileStream {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("fos.txt");

            byte[] b = new byte[fis.available()];
            fis.read(b);
            // Hello FileOutputStream
            System.out.println(new String(b));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

练习1:拷贝图片

  • 思路:
    • 用字节读取流对象和图片关联。
    • 用字节写入流对象创建一个图片文件。用于存储获取到图片数据。
    • 通过循环读写,完成数据的存储。
    • 关闭资源。
import java.io.*;

public class FileStream {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        FileInputStream fis = null;

        try {
            fos = new FileOutputStream("C:/2.jpg");
            fis = new FileInputStream("C:/1.jpg");

            byte[] bytes = new byte[1024];
            int len = 0;

            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }
            System.out.println("文件复制成功!");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                assert fos != null;
                fos.close();
                assert fis != null;
                fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

练习2:拷贝音乐,通过字节流缓冲区。

import java.io.*;

public class FileStream {
    public static void main(String[] args) {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        long start = System.currentTimeMillis();
        try {
            bis = new BufferedInputStream(new FileInputStream("a.mp3"));
            bos = new BufferedOutputStream(new FileOutputStream("b.mp3"));

            int by = 0;
            while ((by = bis.read()) != -1) {
                bos.write(by);
            }

            System.out.println(System.currentTimeMillis()-start+"ms");
            System.out.println("文件复制成功!");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                assert bis != null;
                bis.close();
                assert bos != null;
                bos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

练习3:获取键盘输入的内容,写入到文件中。

/**
 * 需求:
 * 通过键盘录入数据。
 * 当录入一行数据后,就将该行数据进行打印。
 * 如果录入的数据是over,那么停止录入。
 */

import java.io.*;

public class FileStream {
    public static void main(String[] args) throws IOException {
        InputStream in = System.in;
        StringBuilder sb = new StringBuilder();
        while (true) {
            int ch = in.read();
            if (ch == '\r') {
                continue;
            }
            if (ch == '\n') {
                String s = sb.toString();
                if ("over".equals(s)) {
                    break;
                }
                System.out.println(s.toUpperCase());
                sb.delete(0, sb.length());
            } else {
                sb.append((char) ch);
            }
        }
    }
}

InputStreamReader

InputStreamReader是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
每个调用InputStreamReader的read()方法之一可能会导致从底层字节输入流读取一个或多个字节。 为了使字节有效地转换为字符,可以从底层流读取比满足当前读取操作所需的更多字节。

为了最大的效率,请考虑在BufferedReader中包装一个InputStreamReader。 例如:

用法:

/**
 * 需求:
 * 通过键盘录入数据。
 * 当录入一行数据后,就将该行数据进行打印。
 * 如果录入的数据是over,那么停止录入。
 */

import java.io.*;

public class FileStream {
    public static void main(String[] args) throws IOException {
        // 获取键盘对象
        InputStream in = System.in;
        // 将字节流对象转换成字符流对象,使用转换流, InputStreamReader
        InputStreamReader isr = new InputStreamReader(in);
        // 为了提高效率,及字符串进行缓冲区高效操作,使用BufferedReader
        BufferedReader br = new BufferedReader(isr);

        String line = null;
        while ((line = br.readLine()) != null) {
            if ("over".equals(line)) {
                break;
            }
            System.out.println(line.toUpperCase());
        }
        br.close();

    }
}

OutputStreamWriter

OutputStreamWriter是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节charset 。 它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。
每次调用write()方法都会使编码转换器在给定字符上被调用。 所得到的字节在写入底层输出流之前累积在缓冲区中。 可以指定此缓冲区的大小,但是默认情况下它大部分用于大多数目的。 请注意,传递给write()方法的字符不会缓冲。

为了最大的效率,请考虑在BufferedWriter中包装一个OutputStreamWriter,以避免频繁的转换器调用。

用法:

import java.io.*;

public class FileStream {
    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        String line = null;
        while ((line = br.readLine()) != null) {
            if ("over".equals(line)) {
                break;
            }
            bw.write(line.toUpperCase());
            bw.newLine();
            System.out.println(line.toUpperCase());
        }
        br.close();
    }
}

流操作规则

  • 源:键盘录入。
  • 目的:控制台。
  • 需求:
    • 想把键盘录入的数据存储到一个文件中。
    • 源:键盘。
    • 目的:文件。
  • 需求:想要将一个文件的数据打印在控制台上。
    • 源:文件。
    • 目的:控制台。

流操作的基本规律:

最痛苦的就是流对象有很多,不知道该用哪一个。

通过三个明确来完成。

  • 明确源和目的。
    • 源:输入流。InputStream Reader
    • 目的:输出流。OutputStream Writer。
  • 操作的数据是否是纯文本。
    • 是:字符流。
  • 不是:字节流。
  • 当体系明确后,在明确要使用哪个具体的对象。
    • 通过设备来进行区分:
    • 源设备:内存,硬盘。键盘
    • 目的设备:内存,硬盘,控制台。
  • 将一个文本文件中数据存储到另一个文件中。复制文件。
  • 源:因为是源,所以使用读取流。InputStream Reader
  • 是不是操作文本文件。
  • 是!这时就可以选择Reader
  • 这样体系就明确了。
  • 接下来明确要使用该体系中的哪个对象。

  • 明确设备:硬盘。上一个文件。

  • Reader体系中可以操作文件的对象是 FileReader
  • 是否需要提高效率:是!。加入Reader体系中缓冲区 BufferedReader.
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
  • 目的:OutputStream Writer

  • 是否是纯文本。

  • 是!Writer。
  • 设备:硬盘,一个文件。
  • Writer体系中可以操作文件的对象FileWriter。
  • 是否需要提高效率:是!。加入Writer体系中缓冲区 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BufferedWriter bufw = new BufferedWriter(fw);
  • 需求:将键盘录入的数据保存到一个文件中。
    • 这个需求中有源和目的都存在。
    • 那么分别分析
    • 源:InputStream Reader
    • 是不是纯文本?是!Reader
    • 设备:键盘。对应的对象是System.in.
    • 不是选择Reader吗?System.in对应的不是字节流吗?
    • 为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
    • 所以既然明确了Reader,那么就将System.in转换成Reader。
    • 用了Reader体系中转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);

// 需要提高效率吗?需要!BufferedReader
BufferedReader bufr = new BufferedReader(isr);
  • 目的:OutputStream Writer
  • 是否是存文本?是!Writer。
  • 设备:硬盘。一个文件。使用 FileWriter。
FileWriter fw = new FileWriter("c.txt");
// 需要提高效率吗?需要。
BufferedWriter bufw = new BufferedWriter(fw);
  • 扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
  • 目的:OutputStream Writer
  • 是否是存文本?是!Writer。
  • 设备:硬盘。一个文件。使用 FileWriter。
  • 但是FileWriter是使用的默认编码表。GBK.
  • 但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
  • 所以要使用的对象是OutputStreamWriter。
  • 而该转换流对象要接收一个字节输出流。而且还可以操作的文件的字节输出流。FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"UTF-8");
// 需要高效吗?需要。
BufferedWriter bufw = new BufferedWriter(osw);
  • 所以,记住。转换流什么使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时,需要用到转换流。
  • 需求:
    • 想把键盘录入的数据存储到一个文件中。
/**
 * 需求:
 * 通过键盘录入数据。
 * 当录入一行数据后,就将该行数据进行打印,并输出文件。
 * 如果录入的数据是over,那么停止录入。
 */

import java.io.*;

public class FileStream {
    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("demo.txt")));

        String line = null;
        while ((line = br.readLine()) != null) {
            if ("over".equals(line)) {
                break;
            }
            bw.write(line.toUpperCase());
            bw.newLine();
            System.out.println(line.toUpperCase());
        }
        bw.close();
        br.close();
    }
}

  • 需求:
    • 需要将一个文件的数据打印在控制台上。
import java.io.*;

public class FileStream {
    public static void main(String[] args) throws IOException {

        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("demo.txt")));

        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));

        String line = null;
        while ((line = br.readLine()) != null) {
            if ("over".equals(line)) {
                break;
            }
            bw.write(line.toUpperCase());
            bw.newLine();
            System.out.println(line.toUpperCase());
        }
        bw.close();
        br.close();
    }
}

File

  • 用来将文件或者文件夹封装的对象。
  • 方便对对象与文件夹进行操作。
  • File对象可以作为参数传递给流的构造函数。
  • 了解File类的常用方法。

用法1:

import java.io.File;

public class FileDemo {
    public static void main(String[] args) {
        // 将demo.txt封装成File对象。可以将已有的和为出现的文件或者文件夹封装成对象。
        File f = new File("demo.txt");
    }
}

用法2:

import java.io.File;

public class FileDemo {
    public static void main(String[] args) {
        File f = new File("C:/","demo.txt");
    }
}

常用方法

创建

createNewFile()

当且仅当具有该名称的文件尚不存在时,原子地创建一个由该抽象路径名命名的新的空文件。 检查文件的存在和文件的创建(如果不存在)是对可能影响文件的所有其他文件系统活动是单一的操作。

public boolean createNewFile() throws IOException

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("C:/","file.txt");
        boolean nf = f.createNewFile();
        // nf = true
        System.out.println("nf = " + nf);
    }
}
createTempFile()

在默认临时文件目录中创建一个空文件,使用给定的前缀和后缀生成其名称。 调用此方法相当于调用createTempFile(prefix, suffix, null)

public static File createTempFile(String prefix, String suffix) throws IOException
  • prefix 用于生成文件名的前缀字符串; 长度必须至少为3个字符
  • suffix 用于生成文件名称的后缀字符串; 可以是null ,在这种情况下将使用后缀”.tmp

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File ctf = File.createTempFile("demo", null);
        // C:\Users\ADMINI~1\AppData\Local\Temp\demo2278811494087441363.tmp
        System.out.println(ctf);
    }
}

在指定的目录中创建一个新的空文件,使用给定的前缀和后缀字符串生成其名称。 如果此方法成功返回,则可以保证:

  1. 在调用此方法之前,由返回的抽象路径名表示的文件不存在
  2. 该方法和其任何变体都不会在当前虚拟机的调用中再次返回相同的抽象路径名。
public static File createTempFile(String prefix, String suffix, File directory) throws IOException
  • prefix 用于生成文件名的前缀字符串; 长度必须至少为3个字符
  • suffix 用于生成文件名的后缀字符串; 可能是null ,在这种情况下将使用后缀”.tmp
  • directory 其中文件是要创建的目录,或 null如果默认临时文件目录将被使用

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File ctf = File.createTempFile("demo", null,new File("D:/"));
        // D:\demo7965113080039352462.tmp
        System.out.println(ctf);
    }
}
mkdir()

创建由此抽象路径名命名的目录。

public boolean mkdir()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("test");
        // true
        System.out.println(f.mkdir());
    }
}
mkdirs()

创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。 请注意,如果此操作失败,它可能已成功创建一些必需的父目录。

public boolean mkdirs()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("test/test2/test3/test4/test5");
        // true
        System.out.println(f.mkdirs());
    }
}

删除

delete()

删除由此抽象路径名表示的文件或目录。 如果此路径名表示目录,则目录必须为空才能删除。

public boolean delete()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File ctf = File.createTempFile("demo", null);
        // true
        System.out.println(ctf.delete());
        // false
        System.out.println(ctf.delete());
    }
}
deleteOnExit()
  • 请求在虚拟机终止时删除由此抽象路径名表示的文件或目录。文件(或目录)按注册的相反顺序进行删除。调用此方法删除已注册删除的文件或目录无效。将仅针对Java语言规范定义的虚拟机的正常终止而尝试删除。

  • 一旦请求删除,就无法取消请求。 因此,该方法应谨慎使用。

public void deleteOnExit()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File ctf = File.createTempFile("demo", null);
        ctf.deleteOnExit();
    }
}

判断

canExecute()

测试应用程序是否可以执行此抽象路径名表示的文件。 在某些平台上,可能会启动具有特殊权限的Java虚拟机,以允许其执行未标记为可执行文件。 因此,这个方法可能返回true即使该文件不具有执行权限。

public boolean canExecute()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("demo.txt");
        // true
        System.out.println(f.canExecute());
        File f2 = new File("demo2.txt");
        // false
        System.out.println(f2.canExecute());
    }
}

类似方法:

  • canRead() 测试应用程序是否可以读取由此抽象路径名表示的文件。
  • canWrite() 测试应用程序是否可以修改由此抽象路径名表示的文件。
exists()

测试此抽象路径名表示的文件或目录是否存在。

public boolean exists()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("demo.txt");
        // true
        System.out.println(f.exists());
        File f2 = new File("demo2.txt");
        // false
        System.out.println(f2.exists());
    }
}
isDirectory()

测试此抽象路径名表示的文件是否为目录。

public boolean isDirectory()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("test/test2/test3/test4/test5");
        // true
        System.out.println(f.isDirectory());
        File f2 = new File("demo.txt");
        // false
        System.out.println(f2.isDirectory());
    }
}
isFile()

测试此抽象路径名表示的文件是否为普通文件。 如果文件不是目录,并且另外满足其他依赖于系统的条件,文件是正常的 。 Java应用程序创建的任何非目录文件都保证是一个普通文件。

public boolean isFile()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("test/test2/test3/test4/test5");
        // false
        System.out.println(f.isFile());
        File f2 = new File("demo.txt");
        // true
        System.out.println(f2.isFile());
    }
}
isHidden()

测试此抽象路径名命名的文件是否为隐藏文件。 隐藏的确切定义是依赖于系统的。

public boolean isHidden()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File(".git");
        // true
        System.out.println(f.isHidden());

        File f2 = new File("text");
        // false
        System.out.println(f2.isHidden());
    }
}
isAbsolute()

测试这个抽象路径名是否是绝对的。 绝对路径名的定义是依赖于系统的。

public boolean isAbsolute()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("C:/Project/Java/untitled/.git");
        // true
        System.out.println(f.isAbsolute());

        File f2 = new File("text");
        // false
        System.out.println(f2.isAbsolute());
    }
}

获取信息

getName();

返回由此抽象路径名表示的文件或目录的名称。 这只是路径名称序列中的最后一个名字。 如果路径名的名称序列为空,则返回空字符串。

public String getName()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("C:/.git");
        // .git
        System.out.println(f.getName());
    }
}
getPath();

将此抽象路径名转换为路径名字符串。

public String getPath()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("C:/.git");
        // C:\.git
        System.out.println(f.getPath());
    }
}
getParent();

返回此抽象路径名的父null的路径名字符串,如果此路径名未命名为父目录,则返回null

public String getParent()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("C:/.git");
        // C:\
        System.out.println(f.getParent());
        File f2 = new File(".git");
        // null
        System.out.println(f2.getParent());
    }
}
getAbsolutePath();

返回此抽象路径名的绝对路径名字符串。

public String getAbsolutePath()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File(".git");
        // C:\Project\Java\untitled\.git
        System.out.println(f.getAbsolutePath());
    }
}
lastModified();

返回此抽象路径名表示的文件上次修改的时间。

public long lastModified()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("demo.txt");
        // 1595819445830
        System.out.println(f.lastModified());
    }
}
length();

返回由此抽象路径名表示的文件的长度。 如果此路径名表示目录,则返回值未指定。

public long length()

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("demo.txt");
        // 5
        System.out.println(f.length());
    }
}
list()

返回一个字符串数组,命名由此抽象路径名表示的目录中的文件和目录。

public String[] list()

用法:

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File(".git");
        // [config, description, HEAD, hooks, info, objects, refs]
        System.out.println(Arrays.toString(f.list()));
    }
}

返回一个字符串数组,命名由此抽象路径名表示的目录中满足指定过滤器的文件和目录。

public String[] list(FilenameFilter filter)

用法:

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File(".git");
        // [config, description, HEAD, hooks, info, objects, refs]
        String[] list = f.list(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.contains("i");
            }
        });
        // [config, description, info]
        System.out.println(Arrays.toString(list));
    }
}
listFiles()

返回一个抽象路径名数组,表示由该抽象路径名表示的目录中的文件。

public File[] listFiles()

用法:

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File(".git");
        File[] files = f.listFiles();
        // [.git\config, .git\description, .git\HEAD, .git\hooks, .git\info, .git\objects, .git\refs]
        System.out.println(Arrays.toString(files));
    }
}
练习
  • 列出指定目录下文件或者文件夹,包括子目录的内容。
  • 也就是列出指定目录下所有内容。
import java.io.File;
import java.io.IOException;

public class FileDemo {

    public static void main(String[] args) throws IOException {
        File dir = new File("F:/");
        showDir(dir, 0);
    }

    public static String getLevel(int level) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < level; i++) {
            sb.insert(0, "|--");
        }
        return sb.toString();
    }

    /**
     * 因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
     * 在列出过程中出现的还是目录的话,还可以再次调用本功能。
     * 也就是函数自身调用自身。
     * 这种表现形式,或者编程手法,称为递归。
     * 
     * 递归要注意:
     * 
     * 1,限定条件。
     * 2,要注意递归的次数。尽量避免内存溢出。
     */
    public static void showDir(File dir, int level) {
        System.out.println(getLevel(level) + dir);
        level++;

        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    showDir(file, level);
                } else {
                    System.out.println(getLevel(level) + file);
                }
            }
        }
    }
}

修改

renameTo(File dest)

重命名由此抽象路径名表示的文件。

public boolean renameTo(File dest)

用法:

import java.io.File;
import java.io.IOException;

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File f = new File("demo.txt");
        // true
        System.out.println(f.renameTo(new File("demo1.txt")));
    }
}

Properties

  • Properties是Hashtable的子类。
  • 也就是说它具备Map集合的特点。而且它里面存储的是键值对都是字符串。
  • 是集合中和IO流的结合的集合容器。
  • 该对象的特点:
    • 可以利用键值对形式的配置文件。
import java.util.Properties;

public class FileDemo {
    public static void main(String[] args) {
        Properties prop = new Properties();
    }
}

常用方法:

设置

setProperty()

类似Hashtable方法put 。 提供与getProperty方法的并行性 。 强制使用字符串的属性键和值。 返回的值是Hashtable调用put的结果。

public Object setProperty(String key, String value)

参数
+ key 要放入此属性列表的关键字。
+ value 对应的值为 key 。

用法:

import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) {
        Properties prop = new Properties();
        prop.setProperty("zhangsan", "23");
        prop.setProperty("lishi", "20");
        // {zhangsan=23, lishi=20}
        System.out.println(prop);
    }
}

获取

getProperty()

使用此属性列表中指定的键搜索属性。 如果在此属性列表中找不到该键,则会默认属性列表及其默认值递归。 如果找不到属性,该方法返回null 。

public String getProperty(String key)

用法:

import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) {
        Properties prop = new Properties();
        prop.setProperty("zhangsan", "23");
        prop.setProperty("lishi", "20");
        // prop.getProperty("lishi") = 20
        System.out.println("prop.getProperty(\"lishi\") = " + prop.getProperty("lishi"));
        // prop.getProperty("lishi2") = null
        System.out.println("prop.getProperty(\"lishi2\") = " + prop.getProperty("lishi2"));
    }
}

使用此属性列表中指定的键搜索属性。 如果在此属性列表中找不到该键,则会默认属性列表及其默认值递归。 如果找不到属性,该方法返回默认值参数。

public String getProperty(String key, String defaultValue)

参数
+ key 哈希表键。
+ defaultValue 默认值。

用法:

import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) {
        Properties prop = new Properties();
        prop.setProperty("zhangsan", "23");
        prop.setProperty("lishi", "20");
        // prop.getProperty("lishi","30") = 20
        System.out.println("prop.getProperty(\"lishi\",\"30\") = " + prop.getProperty("lishi", "30"));
        // prop.getProperty("lishi2", "找不到") = 找不到
        System.out.println("prop.getProperty(\"lishi2\", \"找不到\") = " + prop.getProperty("lishi2", "找不到"));
    }
}
stringPropertyNames()

返回此属性列表中的一组键,其中键及其对应的值为字符串,包括默认属性列表中的不同键,如果尚未从主属性列表中找到相同名称的键。 键或值不是类型String的属性被省略。

public Set<String> stringPropertyNames()

语法:

import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) {
        Properties prop = new Properties();
        prop.setProperty("zhangsan", "23");
        prop.setProperty("lishi", "20");

        for (String spn : prop.stringPropertyNames()) {
            System.out.println("key=" + spn + ", value=" + prop.getProperty(spn));
        }
    }
}
list()

将此属性列表打印到指定的输出流。 此方法对调试非常有用。

public void list(PrintStream out)
public void list(PrintWriter out)

用法:

import java.io.*;
import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();

        prop.load(new FileReader("userinfo.txt"));

        prop.list(new PrintStream("test.txt"));

        prop.list(new PrintWriter("test2.txt"));
        /*-- listing properties --
          zhangsan=23
          lishi=20
          wangwu=21*/
        prop.list(System.out);
    }
}

读取文件到Properties集合中

import java.io.*;
import java.util.Properties;

/**
 * 需求:将流中的数据存储到集合中。
 * 思路:
 * 1.用一个流和userinof.txt文件关联
 * 2.读取第一行数据,将该行数据用“=”进行切割。
 * 3.等号左边为键,右边为值,存入到Properties集合中。
 */
public class PropertieDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new FileReader("userinfo.txt"));

        Properties prop = new Properties();

        String line = null;
        while ((line = br.readLine()) != null) {
            String[] arr = line.split("=");
            prop.setProperty(arr[0], arr[1]);
        }
        br.close();
        // prop = {zhangsan=23, wangwu=21, lishi=20}
        System.out.println("prop = " + prop);
    }
}
load()

以简单的线性格式从输入字符流读取属性列表(关键字和元素对)。

public void load(Reader reader) throws IOException

用法:

import java.io.*;
import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        prop.load(new FileReader("userinfo.txt"));
        // prop = {zhangsan=23, wangwu=21, lishi=20}
        System.out.println("prop = " + prop);
    }
}

从输入字节流读取属性列表(键和元素对)。

public void load(InputStream inStream) throws IOException

用法:

import java.io.*;
import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        prop.load(new FileInputStream("userinfo.txt"));
        // prop = {zhangsan=23, wangwu=21, lishi=20}
        System.out.println("prop = " + prop);
    }
}

修改

setProperty()

类似Hashtable方法put 。 提供与getProperty方法的并行性 。 强制使用字符串的属性键和值。 返回的值是Hashtable调用put的结果。

public Object setProperty(String key, String value)

用法:

import java.io.*;
import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        prop.load(new FileReader("userinfo.txt"));
        /*-- listing properties --
        zhangsan=23
        lishi=20
        wangwu=21*/
        prop.list(System.out);

        prop.setProperty("lishi", "22");
        /*-- listing properties --
        zhangsan=23
        lishi=22
        wangwu=21*/
        prop.list(System.out);
    }
}

存储

store()

将此Properties表中的此属性列表(键和元素对)以适合使用load(Reader)方法的格式写入输出字符流。

public void store(Writer writer, String comments) throws IOException

参数
+ writer 输出字符流写入器。
+ comments 属性列表的描述。

将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法加载到Properties表中的格式输出流。

public void store(OutputStream out, String comments) throws IOException

参数
+ writer 输出字符流写入器。
+ comments 属性列表的描述。

用法:

import java.io.*;
import java.util.Properties;

public class PropertieDemo {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();
        prop.load(new FileReader("userinfo.txt"));
        /*-- listing properties --
        zhangsan=23
        lishi=21
        wangwu=20*/
        prop.list(System.out);

        prop.setProperty("wangwu", "22");

        // userinfo.txt 顶部会多出一行“ #by webb ”
        prop.store(new FileWriter("userinfo.txt"), "by webb");
        prop.store(new FileOutputStream("userinfo2.txt"), "by webb");

        /*-- listing properties --
        zhangsan=23
        lishi=21
        wangwu=22*/
        prop.list(System.out);
    }
}

练习:使用Properties类记录程序运行次数。

import java.io.*;
import java.util.Properties;

/**
 * 用于记录应用程序运行次数。
 * 如果使用次数已到,那么给出注册提示。
 * 
 * 很容易想到的是:计数器。
 * 可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。
 * 可是随着该应用程序的退出,该计数器也在内存中消失了。
 * 
 * 下一次在启动该程序,又重新开始从0计数。
 * 这样不是我们想要的。
 * 
 * 程序即使结束,该计数器的值也存在。
 * 下次程序启动在会先加载该计数器的值并加1后在重新存储起来。
 * 
 * 所以要建立一个配置文件。用于记录该软件的使用次数。
 * 
 * 该配置文件使用键值对的形式。
 * 这样便于阅读数据,并操作数据。
 * 
 * 键值对数据是map集合。
 * 数据是以文件形式存储,使用io技术。
 * 那么map+io -->properties.
 * 
 * 配置文件可以实现应用程序数据的共享。
 */
public class RunCount {
    public static void main(String[] args) throws IOException {
        Properties prop = new Properties();

        File file = new File("count.ini");
        if (!file.exists()) {
            file.createNewFile();
        }

        FileInputStream fs = new FileInputStream(file);

        prop.load(fs);

        int count = 0;
        String value = prop.getProperty("time");
        if (value != null) {
            count = Integer.parseInt(value);
            if (count>=5) {
                System.out.println("您好,使用的此处已到,请购买VIP服务。");
            }
        }
        System.out.println(count);
        count++;

        prop.setProperty("time", count + "");

        prop.store(new FileOutputStream(file),"");
    }
}

打印流

该提供了打印方法,可以将各种数据类型的数据都原样打印。

PrintStream

字节打印流
字节打印流构造函数可以接收的参数类型:
+ file对象。File
+ 字符串路径。String
+ 字节输出流。OutputStream

import java.io.*;

public class PrintStreamDemo {
    public static void main(String[] args) throws IOException {
        BufferedReader bfr = new BufferedReader(new InputStreamReader(System.in));

        // 获取控制台输入的内容输出到控制台中。
        // PrintWriter pw = new PrintWriter(System.out);
        // 获取控制台输入的内容输出到文件中。
        PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter("print.txt")), true);

        String line = null;
        while ((line = bfr.readLine()) != null) {
            if ("over".equals(line)) {
                break;
            }
            pw.println(line.toUpperCase());
            /*pw.flush();*/
        }
        pw.close();
        bfr.close();
    }
}

PrintWriter

字符打印流
字符打印流构造函数可以接收的参数类型:
+ file对象。File
+ 字符串路径。String
+ 字节输出流。OutputStream
+ 字符输出流。Writer

序列流

SequenceInputStream

表示其他输入流的逻辑级联。 它从一个有序的输入流集合开始,从第一个读取到文件的结尾,然后从第二个文件读取,依此类推,直到最后一个输入流达到文件的结尾。
该流可用于多线程下载。

import java.io.*;
import java.util.Enumeration;
import java.util.Vector;

public class SequenceInputStreamDemo {
    public static void main(String[] args) throws IOException {
        Vector<FileInputStream> v = new Vector<>();
        v.add(new FileInputStream("1.txt"));
        v.add(new FileInputStream("2.txt"));
        v.add(new FileInputStream("3.txt"));

        Enumeration<FileInputStream> en = v.elements();
        SequenceInputStream sis = new SequenceInputStream(en);

        FileOutputStream fos = new FileOutputStream("6.txt");

        byte[] buf = new byte[1024];
        int len = 0;

        while ((len = sis.read(buf)) != -1) {
            fos.write(buf, 0, len);
        }
        fos.close();
        sis.close();
    }
}

切割

该功能通常用于分段上传和下载。

import java.io.*;

public class SplitFileDemo {
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("1.mp3"));

        BufferedOutputStream bos = null;

        byte[] buf = new byte[1024 * 1024];

        int len = 0;
        int count = 1;

        while ((len = bis.read(buf)) != -1) {
            bos = new BufferedOutputStream(new FileOutputStream(count + ".part"));
            bos.write(buf, 0, len);
            bos.close();
            count++;
        }
        bis.close();
    }
}

操作对象

ObjectInputStream与ObjectOutputStream

  • 被操作的对象需要实现Serializable(标记接口);
  • Person类
import java.io.Serializable;

public class Person implements Serializable {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

ObjectInputStream

把obj.txt文件中对象保存内存中。

import java.io.*;

public class ObjectInputDemo {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.txt"));
        Person p = (Person) ois.readObject();
        // p = Person{name='zhangshan', age=22}
        System.out.println("p = " + p);
    }
}

ObjectOutputStream

将对象导出到obj.txt文件中。

import java.io.*;

public class ObjectOutputDemo {
    public static void main(String[] args) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.txt"));
        oos.writeObject(new Person("zhangshan", 22));
        oos.close();
    }
}

管道流

PipedInputStream和PipedOutputStream

  • 输入输出可以直接进行连接,通过结合线程使用。

PipedInputStream

管道输入流应连接到管道输出流; 管道输入流然后提供写入管道输出流的任何数据字节。 典型地,数据被从一个读PipedInputStream对象由一个线程并且数据被写入到对应的PipedOutputStream通过一些其它线程。 不建议尝试从单个线程使用这两个对象,因为它可能会使线程死锁。 管道输入流包含一个缓冲区,在读取操作中将读取操作与限制内的操作相分离。 的管道被认为是broken如果正在提供的数据字节到连接的管道输出流中的线程不再存活。

PipedOutputStream

管道输出流可以连接到管道输入流以创建通信管道。 管道输出流是管道的发送端。 典型地,数据被写入到一个PipedOutputStream由一个线程对象和数据被从连接读取PipedInputStream通过一些其它线程。 不建议尝试从单个线程使用这两个对象,因为它可能会使线程死锁。 管被说成是broken如果从连接读取数据字节的螺纹管道输入流不再存活。

import java.io.*;

class Read implements Runnable {
    private PipedInputStream in;

    public Read(PipedInputStream in) {
        this.in = in;
    }

    @Override
    public void run() {
        byte[] buf = new byte[1024];
        try {
            System.out.println("正在读取数据,没有遇到堵塞。");
            int len = in.read(buf);
            System.out.println(new String(buf, 0, len));
            System.out.println("数据读取完成,阻塞结束");
            in.close();
        } catch (IOException e) {
            System.out.println("管道输入流失败");
        }
    }
}

class Write implements Runnable {
    private PipedOutputStream out;

    public Write(PipedOutputStream out) {
        this.out = out;
    }

    @Override
    public void run() {
        try {
            System.out.println("正在写入数据,请耐心等待");
            Thread.sleep(6000);
            out.write("Hello World".getBytes());
            out.close();
        } catch (IOException | InterruptedException e) {
            System.out.println("管道输出流失败");
        }
    }
}


public class PipedStreamDemo {
    public static void main(String[] args) throws IOException {
        PipedInputStream in = new PipedInputStream();
        PipedOutputStream out = new PipedOutputStream();
        in.connect(out);

        Read r = new Read(in);
        Write w = new Write(out);
        new Thread(r).start();
        new Thread(w).start();
    }
}

RandomAccessFile

  • 随机访问文件,自身具备读写的方法。
  • 通过skipBytes(int x),seek(int x)来达到随机访问。

语法:

// 创建一个随机访问文件流从File参数指定的文件中读取,并可选地写入文件。
RandomAccessFile(File file, String mode) 
// 创建随机访问文件流,以从中指定名称的文件读取,并可选择写入文件。 
RandomAccessFile(String name, String mode) 

参数:
+ file 文件对象
+ name 与系统相关的文件名
+ mode 访问模式

mode参数介绍

介绍
“r”以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException
“rw”打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。
rws”打开以便读取和写入,对于 "rw",还要求对文件的内容或元数据的每个更新都同步写入到底层存储设备。
“rwd”打开以便读取和写入,对于 "rw",还要求对文件内容的每个更新都同步写入到底层存储设备。

用法:

import java.io.*;

public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");
    }
}

常用方法:

write()

写入数据。
用法:

import java.io.*;

public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");
        raf.write("Hello RandomAccessFile".getBytes());
    }
}
writeBoolean()

将 boolean写入文件作为一个字节值。

public final void writeBoolean(boolean v) throws IOException
writeByte()

按单字节值将 byte 写入该文件。写入从文件指针的当前位置开始。

public final void writeByte(int v) throws IOException
writeShort()

按两个字节将 short 写入该文件,先写高字节。写入从文件指针的当前位置开始。

public final void writeShort(int v) throws IOException
writeChar()

按双字节值将 char 写入该文件,先写高字节。写入从文件指针的当前位置开始。

public final void writeChar(int v) throws IOException
writeInt()

按四个字节将 int 写入该文件,先写高字节。写入从文件指针的当前位置开始。

public final void writeInt(int v) throws IOException
writeLong()

按八个字节将 long 写入该文件,先写高字节。写入从文件指针的当前位置开始。

public final void writeLong(long v) throws IOException
writeFloat()

使用 Float 类中的 floatToIntBits 方法将浮点参数转换为一个 int,然后按四字节数量将该 int 值写入该文件,先写高字节。写入从文件指针的当前位置开始。

public final void writeFloat(float v) throws IOException
writeDouble()

使用 Double 类中的 doubleToLongBits 方法将双精度参数转换为一个 long,然后按八字节数量将该 long 值写入该文件,先定高字节。写入从文件指针的当前位置开始。

public final void writeDouble(double v) throws IOException
writeBytes()

按字节序列将该字符串写入该文件。该字符串中的每个字符均按顺序写出,并丢弃其高八位。写入从文件指针的当前位置开始。

public final void writeBytes(String s) throws IOException
writeChars()

按字符序列将一个字符串写入该文件。每个字符均写入数据输出流,类似于使用 writeChar 方法。写入从文件指针的当前位置开始。

public final void writeChars(String s) throws IOException
writeUTF()

使用 modified UTF-8 编码以与机器无关的方式将一个字符串写入该文件。

public final void writeUTF(String str) throws IOException

read()

读取数据。

用法:

import java.io.*;

public class RandomAccessFileDemo { 
    public static void main(String[] args) throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ran.txt", "r");
        System.out.println(raf.read());
    }
}
readBoolean()

从此文件读取一个 boolean。此方法从该文件的当前文件指针开始读取单个字节。

public final boolean readBoolean() throws IOException
readByte()

从此文件读取一个有符号的八位值。

public final byte readByte() throws IOException
readUnsignedByte()

从此文件读取一个无符号的八位数。

public final int readUnsignedByte() throws IOException
readShort()

从此文件读取一个有符号的 16 位数。

public final short readShort() throws IOException
readUnsignedShort()

从此文件读取一个无符号的 16 位数。

public final int readUnsignedShort() throws IOException
readChar()

从此文件读取一个字符。此方法从该文件的当前文件指针开始读取两个字节。

public final char readChar() throws IOException
readInt()

从此文件读取一个有符号的 32 位整数。

public final int readInt() throws IOException
readLong()

从此文件读取一个有符号的 64 位整数。

public final long readLong() throws IOException
readFloat()

从此文件读取一个 float。

public final float readFloat() throws IOException
readDouble()

从此文件读取一个 double。

public final double readDouble() throws IOException
readUTF()

从此文件读取一个字符串。该字符串已使用 UTF-8 修改版格式进行编码。

public final String readUTF() throws IOException

seek()

设置文件指针偏移,从该文件的开头测量,发生下一次读取或写入。

public void seek(long pos) throws IOException

用法1:读取数据

public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ran.txt", "r");
        // raf.length() = 22
        System.out.println("raf.length() = " + raf.length());
        // Hello RandomAccessFile
        System.out.println(raf.readLine());

        raf.seek(6);
        // R
        System.out.println((char) raf.read());
    }
}

用法2:写入数据

import java.io.*;

public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");
        // raf.length() = 22
        System.out.println("raf.length() = " + raf.length());
        // Hello RandomAccessFile
        System.out.println(raf.readLine());

        raf.seek(6);
        // R
        System.out.println((char) raf.read());

        raf.seek(50);
        raf.write("Test".getBytes());
    }
}

skipBytes()

尝试跳过n字节的输入,丢弃跳过的字节。

public int skipBytes(int n) throws IOException

用法1:读取数据

import java.io.*;

public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {
        RandomAccessFile raf = new RandomAccessFile("ran.txt", "r");
        // raf.length() = 22
        System.out.println("raf.length() = " + raf.length());
        // Hello RandomAccessFile
        raf.skipBytes(6);
        // R
        System.out.println((char) raf.read());
    }
}

用法2:写入数据

import java.io.*;

public class RandomAccessFileDemo {
    public static void main(String[] args) throws IOException {
        // ran.txt内容的Hello RandomAccessFile
        RandomAccessFile raf = new RandomAccessFile("ran.txt", "rw");
        raf.skipBytes(6);
        // Hello TestomAccessFile
        raf.write("Test".getBytes());
    }
}

DataInputStream与DataOutputStream

可以用于操作基本数据类型的流对象。

DataInputStream

  • 数据输入流允许应用程序以独立于机器的方式从底层输入流读取原始Java数据类型。 应用程序使用数据输出流来写入稍后可以被数据输入流读取的数据。
  • DataInputStream对于多线程访问来说不一定是安全的。 线程安全是可选的,是本课程中用户的责任。
import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
    }
}

read()

从包含的输入流中读取一些字节数,并将它们存储到缓冲区数组 b 。

public final int read(byte[] b) throws IOException

从包含的输入流读取最多len个字节的数据到字节数组。

public final int read(byte[] b, int off, int len) throws IOException

参数
+ b 读取数据的缓冲区。
+ off 目标数组 b的起始偏移量
+ len 读取的最大字节数。

用法:

import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
        byte[] buf = new byte[1024];
        int len = 0;
        while ((len = dis.read(buf)) != -1) {
            System.out.println(new String(buf, 0, len));
        }
    }
}
readBoolean()

见的总承包 readBoolean的方法 DataInput 。

public final boolean readBoolean() throws IOException
readInt()

见 readInt方法 DataInput的一般合同。

public final int readInt() throws IOException
readDouble()

见 readDouble方法 DataInput的总体合同。

public final double readDouble() throws IOException

用法:

import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
        int i = dis.readInt();
        // i = 100
        System.out.println("i = " + i);
        boolean b = dis.readBoolean();
        // b = true
        System.out.println("b = " + b);
        double v = dis.readDouble();
        // v = 99.99
        System.out.println("v = " + v);

        dis.close();
    }
}

readUTF()

见 readUTF法 DataInput的一般合同。

public final String readUTF() throws IOException

用法:

import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
        // 你好
        System.out.println(dis.readUTF());
    }
}

DataOutputStream

数据输出流使应用程序以便携式方式将原始Java数据类型写入输出流。 然后应用程序可以使用数据输入流来读取数据。
用法:

import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
        dos.close();
    }
}

write()

写入 len从指定的字节数组起始于偏移 off基础输出流。

write(byte[] b, int off, int len) 

将指定的字节(参数 b的低8位)写入底层输出流。

write(int b) 
writeBoolean()

将 boolean写入底层输出流作为1字节值。

public final void writeBoolean(boolean v) throws IOException
writeInt()

将底层输出流写入int作为四字节,高位字节。

public final void writeInt(int v) throws IOException
writeDouble()

双参数传递给转换long使用doubleToLongBits方法在类Double ,然后写入该long值基础输出流作为8字节的数量,高字节。

public final void writeDouble(double v) throws IOException

用法:

import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));

        dos.writeInt(100);
        dos.writeBoolean(true);
        dos.writeDouble(99.99);

        dos.close();
    }
}
writeUTF()

使用机器无关的方式使用modified UTF-8编码将字符串写入基础输出流。

public final void writeUTF(String str) throws IOException

用法:

import java.io.*;

public class DataStreamDemo {
    public static void main(String[] args) throws IOException {
        DataOutputStream dos = new DataOutputStream(new FileOutputStream("data.txt"));
        dos.writeUTF("你好");
        dos.close();
    }
}

ByteArrayInputStream与ByteArrayOutputStream

  • 用于操作字节流的流对象。
  • ByteArrayInputStream与ByteArrayOutputStream这两个流对象都操作数组,并没有使用系统资源,所以不需要关闭资源。

ByteArrayInputStream

在构造函数的时候,需要接收数据源,而且数据源的是一个字节数组。

ByteArrayOutputStream

在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。

用法:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public class ByteArrayStreamDemo {
    public static void main(String[] args) {
        // 数据源
        ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFGHIJKL".getBytes());

        // 数据目的
        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        int by = 0;
        while ((by = bis.read()) != -1) {
            bos.write(by);
        }

        // bos.size() = 12
        System.out.println("bos.size() = " + bos.size());
        // bos.toString() = ABCDEFGHIJKL
        System.out.println("bos.toString() = " + bos.toString());
    }
}

字符编码

  • 字符流的出现为了方便操作字符。
  • 更重要是的加入了编码转换。
  • 通过子类转换流来完成。
    • InputStreamReader
    • OutputStreamWriter
  • 在两个对象进行构造的时候可以加入字符集。

常见的编码表

  • ASCII:美国信息交换标准代码。
    • 用一个字节的7位可以标示。
  • ISO8859-1:阿拉丁表。欧洲编码表。
    • 用一个字节的8位表示。
  • GB2312:中国的中文编码表
  • GBK:中国的中文编码表升级,融合了更多的中文文字字符号。
  • Unicode:国际标准编码,融合了多种文字。
    • 所有文字都用两个字符来表示,java语言使用的就是unicode。
  • UTF-8:最多用三个字节来表示一个字符。

InputStreamReader

InputStreamReader是从字节流到字符流的桥:它读取字节,并使用指定的charset将其解码为字符 。
用法:

import java.io.*;
import java.nio.charset.StandardCharsets;

public class EncodeStream {
    public static void main(String[] args) throws IOException {
        InputStreamReader gbk = new InputStreamReader(new FileInputStream("gbk.txt"), "GBK");
        char[] buf = new char[10];
        int len = gbk.read(buf);
        // 你好 GBK
        System.out.println(new String(buf, 0, len));
        gbk.close();

        InputStreamReader utf = new InputStreamReader(new FileInputStream("utf.txt"), StandardCharsets.UTF_8);
        len = utf.read(buf);
        // 你好 UTF-8
        System.out.println(new String(buf, 0, len));
        utf.close();
    }
}

OutputStreamWriter

OutputStreamWriter是字符的桥梁流以字节流:向其写入的字符编码成使用指定的字节charset 。

用法:

import java.io.*;
import java.nio.charset.StandardCharsets;

public class EncodeStream {
    public static void main(String[] args) throws IOException {
        OutputStreamWriter gbk = new OutputStreamWriter(new FileOutputStream("gbk.txt"), "GBK");
        gbk.write("你好 GBK");
        gbk.close();

        OutputStreamWriter utf = new OutputStreamWriter(new FileOutputStream("utf.txt"), StandardCharsets.UTF_8);
        utf.write("你好 UTF-8");
        utf.close();
    }
}

编码

字符串转换字节数组。

String --> byte[]; 
str.getBytes(charsetName);

解码

字节数转换字符串。

byte[] --> String;
new String(byte[], charsetName);

用法:

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

public class EncodeStream {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "你好";
        byte[] b1 = s.getBytes();
        /*  编码
            [-28, -67, -96, -27, -91, -67]*/
        System.out.println(Arrays.toString(b1));
        /*  解码
            你好*/
        System.out.println(new String(b1));

        byte[] b2 = s.getBytes("GBK");
        /*  编码
            [-28, -67, -96, -27, -91, -67]*/
        System.out.println(Arrays.toString(b2));
        /*  解码
            你好*/
        System.out.println(new String(b2,"GBK"));
    }
}

练习

需求:
+ 有五个学生,每个学生有3门课的成绩,
+ 从键盘输入以上数据(包括姓名,三门课成绩),
+ 输入的格式:如:zhagnsan,30,40,60计算出总成绩,
+ 并把学生的信息和计算出的总分数高低顺序存放在磁盘文件”stud.txt”中。
思路:
1. 通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
2. 因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序,所以可以使用TreeSet。
3. 将集合的信息写入到一个文件中。

import java.io.*;
import java.util.*;

class Student implements Comparable<Student> {
    private String name;
    private int ma,cn,en;
    private int sum;

    Student(String name,int ma,int cn,int en) {
        this.name = name;
        this.ma = ma;
        this.cn = cn;
        this.en = en;
        sum = ma + cn + en;
    }


    public int compareTo(Student s) {
        int num = new Integer(this.sum).compareTo(new Integer(s.sum));
        if(num==0)
            return this.name.compareTo(s.name);
        return num;
    }

    public String getName() {
        return name;
    }
    public int getSum() {
        return sum;
    }

    public int hashCode() {
        return name.hashCode()+sum*78;
    }
    public boolean equals(Object obj) {
        if(!(obj instanceof Student))
            throw new ClassCastException("类型不匹配");
        Student s = (Student)obj;

        return this.name.equals(s.name) && this.sum==s.sum;
    }

    public String toString() {
        return "student["+name+", "+ma+", "+cn+", "+en+"]";
    }
}

class StudentInfoTool {
    public static Set<Student> getStudents()throws IOException {
        return getStudents(null);
    }

    public static Set<Student> getStudents(Comparator<Student> cmp)throws IOException {
        BufferedReader bufr = 
            new BufferedReader(new InputStreamReader(System.in));

        String line = null;

        Set<Student> stus  = null;
        if(cmp==null) {
            stus = new TreeSet<Student>();
        }
        else {
            stus = new TreeSet<Student>(cmp);
        }
        while((line=bufr.readLine())!=null) {
            if("over".equals(line))
                break;

            String[] info = line.split(",");

            Student stu = new Student(info[0],Integer.parseInt(info[1]),
                                        Integer.parseInt(info[2]),
                                        Integer.parseInt(info[3]));


            stus.add(stu);
        }

        bufr.close();
        return stus;
    }

    public static void write2File(Set<Student> stus)throws IOException {
        BufferedWriter bufw = new BufferedWriter(new FileWriter("stuinfo.txt"));

        for(Student stu : stus) {
            bufw.write(stu.toString()+"\t");
            bufw.write(stu.getSum()+"");
            bufw.newLine();
            bufw.flush();
        }

        bufw.close();
    }
}



class StudentInfoTest {
    public static void main(String[] args) throws IOException{
        Comparator<Student> cmp = Collections.reverseOrder();
        Set<Student> stus = StudentInfoTool.getStudents(cmp);
        StudentInfoTool.write2File(stus);
    }
}