5. IO流

5.1 File类

5.1.1 文件对象的构造

这个类对一个文件(夹)的描述。

关于路径分隔符:

路径分隔符是对目录的分隔。表示一层嵌套关系。

在windows系统下,分隔符是:\

在UNIX体系下,分隔符是:/

构造方法 参数
File(String pathName) 使用一个指定的文件路径来实例化一个File对象
File(String parent, String name) 给定一个父目录路径和一个子文件名字,系统会自动的将其拼接在一起
File(File parent, String child) 给定一个父目录和一个子文件的名字,系统自动拼接路径
  1. public class FileDemo {
  2. public static void main(String[] args) {
  3. //File构造函数演示
  4. String pathName = "hello.java";
  5. File f1 = new File(pathName);
  6. System.out.println(f1);
  7. File f2 = new File("/Users/IdeaProjects/JavaSE","hello.java");
  8. System.out.println(f2);
  9. //将parent封装成file对象。
  10. File dir = new File("/Users/IdeaProjects/JavaSE");
  11. File f3 = new File(dir,"hello.java");
  12. System.out.println(f3);
  13. }
  14. }

5.1.2 文件和文件夹的常用方法

常用方 描述
boolean exists() 用来描述指定的路径下到底有没有文件(夹)存在。
boolean isFile() 判断指定路径的内容是不是一个文件
boolean isDirectory() 判断指定路径的内容是不是一个文件夹
boolean mkdir() 在指定的路径创建文件夹,返回值代表创建成功还是失败
boolean mkdirs() 在指定的路径创建文件夹,可以创建多级目录
boolean createNewFile() 在指定的路径创建一个空文件,会有一个IOException
boolean isHidden() 判断一个文件是否是隐藏的
  1. public static void main(String[] args) throws IOException {
  2. // 对文件或者文件加进行操作。
  3. File file = new File("/Users/IdeaProjects/JavaSE/file.txt");
  4. //获取文件的绝对路径,即全路径
  5. String absPath = file.getAbsolutePath();
  6. //File中封装的路径是什么获取到的就是什么。
  7. String path = file.getPath();
  8. //获取文件名称
  9. String filename = file.getName();
  10. //获取文件大小
  11. long size = file.length();
  12. System.out.println("absPath="+absPath);
  13. System.out.println("path="+path);
  14. System.out.println("filename="+filename);
  15. System.out.println("size="+size);
  16. // 创建文件,如果文件不存在,创建 true 如果文件存在,则不创建 false。
  17. // 如果路径错误,IOException。
  18. boolean file1 = file.createNewFile();
  19. System.out.println("file1=" + file1);
  20. //-----------删除文件操作-------注意:不去回收站。慎用------
  21. boolean flag = file.delete();
  22. System.out.println("flag="+flag);
  23. //-----------需要判断文件是否存在------------
  24. boolean falg1 = file.exists();
  25. System.out.println("falg1="+falg1);
  26. //-----------对目录操作 创建,删除,判断------------
  27. File dir = new File("/Users/IdeaProjects/JavaSE/");
  28. //mkdir()创建单个目录。//dir.mkdirs();创建多级目录
  29. boolean flag2 = dir.mkdir();
  30. System.out.println("flag2="+flag2);
  31. //删除目录时,如果目录中有内容,无法直接删除。
  32. boolean flag3 = dir.delete();
  33. //只有将目录中的内容都删除后,保证该目录为空,这个目录才可以删除。
  34. System.out.println("flag3=" + flag3);
  35. //-----------判断文件,目录------------
  36. File file3 = new File("/Users/IdeaProjects/JavaSE/");
  37. // 要判断是否是文件还是目录,必须先判断存在。
  38. System.out.println(file3.isFile());
  39. System.out.println(file3.isDirectory());
  40. //-----------目录遍历------------
  41. File dir1 = new File("/Users/IdeaProjects");
  42. //获取的是目录下的当前的文件以及文件夹的名称。
  43. String[] names = dir.list();
  44. for(String name : names){
  45. System.out.println(name);
  46. }
  47. //获取目录下当前文件以及文件对象,只要拿到了文件对象,那么就可以获取其中想要的信息
  48. File[] files = dir.listFiles();
  49. for(File file4 : files){
  50. System.out.println(file4);
  51. }
  52. }

5.1.3 文件过滤器

实现自己的文件过滤器

  1. public class FileDemo{
  2. public static void main(String[] args) {
  3. //获取扩展名为.java所有文件
  4. //创建File对象
  5. File file = new File("/Users/IdeaProjects");
  6. //获取指定目录下的文件夹
  7. File[] files = file.listFiles(new FileFileterByDir());
  8. //遍历获取到的所有符合条件的文件
  9. for (File f : files) {
  10. System.out.println(f);
  11. }
  12. }
  13. }
  14. 自定义类继承FileFilter过滤器接口
  15. //文件过滤器
  16. class FileFileterByDir implements FileFilter{
  17. public boolean accept(File pathname) {
  18. return pathname.isDirectory();
  19. }
  20. }

5.2 流的分类

分类:

方向:输入流和输出流

数据单元:字节流和字符流

InputStream: 字节输入流的超类

OutputStream: 字节输出流的超类

Reader: 字符输入流

Writer: 字符输出流

无论是使用什么流,在使用结束之后,一定要记得关闭这个流。

5.3 字节流

InputStream:

int read(byte[] arr):

参数:从流中读取数据,需要使用到一个字节数组。read方法会将读取到的数据填充到这个字节数组中。所以,读取完成后,我们直接从这个字节数组中取数据即可。

返回值:每次读取数据后,返回这一次读取到了多少个字节的数据。如果这个方法返回值为-1,说明本次没有读取到任何数据,读取完成。

  1. class FileInputStreamDemo {
  2. public static void main(String[] args) throws Exception {// 先声明
  3. InputStream is = null;
  4. try {
  5. // 实例化一个流
  6. is = new FileInputStream(new File("/Users/IdeaProjects/JavaSE/src/kaikeba/com/ArraysDemo.java"));
  7. // InputStream: 字节输入流,数据是以字节为单位
  8. // 从管道中读取数据:
  9. // 实例化一个数组,用来存储每次读取到的数据
  10. byte[] contents = new byte[100];
  11. // 用来记录每次读取到了多少数据
  12. int length = 0;
  13. // 循环读取,将每次读取到的数据长度给length赋值,并判断是否为-1
  14. while ((length = is.read(contents)) != -1) {
  15. // 通过一个字节数组实例化一个字符串
  16. String str = new String(contents, 0, length);
  17. System.out.print(str);
  18. }
  19. } catch (FileNotFoundException e) {
  20. e.printStackTrace();
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. } finally {
  24. // 判断是否为空,因为如果最开始实例化的时候,文件不存在,则is实例化失败,依然为null
  25. // 此时,如果is是null,那么再去关闭的时候,就会出现NullPointerException
  26. if (is != null) {
  27. try {
  28. is.close();
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }
  34. }
  35. }

outputStream:操作的数据都是字节,定义了输出字节流的基本共性功能方法。

OutputStream有很多子类,其中子类FileOutputStream可用来写入数据到文件。

FileOutputStream类,即文件输出流,是用于将数据写入 File的输出流。

  1. public class FileOutputStreamDemo2 {
  2. public static void main(String[] args) throws Exception {
  3. File file = new File("myfile.txt");
  4. FileOutputStream fos = new FileOutputStream(file, true);
  5. String str = "\r\n"+"kaikeba.com";
  6. fos.write(str.getBytes());
  7. fos.close();
  8. }
  9. }

5.4 字符流

Reader:字符输入流

Writer:字符输出流

写操作

  1. public static void main(String[] args) throws IOException {
  2. //1.创建FileWriter的对象并关联对应的文件
  3. //注意点:
  4. //一:如果只写文件的名字,不写具体路径,默认路径是当前的工程
  5. //二:对于关联的文件,如果之前不存在,程序会自动创建一个,如果存在,会将原来的内容覆盖
  6. //三:可以自己指定路径,但是必须保证路径是真实存在的,否则报异常---FileNotFountException(系统找不到指定的路径。)
  7. FileWriter fileWriter = new FileWriter("fileWrite.txt");
  8. //调用写入方法
  9. //注意点四:在执行write方法时,数据被临时放到了流对象的内部数组中,这个数组是一个字节数组,会默认去查编码表
  10. fileWriter.write("晨晨");
  11. //刷新---将临时数组中的数据放入磁盘
  12. //fileWriter.flush();
  13. //4.关闭流--两个功能:a:关闭流 b:刷新
  14. //第五个注意点:流对象使用完后必须关闭
  15. fileWriter.close();
  16. //第六个注意点:当流对象关闭之后,不能再进行操作,否则会报异常:Stream closed
  17. //fileWriter.write("haha");
  18. }

读操作

  1. public static void main(String[] args) throws IOException {
  2. //1.创建文件读入流
  3. FileReader fileReader = new FileReader("/Users/IdeaProjects/JavaSE/src/kaikeba/com/ArraysDemo.java");
  4. //开始读操作
  5. /*
  6. * read():一个字符一个字符的读,每次读出一个字符
  7. */
  8. //a:将当前的字符读出 b:将当前的指针后移一位
  9. int value;
  10. while ((value = fileReader.read()) != -1) {
  11. System.out.println((char)value);
  12. }
  13. fileReader.close();
  14. }
  15. public static void main(String[] args) throws IOException {
  16. //1.创建文件读入流
  17. FileReader fileReader = new FileReader("/Users/liyunxia/IdeaProjects/JavaSE/src/kaikeba/com/ArraysDemo.java");
  18. //开始读操作
  19. /*
  20. * read(数组):一次可以读出多个字符 ,数组的作用:每次会将读出的字符临时放到这个数组中
  21. */
  22. /* 数组是临时存放数据的地方,我们会将读到的字符放到临时数组中,数组的大小决定了我们一次可以读到的字符个数.
  23. * 一般这个数组的大小<=1kB
  24. * 返回值代表本次读到的真实的字符个数,如果返回值是-1代表读完了.
  25. */
  26. char[] cbuf = new char[2];
  27. int num ;
  28. while ((num = fileReader.read(cbuf)) != -1) {
  29. //System.out.println(new String(cbuf)+" num:"+num);
  30. System.out.println(new String(cbuf,0,num)+" num:"+num);
  31. }
  32. fileReader.close();
  33. }

5.5 转换流

InputStreamReader、OutputStreamWriter

字节=》字符=》字节

转换流:保留了字符流对文本进行操作时候的便利性,保留了字节流的安全性。产生的一种新的流,主要用来做关于文本文件的处理。还可以解决:关于采用了不同字符集的文本之间的处理问题。可以使用指定的字符集来读取一个文本,也可以使用指定的字符集来写一个文本。

OutputStreamWriter

  1. public class InputStreamReaderDemo {
  2. public static void writeCN() throws Exception {
  3. //创建与文件关联的字节输出流对象
  4. FileOutputStream fos = new FileOutputStream("OutputStreamWriter.txt");
  5. //创建可以把字符转成字节的转换流对象,并指定编码
  6. OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
  7. //调用转换流,把文字写出去,其实是写到转换流的缓冲区中
  8. osw.write("你好");//写入缓冲区。
  9. osw.close();
  10. }
  11. }

InputStreamReader

  1. public class InputStreamReaderDemo {
  2. public static void main(String[] args) throws IOException {
  3. //演示字节转字符流的转换流
  4. readCN();
  5. }
  6. public static void readCN() throws IOException{
  7. //创建读取文件的字节流对象
  8. InputStream in = new FileInputStream("/Users/IdeaProjects/JavaSE/src/kaikeba/com/ArraysDemo.java");
  9. //创建转换流对象
  10. //InputStreamReader isr = new InputStreamReader(in);用本地默认码表读取,可能发生解码的错误
  11. InputStreamReader isr = new InputStreamReader(in,"utf-8");
  12. //使用转换流去读字节流中的字节
  13. int ch = 0;
  14. while((ch = isr.read())!=-1){
  15. System.out.println((char)ch);
  16. }
  17. //关闭流
  18. isr.close();
  19. }
  20. }

5.6 缓冲流

Java提供一套缓冲流,可提高IO流的读写速度;

缓冲流,根据流的分类分类字节缓冲流与字符缓冲流。

BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter

BufferInputStream、BufferedOutputStream:

  1. public class BufferedStreamDemo {
  2. public static void main(String[] args) throws IOException {
  3. //写数据到文件的方法
  4. write();
  5. read();
  6. }
  7. private static void write() throws IOException {
  8. //创建基本的字节输出流
  9. FileOutputStream fileOut = new FileOutputStream("bufferedStream.txt");
  10. //使用高效的流,把基本的流进行封装,实现速度的提升
  11. BufferedOutputStream out = new BufferedOutputStream(fileOut);
  12. //2,写数据
  13. out.write("hello".getBytes());
  14. //3,关闭流
  15. fileOut.close
  16. out.close();
  17. }
  18. private static void read() throws IOException {
  19. //1,创建缓冲流对象
  20. FileInputStream fileIn = new FileInputStream("bufferedStream.txt");
  21. //把基本的流包装成高效的流
  22. BufferedInputStream in = new BufferedInputStream(fileIn);
  23. //2,读数据
  24. int ch = -1;
  25. while ( (ch = in.read()) != -1 ) {
  26. //打印
  27. System.out.print((char)ch);
  28. }
  29. //3,关闭
  30. in.close();
  31. }
  32. }

BufferedReader、BufferedWriter

  1. public class BufferedWriterReaderDemo {
  2. public static void main(String[] args) throws IOException {
  3. write();
  4. read();
  5. }
  6. private static void write() throws IOException {
  7. //创建流
  8. //基本字符输出流
  9. FileWriter fileOut = new FileWriter("file.txt");
  10. //把基本的流进行包装
  11. BufferedWriter out = new BufferedWriter(fileOut);
  12. //2,写数据
  13. for (int i=0; i<5; i++) {
  14. out.write("hello");
  15. out.newLine();
  16. }
  17. //3,关闭流
  18. out.close();
  19. }
  20. private static void read() throws IOException {
  21. //1,创建流
  22. BufferedReader in = new BufferedReader(new FileReader("file.txt"));
  23. //2,读数据
  24. //一次一个字符
  25. //一次一个字符数组
  26. //一次读取文本中一行的字符串内容
  27. String line = null;
  28. while( (line = in.readLine()) != null ){
  29. System.out.println(line);
  30. }
  31. //3,关闭流
  32. in.close();
  33. }
  34. }

5.7 序列化和反序列化流

用于从流中读取对象的操作流 ObjectInputStream 称为反序列化流

用于向流中写入对象的操作流 ObjectOutputStream 称为序列化流

特点:用于操作对象。可以将对象写入到文件中,也可以从文件中读取对象

  1. import java.io.*;
  2. class Person implements Serializable {
  3. private String name;
  4. private int age;
  5. public Person() {
  6. super();
  7. }
  8. public Person(String name, int age) {
  9. super();
  10. this.name = name;
  11. this.age = age;
  12. }
  13. public String getName() {
  14. return name;
  15. }
  16. public void setName(String name) {
  17. this.name = name;
  18. }
  19. public int getAge() {
  20. return age;
  21. }
  22. public void setAge(int age) {
  23. this.age = age;
  24. }
  25. @Override
  26. public String toString() {
  27. return "Person [name=" + name + ", age=" + age + "]";
  28. }
  29. }
  30. class ObjectStreamDemo {
  31. public static void main(String[] args) throws IOException, ClassNotFoundException {
  32. writeObj();//对象的序列化。
  33. readObj();//对象的反序列化。
  34. }
  35. public static void writeObj() throws IOException {
  36. //1,明确存储对象的文件。
  37. FileOutputStream fos = new FileOutputStream("object.txt");
  38. //2,给操作文件对象加入写入对象功能。
  39. ObjectOutputStream oos = new ObjectOutputStream(fos);
  40. //3,调用了写入对象的方法。
  41. oos.writeObject(new Person("wangcai",20));
  42. //关闭资源。
  43. oos.close();
  44. }
  45. public static void readObj() throws IOException, ClassNotFoundException {
  46. //1,定义流对象关联存储了对象文件。
  47. FileInputStream fis = new FileInputStream("object.txt");
  48. //2,建立用于读取对象的功能对象。
  49. ObjectInputStream ois = new ObjectInputStream(fis);
  50. Person obj = (Person)ois.readObject();
  51. System.out.println(obj.toString());
  52. }
  53. }

注意:

一个对象要能被序列化,对象所属的类必须实现Serializable接口。否则会发生NotSerializableException异常。

当反序列化对象时,如果对象所属的class文件在序列化之后进行的修改,那么进行反序列化也会发生异常InvalidClassException。发生这个异常的原因如下:该类的序列版本号与从流中读取的类描述符的版本号不匹配/该类包含未知数据类型/该类没有可访问的无参数构造方法.

Serializable标记接口,给需要序列化的类,提供了一个序列版本号:serialVersionUID,该版本号的目的在于验证序列化的对象和对应类是否版本匹配。

静态修饰也不会被序列化,因为序列化是把对象数据进行持久化存储,而静态的属于类加载时的数据,不会被序列化。

当一个类的对象需要被序列化时,某些属性不需要被序列化,这时不需要序列化的属性可以使用关键字transient修饰。只要被transient修饰了,序列化时这个属性就不会琲序列化了。

5.8 标准输入输出流

System类,定义了一系列有用的属性和方法

System.in、System.out

PrintStream

System.in

结束控制台输入方案:

  • 在Windows环境下,需要输入Ctrl+Z;在Linux/Unix/MAC环境下,需要输入Ctrl+D;
  • 使用结束条件;
  1. public static void main(String[] args) throws IOException {
  2. //创建输入流对象
  3. InputStream is = System.in;
  4. //创建输出流对象
  5. FileWriter fw = new FileWriter("file.txt");
  6. //读取数据
  7. byte[] bys = new byte[1024];
  8. int len;
  9. while((len = is.read(bys))!=-1)
  10. {
  11. fw.write(new String(bys, 0, len));
  12. fw.flush();
  13. }
  14. fw.close();
  15. is.close();
  16. }

System.out

  1. public static void main(String[] args) throws IOException {
  2. //创建输入输出流对象
  3. BufferedReader br=new BufferedReader(new FileReader("file.txt"));
  4. OutputStream os=System.out;
  5. String line;//用于存储读取到的数据
  6. while((line=br.readLine())!=null) {
  7. os.write(line.getBytes());
  8. os.write("\r\n".getBytes());
  9. }
  10. //释放资源
  11. os.close();
  12. br.close();
  13. }

由于标准输出流是一个字节输出流,所以只能输出字节或者字节数组,但是我们读到的数据则是字符串,如果想进行输出,还需要转换成字节数组,非常麻烦。我们要想通过标准输出流输出字符串,把标准输出流转换成一种字符输出流即可。可以使用转换流OutputStreamWriter。

  1. public static void main(String[] args) throws IOException {
  2. //创建输入输出流对象
  3. BufferedReader br=new BufferedReader(new FileReader("file.txt"));
  4. Writer w=new OutputStreamWriter(System.out);//多态,父类引用指向子类对象
  5. //进行数据读写
  6. String line;
  7. while((line=br.readLine())!=null) {
  8. w.write(line);
  9. w.write("\r\n");
  10. }
  11. //释放资源
  12. w.close();
  13. br.close();
  14. }

还可以结合高效缓冲流使用:

  1. public static void main(String[] args) throws IOException {
  2. //创建输入输出流对象
  3. BufferedReader br=new BufferedReader(new FileReader("file.txt"));
  4. BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(System.out));
  5. //进行数据读写
  6. String line;
  7. while((line=br.readLine())!=null) {
  8. bw.write(line);
  9. bw.newLine();
  10. }
  11. //释放资源
  12. bw.close();
  13. br.close();
  14. }

5.9 打印流

打印流是输出信息最方便的类,注意包含字节打印流:PrintStream和字符打印流:PrintWriter

通过定义的构造方法可以发现,有一个构造方法可以直接接收OutputStream类的实例,与OutputStream相比起来,PrintStream可以更方便的输出数据,相当于把OutputStream类重新包装了一下,使之输出更方便。

JAVA对PrintStream功能进行了扩充,增加了格式化输出功能。直接使用Print即可。但是输出的时候需要指定输出的数据类型

  1. 提供了一系列重载的print()和println()方法,用于多种数据类型的输出。
  2. PrintStream和PrintWriter的输出不会抛出IOException异常。
  3. PrintStream和PrintWriter有自动flush功能。
  4. PrintStream 打印的所有字符都使用平台的默认字符编码转换为字节。 在需要写入字符而不是写入字节的情况下,应该使用 PrintWriter 类。
  5. System.out返回的是PrintStream的实例。

PrintStream

  1. public static void main(String[] args) throws IOException {
  2. //创建流,绑定输出的目的地
  3. PrintStream ps=new PrintStream("a.txt");
  4. //使用write方法写数据,保持内容不变
  5. ps.write(97);
  6. ps.println();
  7. //使用print方法,会根据平台编码,进行转码工作
  8. ps.println(97);//97->a
  9. ps.println("HelloWorld");//HelloWorld
  10. //释放资源
  11. ps.close();
  12. }

PrintWriter

  1. public static void main(String[] args) throws IOException {
  2. //创建流
  3. //PrintWriter out = new PrintWriter(new FileWriter("printFile.txt"));
  4. PrintWriter out = new PrintWriter("a.txt");
  5. //2,写数据
  6. for (int i=0; i<5; i++) {
  7. out.println("helloWorld");
  8. }
  9. //3,关闭流
  10. out.close();
  11. }

5.10 Properties类

Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。

特点:

  1. Hashtable的子类,map集合中的方法都可以用。

  2. 该集合没有泛型。键值都是字符串。

  3. 它是一个可以持久化的属性集。

  4. 唯一一个能与IO流交互的集合

  5. 有和流技术相结合的方法。
    load(InputStream) 把指定流所对应的文件中的数据,读取出来,保存到Propertie集合中
    load(Reader)
    store(OutputStream,commonts)把集合中的数据,保存到指定的流所对应的文件中,参数commonts代表对描述信息
    store(Writer,comments);

  6. 常用方法

  • public Object setProperty(String key, String value)调用 Hashtable 的方法 put。
  • public Set stringPropertyNames()返回此属性列表中的键集,
  • public String getProperty(String key)用指定的键在此属性列表中搜索属性
  1. //Properties的使用
  2. public class PropertiesDemo01 {
  3. public static void main(String[] args) {
  4. //创建集合对象
  5. Properties prop = new Properties();
  6. //添加元素到集合
  7. //prop.put(key, value);
  8. prop.setProperty("小丽", "大学生");
  9. prop.setProperty("小美", "研究生");
  10. prop.setProperty("小芳", "博士生");
  11. //遍历集合
  12. Set<String> keys = prop.stringPropertyNames();
  13. for (String key : keys) {
  14. //通过键 找值
  15. String value = prop.getProperty(key);
  16. System.out.println(key+"==" +value);
  17. }
  18. }
  19. }

使用Properties集合,完成把集合内容存储到IO流所对应文件中的操作

  1. public class PropertiesDemo02 {
  2. public static void main(String[] args) throws IOException {
  3. //1,创建Properties集合
  4. Properties prop = new Properties();
  5. //2,添加元素到集合
  6. prop.setProperty("小丽", "大学生");
  7. prop.setProperty("小美", "研究生");
  8. prop.setProperty("小芳", "博士生");
  9. //3,创建流
  10. FileWriter out = new FileWriter("prop.properties");
  11. //4,把集合中的数据存储到流所对应的文件中
  12. prop.store(out, "save data");
  13. //5,关闭流
  14. out.close();
  15. }
  16. }

需求:从属性集文件prop.properties 中取出数据,保存到集合中

  1. public class PropertiesDemo03 {
  2. public static void main(String[] args) throws IOException {
  3. //1,创建集合
  4. Properties prop = new Properties();
  5. //2,创建流对象
  6. FileReader in = new FileReader("prop.properties");
  7. //3,把流所对应文件中的数据 读取到集合中
  8. prop.load(in);
  9. //4,关闭流
  10. in.close();
  11. //5,显示集合中的数据
  12. System.out.println(prop);
  13. }
  14. }

5.11 NIO和NIO.2

NIO(New IO):

从 JDK 1.4 开始引入的一个用来替代传统IO的API。NIO与传统的IO具有相同的作用,但是使用的方式是不一样的。NIO是面向缓冲区(Buffe)的、基于通道(Channel)。

从 JDK 1.7 开始加入了一些新的元素。被称作 NIO.2

NIO 和 IO 有什么区别:

  • IO是面向流(Stream)的,NIO是面向缓冲区(Buffer)的。
  • IO是阻塞型的,NIO是非阻塞型的。

缓冲区Buffer:是一个用来存储基本数据类型的容器。

按照其存储的数据类型不同,缓冲区有着不同的分类:(没有boolean)

ByteBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer、CharBuffer

以上,这些缓冲区有着相同的方法来进行获取和数据的管理。因为所有以上的缓冲区都是继承自Buffer类的。

常用属性和方法:

1,获取缓冲区:不是通过new的方式,而是通过静态方法 allocate(int capacity) 来获取缓冲区。

2,属性:

  • capacity: 容量。表示缓冲区最多可以存储多少数据。一旦设置后,将不能改变。
  • limit: 界限。表示缓冲区可以操作的数据数量。(实际上存储了多少数据)。
  • position: 位置。缓冲区中正在进行操作的数据的位置。
  • mark: 使用mark()方法标记的位置。
  • mark <= position <= limit <= capacity

3,常用方法:

put():将数据放入缓冲区

get():从缓冲区中获取数据

flip():切换成读模式

rewind():重新读取(position重置为0)

clear():清空缓冲区。将缓冲区中limit和position重置为allocate之后的状态。

clear方法只是重置了一下标记,缓冲区中的数据还在。

mark():在指定的position做一个标记

  1. public class FileDemo{
  2. public static void main(String[] args) throws IOException {
  3. // 设置输入源 & 输出目的 = 文件
  4. String infile = "a.txt";
  5. String outfile = "b.txt";
  6. // 1. 获取数据源 和 目标传输地的输入输出流(此处以数据源 = 文件为例)
  7. FileInputStream fin = new FileInputStream(infile);
  8. FileOutputStream fout = new FileOutputStream(outfile);
  9. // 2. 获取数据源的输入输出通道
  10. FileChannel fcin = fin.getChannel();
  11. FileChannel fcout = fout.getChannel();
  12. // 3. 创建缓冲区对象
  13. ByteBuffer buff = ByteBuffer.allocate(1024);
  14. while (true) {
  15. // 4. 从通道读取数据 & 写入到缓冲区
  16. // 注:若 以读取到该通道数据的末尾,则返回-1
  17. int r = fcin.read(buff);
  18. if (r == -1) {
  19. break;
  20. }
  21. // 5. 传出数据准备:调用flip()方法
  22. buff.flip();
  23. // 6. 从 Buffer 中读取数据 & 传出数据到通道
  24. fcout.write(buff);
  25. // 7. 重置缓冲区
  26. buff.clear();
  27. }
  28. }
  29. }