io流不关闭会内存溢出吗_IO流——学习笔记

Myth丶恋晨 2023-01-01 10:49 676阅读 0赞

#

一、简介

  • IO:

    • 输入(读文件):表示将文件数据从文件当中输到内存当中
    • 输出(写文件):表示将数据从内存当中写到文件当中去
    • 流(stream):
    • 就是一串不段连续的数据集,其实就是管道
  • 作用:

    • 数据的载体
    • 将数据从一端传输到另一端的功能实现

二、IO流的分类

1、按方向分类

  • 输入流

    • 输入流他是针对读数据而言

4bdde85c12506692788577a3b045038e.png

输出流

  • 输出流他是针对写数据而言

4ea4439857e3f370e2eb82e637d5842d.png

2、按数据单位

  • 字符流

    • 2个字节为一个数据单元来传输
  • 字节流

    • 一个字节为一个数据单元来传输

3、按角色分类

  • 节点流

    • FileOutputStream
    • FileInputStream
    • 他是直接对接物理节点的流对象,称为节点流
    • 例如
  • 处理流

    • 他是在节点流的基础上,进一步装饰及包装,形成一个处理流

三、输出/输入流体系

595931f05c65fd8d991991fe6be39b30.png

四、分析FileInputStream类

1、所属的类

  • 输入流

    • 将数据从文件当中读取到内存中,可以在控制台输出
  • 字节流

    • 注意:读取文本文档时可能会出现乱码(一个汉字为2个字节)
    • 以字节单元读数据(byte)
  • 节点流

    • 直接对接文件

2、具体用法

  1. 创建File类的对象,指明所读文件(读文件一定要事先建好文件,写文件可以不用)
  2. 创建相应流的对象,把File类对象放进去
  3. 进行相应流的操做(读和写)
  4. 资源关闭

    package FileInputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;public class MainTest2 {

    1. public static void main(String[] args) {
    2. // TODO Auto-generated method stub FileInputStream fileInputStream=null; try {
    3. //1.创建File类对象,指明读取的文件 File file = new File("C:\\Users\\WQW\\Desktop\\wqw\\test.txt"); //2.创建相应 的流对象 fileInputStream = new FileInputStream(file); //3.进行流的相应操作,这里进行读的操作 //这是一种最先的方式// int c1 = fileInputStream.read();// //输出的是Scall码// System.out.println(c1);// int c2 = fileInputStream.read();// System.out.println(c2);// int c3 = fileInputStream.read();// //可以强转为字符// System.out.println((char)c3); //改进后的方式// //新建一个字节数组// byte[] buf = new byte[32];// //read(buf),此方法也就是当前读取的字节个数,将数据读取到buf数组// int len = fileInputStream.read(buf); //再次改进的方式// int buf;// while ((buf=fileInputStream.read())!=-1) {
    4. // System.out.print((char) buf);// } //或者 byte[] buf = new byte[5]; int len; while ((len=fileInputStream.read(buf))!=-1) {
    5. // for (int i = 0; i < len; i++) {
    6. // System.out.println(buf[i]);// } //或者直接转化成String类型 String string = new String(buf,0,len); System.out.print(string); } } catch (Exception e) {
    7. // TODO: handle exception e.printStackTrace(); }finally {
    8. //4资源的关闭 try {
    9. if(fileInputStream!=null) fileInputStream.close(); } catch (IOException e) {
    10. // TODO Auto-generated catch block e.printStackTrace(); } }}}

五、分析FileOutputStream类

1、此IO流所属分类

  • 输出流

    • 将内存中数据写到文件中去
  • 字节流

    • 他是以字节为位置写数据
  • 节点流

    • 直接面向文件操作

2、FileOutputStream用法

093d8b2321f33910f7bd5364fb018652.png

  1. package FileOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;public class MainTest2 {
  2. public static void main(String[] args) {
  3. FileOutputStream fileOutputStream =null; try {
  4. //创建File类的对象,指明文件 File file = new File("C:\\Users\\WQW\\Desktop\\wqw\\test2.txt"); //2.创建相应流的对象 fileOutputStream = new FileOutputStream(file,true); //3.进行流的相关操作 //方式一 //fileOutputStream.write(97); //方式二 String content = "welcome come to china"; //将字符串转换成字节数组 byte[] buf = content.getBytes(); fileOutputStream.write(buf); fileOutputStream.flush();//刷新 //方式三 fileOutputStream.write("helloworld123".getBytes());//转化成字节的形式 fileOutputStream.flush(); } catch (Exception e) {
  5. // TODO: handle exception e.printStackTrace(); }finally {
  6. //4.资源的关闭 try {
  7. if(fileOutputStream!=null) fileOutputStream.close(); } catch (IOException e) {
  8. // TODO Auto-generated catch block e.printStackTrace(); } }}}

六FileReader用法

1、所属的IO流分类

  • 输入流

    • 从文件读取数据到内存
  • 字符流

    • 以字符为传输数据单元
  • 节点流

    • 直接面向文件操作

2、注意事项

  • 注意乱码问题

    • 控制台编码格式必须跟文件编码一致

3、具体用法

  1. package FileReader;import java.io.File;import java.io.FileReader;import java.io.IOException;public class MainTest {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub// FileReader fileReader = null;// try {
  4. // //1.实例化File类的对象,指明要操作的文件// File file = new File("test.txt");//// //2.提供具体的流// fileReader = new FileReader(file);// // //3.数据的读入// int date = -1;// while ((date = fileReader.read()) != -1) {
  5. // System.out.print((char) date);// } // } catch (Exception e) {
  6. // e.printStackTrace();// }finally {
  7. // //4.关闭流// try {
  8. // if (fileReader !=null) {
  9. // fileReader.close();// }// // } catch (IOException e) {
  10. // e.printStackTrace();// }// } FileReader fileReader = null; try {
  11. //1.File类的实例化 File file = new File("test.txt"); //2.流的实例化 fileReader = new FileReader(file); //3.读入的操作 char[] cbuf = new char[5]; int len; while ((len = fileReader.read(cbuf)) != -1) {
  12. // for (int i = 0; i < len; i++) {
  13. // System.out.print(cbuf[i]);// } //或者 String str = new String(cbuf, 0, len); System.out.print(cbuf); } } catch (Exception e) {
  14. e.printStackTrace(); }finally {
  15. //4.资源 的关闭 try {
  16. if(fileReader!=null) fileReader.close(); } catch (IOException e) {
  17. // TODO Auto-generated catch block e.printStackTrace(); } }}}

七、FileWriter的用法

1、所属的IO流分类

  • 输出流

    • 将内存的数据写到文件
  • 字符流

    • 以字符为数据单元来传输数据
  • 节点流

    • 直接面向文件操作

2、注意事项

  • 输出操作,如果对应的file不存在,则会创建
  • 如果存在,fileWriter = new FileWriter(file,true);
  • 这里写入true的的话,则会在原先内容的上再次添加
  • 如果不写或者为false则会进行文件的覆盖

3、具体用法

  1. package FileWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;public class MainTest {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub FileWriter fileWriter=null; try {
  4. //提供File的类,指明写入文件 File file = new File("test2.txt"); //2.提供需要的流 fileWriter = new FileWriter(file,true); //3.写出的操作 fileWriter.write("I love Java".toCharArray()); } catch (Exception e) {
  5. // TODO: handle exception e.printStackTrace(); }finally {
  6. //4.资源 的关闭 try {
  7. fileWriter.close(); } catch (IOException e) {
  8. // TODO Auto-generated catch block e.printStackTrace(); } }}}

4、读取和写入的综合操作

  1. package FileWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class Test {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub FileReader fileReader=null; FileWriter fileWriter=null; try {
  4. //创建file类的对象 File file = new File("test.txt"); File file2 = new File("test2.txt"); //创建流的对象 fileReader= new FileReader(file); fileWriter = new FileWriter(file2); //数据的读入和写出操作 char[] cbuf = new char[5]; int len;//每次读入到cbuf数组中的字符 while ((len =fileReader.read(cbuf))!=-1 ) {
  5. //每次写出len个字符 fileWriter.write(cbuf, 0, len); } } catch (Exception e) {
  6. // TODO: handle exception e.printStackTrace(); }finally {
  7. //资源的关闭 try {
  8. if(fileReader!=null) fileReader.close(); } catch (IOException e) {
  9. // TODO Auto-generated catch block e.printStackTrace(); } try {
  10. if(fileWriter!=null) fileWriter.close(); } catch (IOException e) {
  11. // TODO Auto-generated catch block e.printStackTrace(); } }}}

八、转换流

1、概述

  • 将字节流——》字符流
  • 将一个字节 的输入流转换成字符的输入流

2、InputStreamReader类作用

  • 输入流

    • 能够将字节输入流的内容以字符的形式读取内存
  • 字符流
  • 处理流

    package InputStreamReader用法;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;public class MainTest {

    1. public static void main(String[] args) throws IOException {
    2. File file=new File("file2.txt"); //以文件输入字节流读取文件 FileInputStream fileInputStream=new FileInputStream(file); //通过转换流将输入字节流----》输入字符流 InputStreamReader reader=new InputStreamReader(fileInputStream); char []cbuf=new char[32]; int len=reader.read(cbuf); //创建一个字符串对象 String content=new String(cbuf,0,len); System.out.println(content);}}

3、OutputStreamWriter的用法

  • 所属的IO流的分类

    • 输出流
    • 字符流
    • 处理流
  • 作用

    • 将一个字符的输出流转换为字节的输出流

    package OutputStreamWriter用法;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;public class MainTest {

    1. public static void main(String[] args) throws IOException {
    2. File file = new File("file3.txt"); FileOutputStream fileOutputStream = new FileOutputStream(file); //将输出字节流---->输出字符流 //将数据以字符方式写到文件里面 OutputStreamWriter writer=new OutputStreamWriter(fileOutputStream); writer.write("欢迎来到粤嵌,学习java"); writer.flush(); writer.close(); fileOutputStream.close();}}

九、缓冲流

1、简介

  • 最大的特点就是它有一个缓存区

    • 默认分配一个8k大小的缓存区,来存储数据
  • 作用

    • 针对大量的读取及写入数据,提高操作效率
  • 处理流之一
  • 不能直接对接文件

2、BufferedReader类的用法

  • 将从缓存区读取到内存(默认分配8k)
  • 缓存区

    • 批量读取数据
    • 按行读取
    • 反复读

    package BufferedReader用法;import java.io.BufferedReader;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;public class MainTest {

    1. public static void main(String[] args) throws IOException {
    2. FileReader reader=new FileReader(new File("file4.txt")); BufferedReader br=new BufferedReader(reader); System.out.println((char)br.read());//a System.out.println((char)br.read());//b //设置一个mark:标记一个位置 System.out.println("mark 操作"); br.mark(2); System.out.println((char)br.read());//c System.out.println((char)br.read());//d System.out.println("reset 操作"); br.reset(); System.out.println((char)br.read());//c System.out.println((char)br.read());//d //按行读取/* String line1=br.readLine(); String line2=br.readLine(); String line3=br.readLine(); String line4=br.readLine(); System.out.println(line1); System.out.println(line2); System.out.println(line3); System.out.println(line4);*/ //流}}

3、BufferedWriter用法

  1. package BufferedWriter用法;import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;public class MainTest {
  2. public static void main(String[] args) throws IOException {
  3. //构造器一个File对象 File file=new File("file4.txt"); //构造器Writer对象 FileWriter fileWriter=new FileWriter(file); //使用缓存流针对文件进行读、写 BufferedWriter writer=new BufferedWriter(fileWriter); writer.write("欢迎来到粤嵌!!!"); //刷新一下 writer.flush(); //资源关闭 //要求:先关闭外层的流,在关闭内层的流 writer.close(); //说明:内层的流会自动关闭 // fileWriter.close();}}

4、封装一个用Buffered实现文本复制的方法

  1. package BufferedTest;import java.io.BufferedInputStream;import java.io.BufferedOutputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;public class MainTest {
  2. //这是我们常用的方法//public static void main(String[] args) {
  3. // // TODO Auto-generated method stub// //实现非文本文件的复制// FileInputStream fileInputStream=null;// FileOutputStream fileOutputStream=null;// BufferedInputStream bufferedInputStream=null;// BufferedOutputStream bufferedOutputStream=null;// try {
  4. // //1、造文件// File file = new File("C:\\Users\\WQW\\Desktop\\bj.jpg");// File file2 = new File("C:\\Users\\WQW\\Desktop\\bj2.jpg");// //2.造流// //2.1造节点流// fileInputStream = new FileInputStream(file);// fileOutputStream = new FileOutputStream(file2); // //2.2造缓冲流// bufferedInputStream = new BufferedInputStream(fileInputStream);// bufferedOutputStream = new BufferedOutputStream(fileOutputStream);// //3.复制的细节:读取,写入// byte[] buf = new byte[10];// int len;// while((len=bufferedInputStream.read(buf))!=-1) {
  5. // bufferedOutputStream.write(buf, 0, len);// bufferedOutputStream.flush();// }// } catch (IOException e2) {
  6. // e2.printStackTrace();// }// //资源的关闭// //要求:先关外层,在关内层// try {
  7. // if(bufferedInputStream!=null)// bufferedInputStream.close();// } catch (IOException e1) {
  8. // // TODO Auto-generated catch block// e1.printStackTrace();// }// try {
  9. // if(bufferedOutputStream!=null)// bufferedOutputStream.close();// } catch (IOException e) {
  10. // // TODO Auto-generated catch block// e.printStackTrace();// }// //说明:关闭外层流的时候会自动关闭内层的流 fileInputStream.close(); fileOutputStream.close();//} //在这里我们把上面的方法进行封装 //封装一个实现文件复制的方法 public void copyFileWriterBuffered(String srcPath,String destPath) {
  11. //实现非文本文件的复制 FileInputStream fileInputStream=null; FileOutputStream fileOutputStream=null; BufferedInputStream bufferedInputStream=null; BufferedOutputStream bufferedOutputStream=null; try {
  12. //1、造文件 File file = new File(srcPath); File file2 = new File(destPath); //2.造流 //2.1造节点流 fileInputStream = new FileInputStream(file); fileOutputStream = new FileOutputStream(file2); //2.2造缓冲流 bufferedInputStream = new BufferedInputStream(fileInputStream); bufferedOutputStream = new BufferedOutputStream(fileOutputStream); //3.复制的细节:读取,写入 byte[] buf = new byte[10]; int len; while((len=bufferedInputStream.read(buf))!=-1) {
  13. bufferedOutputStream.write(buf, 0, len); bufferedOutputStream.flush(); } } catch (IOException e2) {
  14. e2.printStackTrace(); } //资源的关闭 //要求:先关外层,在关内层 try {
  15. if(bufferedInputStream!=null) bufferedInputStream.close(); } catch (IOException e1) {
  16. // TODO Auto-generated catch block e1.printStackTrace(); } try {
  17. if(bufferedOutputStream!=null) bufferedOutputStream.close(); } catch (IOException e) {
  18. // TODO Auto-generated catch block e.printStackTrace(); } //说明:关闭外层流的时候会自动关闭内层的流// fileInputStream.close();// fileOutputStream.close();}}

5、调用上面封装的方法,并测试复制文件所需要的时间

  1. package BufferedTest;public class TestCopyFileWriteBuffered {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub //起始的时间 long start = System.currentTimeMillis(); String srcPath = "C:\\Users\\WQW\\Desktop\\bj.jpg"; String destPath ="C:\\Users\\WQW\\Desktop\\bj3.jpg"; //调用方法 MainTest m = new MainTest(); m.copyFileWriterBuffered(srcPath,destPath); //结束的时间 long end = System.currentTimeMillis(); System.out.println("复制操作花费的时间为:"+(end-start));}}

6.进行图片的加密

  1. package 课堂练习;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;/** * 进行图片的加密 * */public class PicTest {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub //FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\WQW\\Desktop\\bj.jpg")); //或者 try {
  4. FileInputStream fileInputStream = new FileInputStream("C:\\Users\\WQW\\Desktop\\bj.jpg"); FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\WQW\\Desktop\\bj2.jpg"); byte[] buffer = new byte[20]; int len; while ((len=fileInputStream.read(buffer))!=-1) {
  5. //加密:对字节数组进行修改// //错误的,buffer数据没有改变,只是b改变了// for (byte b : buffer) {
  6. // b=(byte)(b^5);// } //正确的 for (int i = 0; i < len; i++) {
  7. buffer[i] = (byte) (buffer[i] ^ 5); } fileOutputStream.write(buffer, 0, len); } fileInputStream.close(); fileOutputStream.close(); } catch (FileNotFoundException e) {
  8. // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
  9. // TODO Auto-generated catch block e.printStackTrace(); }}}

7、进行图片 的解密

  1. package 课堂练习;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;/** * 进行图片的解密 * 主要是^位运算符的使用 * */public class PicTest2 {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub //FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\WQW\\Desktop\\bj.jpg")); //或者 try {
  4. FileInputStream fileInputStream = new FileInputStream("C:\\Users\\WQW\\Desktop\\bj2.jpg"); FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\WQW\\Desktop\\bj3.jpg"); byte[] buffer = new byte[20]; int len; while ((len=fileInputStream.read(buffer))!=-1) {
  5. //解密:对字节数组进行修改// //错误的,buffer数据没有改变,只是b改变了// for (byte b : buffer) {
  6. // b=(byte)(b^5);// } //正确的 for (int i = 0; i < len; i++) {
  7. buffer[i] = (byte) (buffer[i] ^ 5); } fileOutputStream.write(buffer, 0, len); } //资源的关闭 fileInputStream.close(); fileOutputStream.close(); } catch (FileNotFoundException e) {
  8. // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
  9. // TODO Auto-generated catch block e.printStackTrace(); }}}

8、其它

  • 使用ByteArrayOutputStream来解决读取字节出现乱码问题

    //如果文件内容太大,会出现乱码,可以用ByteArrayOutputStream来实现// byte[] buffer = new byte[20];// int len;// while((len= inputStream.read(buffer))!=-1) {

    1. // String str = new String(buffer, 0, len);// System.out.println(str);// } //使用ByteArrayOutputStream,把文件内容写入到一个数组中去// baos = new ByteArrayOutputStream();// byte[] buffer = new byte[5];// int len;// while((len=inputStream.read(buffer))!=-1) {
    2. // baos.write(buffer, 0, len);// }// //转换成字符串// System.out.println(baos.toString());

十一、字符集

1、常用的字符集

  • ASCII:美国信息交换码,用一个字节的7位可以表示
  • ISO-8859-1:用一个字节的8位可以表示
  • GB2312:中国的中文编码表,最多两个字节编码中文
  • GBK:融合了更多 的中文字文字字符
  • Unicode:国际标准码,融合了目前人类使用的所有字符,所有的文字都要用两个字节来表示
  • UTF-8:变长的编码方式,可用1-4个字节来表示一个字符

2、解决字符乱码问题

  1. package 课堂练习;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.util.Arrays;public class Test4 {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub FileInputStream fileInputStream = null; try {
  4. //创建File类对象 File file = new File("C:\\Users\\WQW\\Desktop\\wqw\\hello.txt"); //创建流的对象 fileInputStream = new FileInputStream(file); //3.进行流的读取 //新建一个字节数组、 byte[] buf = new byte[2]; int len; while ((len=fileInputStream.read(buf))!=-1) {
  5. int pos=0; for(byte v:buf) {
  6. //记录负数的个数 if(v<0) {
  7. pos++; } } if(pos%2==0) {
  8. //将字节数组转化成字符串 String str= new String(buf,0,len); System.out.print(str); }else {
  9. //再读取下一位 int nextByteValue = fileInputStream.read(); int nextLen = len+1; //将字节数组扩容一位 buf = Arrays.copyOf(buf, nextLen); buf[len]=(byte)nextByteValue; //打印输出 String str = new String(buf,0,nextLen); System.out.print(str); } } } catch (Exception e) {
  10. // TODO: handle exception e.printStackTrace(); }finally {
  11. //关闭资源 try {
  12. if(fileInputStream!=null) fileInputStream.close(); } catch (IOException e) {
  13. // TODO Auto-generated catch block e.printStackTrace(); } }}}

十一、求一篇文档中的每个字符出现的次数

  1. package 课堂练习;import java.io.BufferedWriter;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.Set;/** * 获取文本上每个字符出现的字数 * 提示:遍历文本的所有一个字符,保存在Map中 * */public class Test5 {
  2. public static void main(String[] args) {
  3. // TODO Auto-generated method stub FileReader fileReader = null; BufferedWriter bufferedWriter = null; try {
  4. //1.创建Map集合 Map<Character,Integer> map = new HashMap<>(); //遍历每一个字符,每一个字符出现的次数放到map中 fileReader = new FileReader("C:\\Users\\WQW\\Desktop\\Test.txt"); int c = 0; while ((c=fileReader.read())!=-1) {
  5. //int 还原char char ch =(char)c; //判断char是否在map中第一次出现 if (map.get(ch)==null) {
  6. map.put(ch, 1); }else {
  7. map.put(ch, map.get(ch)+1); } } //3.把map中的数据存放在count.txt //3.1创建writer bufferedWriter = new BufferedWriter(new FileWriter("C:\\Users\\WQW\\Desktop\\Test2.txt")); //3.2遍历map,在写入数据 Set<Map.Entry<Character,Integer>> entrySet = map.entrySet(); for (Map.Entry<Character, Integer> entry : entrySet) {
  8. switch(entry.getKey()) {
  9. case ' ': bufferedWriter.write("空格="+entry.getValue()); break; case '\t': bufferedWriter.write("tab键="+entry.getValue()); break; case '\r': bufferedWriter.write("回车="+entry.getValue()); break; case '\n': bufferedWriter.write("换行="+entry.getValue()); break; default: bufferedWriter.write(entry.getKey()+"="+entry.getValue()); break; } bufferedWriter.newLine(); } }catch (Exception e) {
  10. e.printStackTrace(); }finally {
  11. try {
  12. if(bufferedWriter!=null) bufferedWriter.close(); } catch (IOException e) {
  13. // TODO Auto-generated catch block e.printStackTrace(); } }}}

十二、BufferedReader源码分析

1、分析构造器

  1. public MyBufferedReader(Reader in, int sz) {
  2. super(in); if (sz <= 0) throw new IllegalArgumentException("Buffer size <= 0"); this.in = in; //自定义缓存大小 //分配8个字符的缓存大小 cb = new char[sz]; //nextChar:记录下一次读取字符的位置 //nChars:记录当前缓存区可读的字符个数 nextChar = nChars = 0; }

2、分析read方法

  1. public int read(char cbuf[], int off, int len) throws IOException {
  2. //编写同步锁代码块 synchronized (lock) {
  3. //确认输入流不为空 ensureOpen(); if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) {
  4. throw new IndexOutOfBoundsException(); } else if (len == 0) {
  5. return 0; } //从缓存区的数据复制到cbuf数组里面 int n = read1(cbuf, off, len); if (n <= 0) return n; //将之前处理不完的数据复制到cbuf数组,再次调用read1方法 while ((n < len) && in.ready()) {
  6. int n1 = read1(cbuf, off + n, len - n); if (n1 <= 0) break; n += n1; } return n; } }

read1方法

  1. private int read1(char[] cbuf, int off, int len) throws IOException {
  2. //nextChar:记录下一次读取字符的位置 //nChars:记录缓存区可读的字符个数 //如果nextChar>nChars,则重新刷新缓存区 if (nextChar >= nChars) {
  3. /* If the requested length is at least as large as the buffer, and if there is no mark/reset activity, and if line feeds are not being skipped, do not bother to copy the characters into the local buffer. In this way buffered streams will cascade harmlessly. */ if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
  4. return in.read(cbuf, off, len); } //针对缓存区的数据,重新刷新,将新的数据重新更新到缓存区 fill(); } if (nextChar >= nChars) return -1; if (skipLF) {
  5. skipLF = false; if (cb[nextChar] == '\n') {
  6. nextChar++; if (nextChar >= nChars) fill(); if (nextChar >= nChars) return -1; } } int n = Math.min(len, nChars - nextChar); //将缓冲区的数据复制到cbuf System.arraycopy(cb, nextChar, cbuf, off, n); //并且更新nextChar的位置值 nextChar += n; return n; }

fill方法(刷新)

  1. private void fill() throws IOException {
  2. int dst; //是否有调有mark方法,如果没有设置mark值,则markedChar <= UNMARKED为true if (markedChar <= UNMARKED) {
  3. /* No mark */ dst = 0; } else {
  4. /* Marked */ int delta = nextChar - markedChar; if (delta >= readAheadLimit) {
  5. /* Gone past read-ahead limit: Invalidate mark */ markedChar = INVALIDATED; readAheadLimit = 0; dst = 0; } else {
  6. if (readAheadLimit <= cb.length) {
  7. /* Shuffle in the current buffer */ System.arraycopy(cb, markedChar, cb, 0, delta); markedChar = 0; dst = delta; } else {
  8. /* Reallocate buffer to accommodate read-ahead limit */ char ncb[] = new char[readAheadLimit]; System.arraycopy(cb, markedChar, ncb, 0, delta); cb = ncb; markedChar = 0; dst = delta; } nextChar = nChars = delta; } } int n; do {
  9. //将输入流的数据读取到缓存区里面,n变量决定读取多个字符 n = in.read(cb, dst, cb.length - dst); } while (n == 0); //如果n>0,代表已经读到数据 if (n > 0) {
  10. //nChars:缓存区可读的数据 nChars = dst + n; //下一次可读数据的位置 nextChar = dst; } }

十三、打印流(PrintStream\PrintWriter)

1、重定向概念

  • 有两种重定向输出

    • 默认的标准输出设备:控制台(以红色字体输出)
    • 默认的标准输出设备:控制台
    • 标准输出
    • 标准错误输出
  • 标准输入

    • 默认的设备;键盘
  • 上述重定向输入、输出都可以使用System类来描述

    • 描述标准输出错误(默认控制台,红色字体输出)
    • 描述标准输出(默认控制台)
    • 描述标准输入(默认:键盘)
    • System.in
    • System.out
    • System.err
  • 举例

    public class MainTest{

    1. public static void main(String[] args){
    2. //思路:使用System.in实现。System.in---->转换流----》BufferedReaderd的readline()方法 //将字节转换成字符 InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); while(true){
    3. System.out.println("请输入字符"); String data = br.readLine(); if("e".equalsIgnoreCase(data)){
    4. System.ouot.priintln("程序结束"); break; } String upperCase = data.toUpperCase(); System.outprintln(upperCase); } }}

2、PrintStream类

  • 分类

    • 但同时它也支持字符串输出,如果调用printxxx(String str)方法,他底层就是调用BufferWriter实现输出
    • 也支持字节输出操作
    • writer(int b);
    • writer(byte[] buf);
    • 写数据
    • 输出流
    • 字节流

    package PrintStream实例;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.PrintStream;public class MainTest {

    1. public static void main(String[] args) throws IOException {
    2. /* System.out.println("hello world"); System.err.println("java hello");*/ //调用PrintStream的打印流将helloworld输出到控制器 //重定向输出 /* * 标准输出:System.out配置 * 标准错误输出:System.err配置 * */ /* * 修改重定向设备: * 标准输出到a.txt * 标准错误输出:b.txt * */ PrintStream consolePs=System.out; //创建一个PrintStream打印类,针对文件输出流进行打印写入操作 FileOutputStream aFileOutptStream=new FileOutputStream(new File("a.txt")); PrintStream ps=new PrintStream(aFileOutptStream);/* ps.println("helloworld 1"); ps.println("helloworld 2"); ps.println("helloworld 3");*/ ps.write(97); //创建一个PrintStream打印类,针对标准错误输出信息打印到b.txt /*FileOutputStream bFileOutptStream=new FileOutputStream(new File("b.txt")); PrintStream errorPs=new PrintStream(bFileOutptStream); //更改标准输出设备:从控制台---->a.txt文件 System.setOut(ps); //更改标准错误输出设备:从控制台----->b.txt System.setErr(errorPs); System.out.println("helloworld"); System.out.println("helloworld2"); System.out.println("helloworld3"); //还原默认的标准输出 System.setOut(consolePs); System.out.println("helloworld4"); System.out.println("helloworld5"); System.out.println("helloworld6"); //输出标准错误信息 System.err.println("error helloworld 1"); System.err.println("error helloworld 2"); System.err.println("error helloworld 3"); System.err.println("error helloworld 4");*/ /* ps.println("helloworld"); ps.println("aaaaaa"); ps.println("bbbbb"); ps.flush(); ps.close(); aFileOutptStream.close(); */}}

3、PrintWriter类

  • 输出流
  • 输出数据、打印数据
  • 字符流

    • 不支持字节操作
    • 仅支持字符操作

    package PrintWriter实例;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.io.PrintWriter;public class MainTest {

    1. public static void main(String[] args) throws IOException {
    2. FileWriter fileWriter=new FileWriter(new File("c.txt")); PrintWriter pw=new PrintWriter(fileWriter); pw.println("helloworld1"); pw.println("helloworld2"); pw.println("helloworld3"); pw.println("helloworld4"); //刷新一下 pw.flush();}}

十四、RandomAccessFile类作用

1、简介

  • 它并不是IO流体系中的一种
  • 但它能够读、写文件
  • 可以自由访问文件的任意位置

2、特点

  • 针对文件,支持字节、字符操作
  • 针对行数据操作
  • 自由访问文件的任意位置

    • seck方法

3、使用方式

  • 创建RandomAccessFile类实例需要指定一个mode参数,该参数指定RandomAccessFile的访问模式

    • r:以只读的方式打开
    • rw:打开以便读取和写入
    • rwd:打开以便读取和写入,同步文件内容的更新
    • rws:打开以便读取和写入,同步文件内容和元数据的更新

4、举例

  1. package RandomAccessFile实例;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;public class MainTest2 {
  2. public static void main(String[] args) throws IOException {
  3. File file=new File("g.txt"); RandomAccessFile randomAccessFile=new RandomAccessFile(file, "rw"); String content="helloworld"; randomAccessFile.writeUTF(content); randomAccessFile.writeUTF(content); randomAccessFile.writeUTF(content); randomAccessFile.writeUTF(content);}}

十五、对象流(处理流)

1、概述:

  • 用于存储和读取基本数据类型数据或对象的处理流
  • 序列化

    • 用ObjectOutputStream类保存基本数据类型或对象的机制
  • 反序列化

    • 用ObjectInputStream类读取基本类型数据或对象的机制
  • ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量

2、ObjectOutputStream(序列化)

  • 将内存中java对象序列化成字节序列,保存到磁盘中或通过网络传输出去
  • 如何实现序列化

    • 创建一个类并实现Serializable接口
    • 创建上面类的对象
    • 创建一个输出流的文件
    • 新建一个ObjectOutputStream对象
    • 调用writerObject()方法
  • 举例

    package objectOutputStream;import java.io.Serializable;//创建一个类并实现Serializable接口public class Person implements Serializable{

    1. private String name; private int age; public String getName() {
    2. return name;} public void setName(String name) {
    3. this.name = name;} public int getAge() {
    4. return age;} public void setAge(int age) {
    5. this.age = age;} public Person(String name, int age) {
    6. super(); this.name = name; this.age = age;} public Person() {
    7. super();} @Override public String toString() {
    8. return "Person [name=" + name + ", age=" + age + "]";}}

    package objectOutputStream;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectOutputStream;public class MainTest {

    1. //进行序列化处理 public static void main(String[] args) {
    2. // TODO Auto-generated method stub //创建Person对象 Person person = new Person(); person.setAge(25); person.setName("张三"); FileOutputStream fileOutputStream; ObjectOutputStream objectOutputStream=null; try {
    3. //创建一个输出流的文件 fileOutputStream = new FileOutputStream(new File("person.txt")); //ObjectOutputStream针对次此fileOutputStream进行处理 objectOutputStream= new ObjectOutputStream(fileOutputStream); //调用writerObject方法 objectOutputStream.writeObject(person); } catch (FileNotFoundException e) {
    4. // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
    5. // TODO Auto-generated catch block e.printStackTrace(); }finally {
    6. //资源关闭 try {
    7. //进行判断ObjectOutputStream对象是否创建成功 if(objectOutputStream!=null) objectOutputStream.close(); } catch (IOException e) {
    8. // TODO Auto-generated catch block e.printStackTrace(); } }}}

3、ObjectInputStream(反序列化)

  • 从磁盘针对序列化文件,还原成一个对象
  • 步骤

    • Person p=(Person) os.readObject();

    • 创建读取文件的输入流对象

    • 创建一个读取对象的输入流对象,读取某个文件
    • 反序列化成一个对象
    • 打印输出
  • 举例

    package objectInputStream;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.ObjectInputStream;import objectOutputStream.Person;public class MainTest {

    1. //进行反序列化处理 public static void main(String[] args) {
    2. // TODO Auto-generated method stub try {
    3. //创建一个输入流的文件 FileInputStream fileInputStream = new FileInputStream(new File("person.txt")); //ObjectInputStream针对次此fileInputStream进行处理 ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); //反序列化成一个对象 Person person = (Person) objectInputStream.readObject(); //打印输出 System.out.println("年龄:"+person.getAge()); System.out.println("用户名:"+person.getName()); //资源关闭 objectInputStream.close(); } catch (FileNotFoundException e) {
    4. // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
    5. // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) {
    6. // TODO Auto-generated catch block e.printStackTrace(); }}}

4、关键字

  • transient

    • 使用该关键字修饰成员变量,则此变量忽略序列化处理

5、自定义序列化处理

  • 简介

    • 可以自定义实现序列化逻辑处理
  • 具体实现

    • 在序列化对象类重写:readObject和writeObject方法
  • 举例

    package 自定义序列化;import java.io.IOException;import java.io.Serializable;public class Person2 implements Serializable{

    1. private String name; private int age; public String getName() {
    2. return name;} public void setName(String name) {
    3. this.name = name;} public int getAge() {
    4. return age;} public void setAge(int age) {
    5. this.age = age;} public Person2(String name, int age) {
    6. super(); this.name = name; this.age = age;} public Person2() {
    7. super();} @Override public String toString() {
    8. return "Person [name=" + name + ", age=" + age + "]";} /** * 通过重写此方法,还原成文件 * 要用private方法 * */ private void readObject(java.io.ObjectInputStream in) {
    9. try {
    10. setName(in.readUTF().toUpperCase()); setAge(in.readInt()); } catch (IOException e) {
    11. // TODO Auto-generated catch block e.printStackTrace(); }} /**通过重写此方法,自定义序列化逻辑(序列化,将对象序列化成字节,存储到磁盘) * * */ private void writeObject(java.io.ObjectOutputStream out) {
    12. //将用户名序列化 try {
    13. out.writeUTF(getName()); //将年龄序列化 out.writeInt(getAge()); } catch (IOException e) {
    14. // TODO Auto-generated catch block e.printStackTrace(); }}}

发表评论

表情:
评论列表 (有 0 条评论,676人围观)

还没有评论,来说两句吧...

相关阅读

    相关 学习笔记IO

    ![70][] 图1. IO流的体系(部分​​​​) 前面所说的File类,并不能访问文件内容本身,要实现 对文件内容的操作(输入/输出)就需要用到 IO流,他可以方便实现数