io流不关闭会内存溢出吗_IO流——学习笔记
#
一、简介
IO:
- 输入(读文件):表示将文件数据从文件当中输到内存当中
- 输出(写文件):表示将数据从内存当中写到文件当中去
- 流(stream):
- 就是一串不段连续的数据集,其实就是管道
作用:
- 数据的载体
- 将数据从一端传输到另一端的功能实现
二、IO流的分类
1、按方向分类
输入流
- 输入流他是针对读数据而言
输出流
- 输出流他是针对写数据而言
2、按数据单位
字符流
- 2个字节为一个数据单元来传输
字节流
- 一个字节为一个数据单元来传输
3、按角色分类
节点流
- FileOutputStream
- FileInputStream
- 他是直接对接物理节点的流对象,称为节点流
- 例如
处理流
- 他是在节点流的基础上,进一步装饰及包装,形成一个处理流
三、输出/输入流体系
四、分析FileInputStream类
1、所属的类
输入流
- 将数据从文件当中读取到内存中,可以在控制台输出
字节流
- 注意:读取文本文档时可能会出现乱码(一个汉字为2个字节)
- 以字节单元读数据(byte)
节点流
- 直接对接文件
2、具体用法
- 创建File类的对象,指明所读文件(读文件一定要事先建好文件,写文件可以不用)
- 创建相应流的对象,把File类对象放进去
- 进行相应流的操做(读和写)
资源关闭
package FileInputStream;import java.io.File;import java.io.FileInputStream;import java.io.IOException;public class MainTest2 {
public static void main(String[] args) {
// TODO Auto-generated method stub FileInputStream fileInputStream=null; try {
//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) {
// System.out.print((char) buf);// } //或者 byte[] buf = new byte[5]; int len; while ((len=fileInputStream.read(buf))!=-1) {
// for (int i = 0; i < len; i++) {
// System.out.println(buf[i]);// } //或者直接转化成String类型 String string = new String(buf,0,len); System.out.print(string); } } catch (Exception e) {
// TODO: handle exception e.printStackTrace(); }finally {
//4资源的关闭 try {
if(fileInputStream!=null) fileInputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } }}}
五、分析FileOutputStream类
1、此IO流所属分类
输出流
- 将内存中数据写到文件中去
字节流
- 他是以字节为位置写数据
节点流
- 直接面向文件操作
2、FileOutputStream用法
package FileOutputStream;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;public class MainTest2 {
public static void main(String[] args) {
FileOutputStream fileOutputStream =null; try {
//创建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) {
// TODO: handle exception e.printStackTrace(); }finally {
//4.资源的关闭 try {
if(fileOutputStream!=null) fileOutputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } }}}
六FileReader用法
1、所属的IO流分类
输入流
- 从文件读取数据到内存
字符流
- 以字符为传输数据单元
节点流
- 直接面向文件操作
2、注意事项
注意乱码问题
- 控制台编码格式必须跟文件编码一致
3、具体用法
package FileReader;import java.io.File;import java.io.FileReader;import java.io.IOException;public class MainTest {
public static void main(String[] args) {
// TODO Auto-generated method stub// FileReader fileReader = null;// try {
// //1.实例化File类的对象,指明要操作的文件// File file = new File("test.txt");//// //2.提供具体的流// fileReader = new FileReader(file);// // //3.数据的读入// int date = -1;// while ((date = fileReader.read()) != -1) {
// System.out.print((char) date);// } // } catch (Exception e) {
// e.printStackTrace();// }finally {
// //4.关闭流// try {
// if (fileReader !=null) {
// fileReader.close();// }// // } catch (IOException e) {
// e.printStackTrace();// }// } FileReader fileReader = null; try {
//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) {
// for (int i = 0; i < len; i++) {
// System.out.print(cbuf[i]);// } //或者 String str = new String(cbuf, 0, len); System.out.print(cbuf); } } catch (Exception e) {
e.printStackTrace(); }finally {
//4.资源 的关闭 try {
if(fileReader!=null) fileReader.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } }}}
七、FileWriter的用法
1、所属的IO流分类
输出流
- 将内存的数据写到文件
字符流
- 以字符为数据单元来传输数据
节点流
- 直接面向文件操作
2、注意事项
- 输出操作,如果对应的file不存在,则会创建
- 如果存在,fileWriter = new FileWriter(file,true);
- 这里写入true的的话,则会在原先内容的上再次添加
- 如果不写或者为false则会进行文件的覆盖
3、具体用法
package FileWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;public class MainTest {
public static void main(String[] args) {
// TODO Auto-generated method stub FileWriter fileWriter=null; try {
//提供File的类,指明写入文件 File file = new File("test2.txt"); //2.提供需要的流 fileWriter = new FileWriter(file,true); //3.写出的操作 fileWriter.write("I love Java".toCharArray()); } catch (Exception e) {
// TODO: handle exception e.printStackTrace(); }finally {
//4.资源 的关闭 try {
fileWriter.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } }}}
4、读取和写入的综合操作
package FileWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.IOException;public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub FileReader fileReader=null; FileWriter fileWriter=null; try {
//创建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 ) {
//每次写出len个字符 fileWriter.write(cbuf, 0, len); } } catch (Exception e) {
// TODO: handle exception e.printStackTrace(); }finally {
//资源的关闭 try {
if(fileReader!=null) fileReader.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } try {
if(fileWriter!=null) fileWriter.close(); } catch (IOException e) {
// 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 {
public static void main(String[] args) throws IOException {
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 {
public static void main(String[] args) throws IOException {
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 {
public static void main(String[] args) throws IOException {
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用法
package BufferedWriter用法;import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;public class MainTest {
public static void main(String[] args) throws IOException {
//构造器一个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实现文本复制的方法
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 {
//这是我们常用的方法//public static void main(String[] args) {
// // TODO Auto-generated method stub// //实现非文本文件的复制// FileInputStream fileInputStream=null;// FileOutputStream fileOutputStream=null;// BufferedInputStream bufferedInputStream=null;// BufferedOutputStream bufferedOutputStream=null;// try {
// //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) {
// bufferedOutputStream.write(buf, 0, len);// bufferedOutputStream.flush();// }// } catch (IOException e2) {
// e2.printStackTrace();// }// //资源的关闭// //要求:先关外层,在关内层// try {
// if(bufferedInputStream!=null)// bufferedInputStream.close();// } catch (IOException e1) {
// // TODO Auto-generated catch block// e1.printStackTrace();// }// try {
// if(bufferedOutputStream!=null)// bufferedOutputStream.close();// } catch (IOException e) {
// // TODO Auto-generated catch block// e.printStackTrace();// }// //说明:关闭外层流的时候会自动关闭内层的流 fileInputStream.close(); fileOutputStream.close();//} //在这里我们把上面的方法进行封装 //封装一个实现文件复制的方法 public void copyFileWriterBuffered(String srcPath,String destPath) {
//实现非文本文件的复制 FileInputStream fileInputStream=null; FileOutputStream fileOutputStream=null; BufferedInputStream bufferedInputStream=null; BufferedOutputStream bufferedOutputStream=null; try {
//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) {
bufferedOutputStream.write(buf, 0, len); bufferedOutputStream.flush(); } } catch (IOException e2) {
e2.printStackTrace(); } //资源的关闭 //要求:先关外层,在关内层 try {
if(bufferedInputStream!=null) bufferedInputStream.close(); } catch (IOException e1) {
// TODO Auto-generated catch block e1.printStackTrace(); } try {
if(bufferedOutputStream!=null) bufferedOutputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } //说明:关闭外层流的时候会自动关闭内层的流// fileInputStream.close();// fileOutputStream.close();}}
5、调用上面封装的方法,并测试复制文件所需要的时间
package BufferedTest;public class TestCopyFileWriteBuffered {
public static void main(String[] args) {
// 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.进行图片的加密
package 课堂练习;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;/** * 进行图片的加密 * */public class PicTest {
public static void main(String[] args) {
// TODO Auto-generated method stub //FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\WQW\\Desktop\\bj.jpg")); //或者 try {
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) {
//加密:对字节数组进行修改// //错误的,buffer数据没有改变,只是b改变了// for (byte b : buffer) {
// b=(byte)(b^5);// } //正确的 for (int i = 0; i < len; i++) {
buffer[i] = (byte) (buffer[i] ^ 5); } fileOutputStream.write(buffer, 0, len); } fileInputStream.close(); fileOutputStream.close(); } catch (FileNotFoundException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); }}}
7、进行图片 的解密
package 课堂练习;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;/** * 进行图片的解密 * 主要是^位运算符的使用 * */public class PicTest2 {
public static void main(String[] args) {
// TODO Auto-generated method stub //FileInputStream fileInputStream = new FileInputStream(new File("C:\\Users\\WQW\\Desktop\\bj.jpg")); //或者 try {
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) {
//解密:对字节数组进行修改// //错误的,buffer数据没有改变,只是b改变了// for (byte b : buffer) {
// b=(byte)(b^5);// } //正确的 for (int i = 0; i < len; i++) {
buffer[i] = (byte) (buffer[i] ^ 5); } fileOutputStream.write(buffer, 0, len); } //资源的关闭 fileInputStream.close(); fileOutputStream.close(); } catch (FileNotFoundException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); }}}
8、其它
使用ByteArrayOutputStream来解决读取字节出现乱码问题
//如果文件内容太大,会出现乱码,可以用ByteArrayOutputStream来实现// byte[] buffer = new byte[20];// int len;// while((len= inputStream.read(buffer))!=-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) {
// 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、解决字符乱码问题
package 课堂练习;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.util.Arrays;public class Test4 {
public static void main(String[] args) {
// TODO Auto-generated method stub FileInputStream fileInputStream = null; try {
//创建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) {
int pos=0; for(byte v:buf) {
//记录负数的个数 if(v<0) {
pos++; } } if(pos%2==0) {
//将字节数组转化成字符串 String str= new String(buf,0,len); System.out.print(str); }else {
//再读取下一位 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) {
// TODO: handle exception e.printStackTrace(); }finally {
//关闭资源 try {
if(fileInputStream!=null) fileInputStream.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } }}}
十一、求一篇文档中的每个字符出现的次数
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 {
public static void main(String[] args) {
// TODO Auto-generated method stub FileReader fileReader = null; BufferedWriter bufferedWriter = null; try {
//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) {
//int 还原char char ch =(char)c; //判断char是否在map中第一次出现 if (map.get(ch)==null) {
map.put(ch, 1); }else {
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) {
switch(entry.getKey()) {
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) {
e.printStackTrace(); }finally {
try {
if(bufferedWriter!=null) bufferedWriter.close(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } }}}
十二、BufferedReader源码分析
1、分析构造器
public MyBufferedReader(Reader in, int sz) {
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方法
public int read(char cbuf[], int off, int len) throws IOException {
//编写同步锁代码块 synchronized (lock) {
//确认输入流不为空 ensureOpen(); if ((off < 0) || (off > cbuf.length) || (len < 0) || ((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException(); } else if (len == 0) {
return 0; } //从缓存区的数据复制到cbuf数组里面 int n = read1(cbuf, off, len); if (n <= 0) return n; //将之前处理不完的数据复制到cbuf数组,再次调用read1方法 while ((n < len) && in.ready()) {
int n1 = read1(cbuf, off + n, len - n); if (n1 <= 0) break; n += n1; } return n; } }
read1方法
private int read1(char[] cbuf, int off, int len) throws IOException {
//nextChar:记录下一次读取字符的位置 //nChars:记录缓存区可读的字符个数 //如果nextChar>nChars,则重新刷新缓存区 if (nextChar >= nChars) {
/* 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) {
return in.read(cbuf, off, len); } //针对缓存区的数据,重新刷新,将新的数据重新更新到缓存区 fill(); } if (nextChar >= nChars) return -1; if (skipLF) {
skipLF = false; if (cb[nextChar] == '\n') {
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方法(刷新)
private void fill() throws IOException {
int dst; //是否有调有mark方法,如果没有设置mark值,则markedChar <= UNMARKED为true if (markedChar <= UNMARKED) {
/* No mark */ dst = 0; } else {
/* Marked */ int delta = nextChar - markedChar; if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */ markedChar = INVALIDATED; readAheadLimit = 0; dst = 0; } else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */ System.arraycopy(cb, markedChar, cb, 0, delta); markedChar = 0; dst = delta; } else {
/* 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 {
//将输入流的数据读取到缓存区里面,n变量决定读取多个字符 n = in.read(cb, dst, cb.length - dst); } while (n == 0); //如果n>0,代表已经读到数据 if (n > 0) {
//nChars:缓存区可读的数据 nChars = dst + n; //下一次可读数据的位置 nextChar = dst; } }
十三、打印流(PrintStream\PrintWriter)
1、重定向概念
有两种重定向输出
- 默认的标准输出设备:控制台(以红色字体输出)
- 默认的标准输出设备:控制台
- 标准输出
- 标准错误输出
标准输入
- 默认的设备;键盘
上述重定向输入、输出都可以使用System类来描述
- 描述标准输出错误(默认控制台,红色字体输出)
- 描述标准输出(默认控制台)
- 描述标准输入(默认:键盘)
- System.in
- System.out
- System.err
举例
public class MainTest{
public static void main(String[] args){
//思路:使用System.in实现。System.in---->转换流----》BufferedReaderd的readline()方法 //将字节转换成字符 InputStreamReader isr = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(isr); while(true){
System.out.println("请输入字符"); String data = br.readLine(); if("e".equalsIgnoreCase(data)){
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 {
public static void main(String[] args) throws IOException {
/* 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 {
public static void main(String[] args) throws IOException {
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、举例
package RandomAccessFile实例;import java.io.File;import java.io.IOException;import java.io.RandomAccessFile;public class MainTest2 {
public static void main(String[] args) throws IOException {
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{
private String name; private int age; public String getName() {
return name;} public void setName(String name) {
this.name = name;} public int getAge() {
return age;} public void setAge(int age) {
this.age = age;} public Person(String name, int age) {
super(); this.name = name; this.age = age;} public Person() {
super();} @Override public String toString() {
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 {
//进行序列化处理 public static void main(String[] args) {
// TODO Auto-generated method stub //创建Person对象 Person person = new Person(); person.setAge(25); person.setName("张三"); FileOutputStream fileOutputStream; ObjectOutputStream objectOutputStream=null; try {
//创建一个输出流的文件 fileOutputStream = new FileOutputStream(new File("person.txt")); //ObjectOutputStream针对次此fileOutputStream进行处理 objectOutputStream= new ObjectOutputStream(fileOutputStream); //调用writerObject方法 objectOutputStream.writeObject(person); } catch (FileNotFoundException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); }finally {
//资源关闭 try {
//进行判断ObjectOutputStream对象是否创建成功 if(objectOutputStream!=null) objectOutputStream.close(); } catch (IOException e) {
// 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 {
//进行反序列化处理 public static void main(String[] args) {
// TODO Auto-generated method stub try {
//创建一个输入流的文件 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) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) {
// 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{
private String name; private int age; public String getName() {
return name;} public void setName(String name) {
this.name = name;} public int getAge() {
return age;} public void setAge(int age) {
this.age = age;} public Person2(String name, int age) {
super(); this.name = name; this.age = age;} public Person2() {
super();} @Override public String toString() {
return "Person [name=" + name + ", age=" + age + "]";} /** * 通过重写此方法,还原成文件 * 要用private方法 * */ private void readObject(java.io.ObjectInputStream in) {
try {
setName(in.readUTF().toUpperCase()); setAge(in.readInt()); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); }} /**通过重写此方法,自定义序列化逻辑(序列化,将对象序列化成字节,存储到磁盘) * * */ private void writeObject(java.io.ObjectOutputStream out) {
//将用户名序列化 try {
out.writeUTF(getName()); //将年龄序列化 out.writeInt(getAge()); } catch (IOException e) {
// TODO Auto-generated catch block e.printStackTrace(); }}}
还没有评论,来说两句吧...