Java IO 学习笔记
1.核心类
- File 文件类
- InputStream 字节输入流
- OutputStream 字节输出流
- Reader 字符输入流
- Writer 字符输出流
- Closeable 关闭流接口
- Flushable 刷新流接口
- Serializable 序列化接口
2.流分类
- 输入流:数据源到程序(InputStream、Reader读进来)
- 输出流:程序到目的地(OutputStream、Writer写进去)
- 节点流:可以直接从数据源或 目的地读写数据
- 处理流:不直接连接到数据源或目的地,是其他流进行封装。目的主要是简化操作和提高性能
- 节点流和处理流的关系:
- 节点流处于IO操作的第一线,所有操作必须用过他们进行
- 处理流可以对其他流进行处理(提高效率或操作灵活性)
- 字节流:按照字节读取数据(InputStream、OutputStream)
- 字符流:按照字符读取数据(Reader、Writer),因为文件编码的不同,从而有了对字符进行高效操作的字符流对象。
- 原理:底层还是基于字节流操作,自动搜寻了指定的码表
3.File常用API及文件编码
文件路径推荐表示法:
1.path= “D:/XXX/XXX/XXX.png”;
2.path=”D:”+File.separator+”java300”+File.separator+”XXX.png”;
API
- pathSeparator separator 路径|路径分隔符
- File(String parent,String child) 构造器
- File(File parent,String child)
- File(String name)
- getName() 文件名、路径名
- getPath()
- getAbsolutePath()
- getParent
- exists() 判断状态
- isFile()
- isDirectorv()
- length() 文件长度
- createNewFile() 创建新文件
- delete() 删除文件
- mkdir() 创建目录,需要确保上级目录存在,不存在时创建失败
- mkdirs() 创建目录,当父目录不存在时一同创建
- list() 下级名称
- listFiles() 下级File
- listRoots() 根路径
4.IO流读写操作
- InputStream 字节输入流的父类,数据单位为字节
- int read()
- void close()
- OutputStream 字节输出流的父类,数据单位为字节
- void write(int)
- void flush()
- void close()
- Reader 字符输入流的父类,数据单位为字符
- int read()
- void close()
- Writer 字符输出流的父类,数据单位为字符
- void write(String)
- void flush()
- void close()
5.代码段
输入流代码演示
1 package wangyue; 2 3 import java.io.*; 4 5 public class IoStudy02 { 6 public static void main(String[] args) { 7 //1.创建源 8 File file = new File("test"); 9 //2.创建流 10 InputStream is = null; 11 try { 12 is = new FileInputStream(file); 13 byte[] flush = new byte[30];//缓冲容器 14 int len;//接收长度 15 while ((len = is.read(flush)) != -1) { 16 String str = new String(flush, 0, len); 17 System.out.println(str); 18 } 19 } catch (FileNotFoundException e) { 20 e.printStackTrace(); 21 } catch (IOException e) { 22 e.printStackTrace(); 23 }finally { 24 if (is != null) { 25 try { 26 is.close(); 27 } catch (IOException e) { 28 e.printStackTrace(); 29 } 30 } 31 } 32 } 33 } 34
输出流代码演示
1 package wangyue; 2 3 import java.io.*; 4 5 public class IoStudy03 { 6 public static void main(String[] args) { 7 //1.创建源 8 File dest = new File("output.txt"); 9 //2.选择流 10 OutputStream os = null; 11 try { 12 os = new FileOutputStream(dest); 13 //3.操作 14 String msg = "向文件中写入一些没什么用的东西"; 15 byte[] datas = msg.getBytes();//字符串--》字节数组 (编码) 16 os.write(datas, 0, datas.length); 17 //刷新流,避免有数据存在在缓存中。即使os.close() 也会刷新流,此处也再刷新一次 18 os.flush(); 19 } catch (FileNotFoundException e) { 20 e.printStackTrace(); 21 } catch (IOException e) { 22 e.printStackTrace(); 23 }finally { 24 if (os != null) { 25 try { 26 os.close(); 27 } catch (IOException e) { 28 e.printStackTrace(); 29 } 30 } 31 } 32 33 } 34 } 35
文件拷贝
1 package wangyue; 2 3 import java.io.*; 4 5 public class IoStudy04 { 6 public static void main(String[] args) { 7 //1.创建源 8 File src = new File("C:/Users/86178/Desktop/微信截图_20191006134845.png"); 9 File dest = new File("C:/Users/86178/Desktop/copy.png"); 10 //2.选择流 11 InputStream is = null; 12 OutputStream os = null; 13 try { 14 is = new FileInputStream(src); 15 os = new FileOutputStream(dest,false); 16 //3.操作 17 byte[] flush = new byte[1024]; 18 int len; 19 while ((len = is.read(flush)) != -1) { 20 os.write(flush, 0, len); 21 } 22 //刷新流,避免有数据存在在缓存中。即使os.close() 也会刷新流,此处也再刷新一次 23 os.flush(); 24 } catch (FileNotFoundException e) { 25 e.printStackTrace(); 26 } catch (IOException e) { 27 e.printStackTrace(); 28 }finally { 29 if (os != null && is != null) { 30 //4.关闭资源,先打开的后关闭。注意要分别关闭 31 try { 32 is.close(); 33 } catch (IOException e) { 34 e.printStackTrace(); 35 } 36 try { 37 os.close(); 38 } catch (IOException e) { 39 e.printStackTrace(); 40 } 41 } 42 } 43 44 } 45 } 46
6.字节数组流 ByteArrayInputStream & ByteArrayOutputStream
字节数组流无需关闭,由java虚拟机gc进行回收.
7.IO工具类
1 package wangyue; 2 3 import java.io.*; 4 5 /** 6 * 1、封装拷贝 7 * 2、封装释放资源 8 */ 9 public class FileUtils { 10 11 public static void main(String[] args) { 12 13 byte[] datas = null; 14 //文件到文件 15 try { 16 InputStream is = new FileInputStream("test"); 17 OutputStream os = new FileOutputStream("test-copy.txt"); 18 copy(is, os); 19 } catch (IOException e) { 20 e.printStackTrace(); 21 } 22 //文件到字节数组 23 try { 24 InputStream is = new FileInputStream("test.png"); 25 ByteArrayOutputStream os = new ByteArrayOutputStream(); 26 copy(is, os); 27 datas = os.toByteArray(); 28 System.out.println(datas.length); 29 } catch (IOException e) { 30 e.printStackTrace(); 31 } 32 //字节数组到文件 33 try { 34 InputStream is = new ByteArrayInputStream(datas); 35 OutputStream os = new FileOutputStream("test-copy.png"); 36 copy(is,os); 37 } catch (FileNotFoundException e) { 38 e.printStackTrace(); 39 } 40 } 41 42 /** 43 * 对接输入输出流 44 * @param is 45 * @param os 46 */ 47 public static void copy(InputStream is, OutputStream os) { 48 try { 49 byte[] flush = new byte[2014];//缓冲容器 50 int len; 51 while ((len = is.read(flush)) != -1) { 52 os.write(flush, 0, len); 53 } 54 os.flush(); 55 } catch (IOException e) { 56 e.printStackTrace(); 57 }finally { 58 close(is,os); 59 } 60 } 61 62 /** 63 * 释放资源 64 * @param is 65 * @param os 66 */ 67 public static void close(InputStream is,OutputStream os) { 68 try { 69 if (is != null) { 70 is.close(); 71 } 72 } catch (IOException e) { 73 e.printStackTrace(); 74 } 75 76 try { 77 if (os != null) { 78 os.close(); 79 } 80 } catch (IOException e) { 81 e.printStackTrace(); 82 } 83 } 84 85 /** 86 * 释放资源 87 * @param ios 88 */ 89 public static void close(Closeable... ios) { 90 for (Closeable io : ios) { 91 try { 92 if (null != io) { 93 io.close(); 94 } 95 } catch (IOException e) { 96 e.printStackTrace(); 97 } 98 } 99 } 100 101 } 102
1 package wangyue; 2 3 import java.io.*; 4 5 public class FileUtils2 { 6 /** 7 * 对接输入输出流 8 * try...with...resource 9 * 不需要在finally中释放资源,只要try(is,os)即可,系统自动释放资源,不需要关心释放顺序 10 * @param is 11 * @param os 12 */ 13 public static void copy(InputStream is, OutputStream os) { 14 try (InputStream iss = new FileInputStream("sdf"); 15 OutputStream oss = new FileOutputStream("test")) { 16 17 byte[] flush = new byte[2014];//缓冲容器 18 int len; 19 while ((len = is.read(flush)) != -1) { 20 os.write(flush, 0, len); 21 } 22 os.flush(); 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 } 27 } 28
8.装饰器设计模式,原理剖析
1 package wangyue; 2 3 /** 4 * 模拟咖啡 5 * 1、抽象组件:需要装饰的抽象对象(接口或抽象父类) 6 * 2、具体组件:需要装饰的对象 7 * 3、抽象装饰类:包含了对抽象组件的引用,以及装饰者共有的方法 8 * 4、具体装饰类:被装饰的对象 9 */ 10 public class DecorateTest02 { 11 12 public static void main(String[] args) { 13 Drink coffee = new Coffee(); 14 Drink sugar = new Sugar(coffee); 15 System.out.println(sugar.info() + "-->" + sugar.cost()); 16 Drink milk = new Milk(coffee); 17 System.out.println(milk.info() + "-->" + milk.cost()); 18 } 19 } 20 //抽象组件 21 interface Drink { 22 double cost();//费用 23 String info();//说明 24 } 25 26 //具体组件 27 class Coffee implements Drink { 28 private String name = "原味咖啡"; 29 30 @Override 31 public double cost() { 32 return 10; 33 } 34 35 @Override 36 public String info() { 37 return name; 38 } 39 } 40 41 //抽象装饰类 42 abstract class Decorate implements Drink { 43 44 //对抽象组件的引用 45 private Drink drink; 46 47 public Decorate(Drink drink) { 48 this.drink = drink; 49 } 50 51 @Override 52 public double cost() { 53 return this.drink.cost(); 54 } 55 56 @Override 57 public String info() { 58 return this.drink.info(); 59 } 60 } 61 62 //具体的装饰类 63 class Milk extends Decorate { 64 65 public Milk(Drink drink) { 66 super(drink); 67 } 68 @Override 69 public double cost() { 70 return super.cost() * 4; 71 } 72 73 @Override 74 public String info() { 75 return super.info() + "牛奶"; 76 } 77 } 78 //具体的装饰类 79 class Sugar extends Decorate { 80 81 public Sugar(Drink drink) { 82 super(drink); 83 } 84 @Override 85 public double cost() { 86 return super.cost() * 2; 87 } 88 89 @Override 90 public String info() { 91 return super.info() + "加入优质方糖"; 92 } 93 } 94 95
9.字节缓冲流 BufferedInputStream & BufferedOutputStream
- 提升性能
- 最底层一定是节点流
- 只需要释放最外层的处理流,java自动寻找对应的字节流,并释放
使用方式,直接在字节流外面加上字节缓冲流,能够显著提升效率
1 InputStream is = new BufferedInputStream(new FileInputStream(src)); 2 OutputStream os = new BufferedOutputStream(new FileOutputStream(dest));
释放资源只需要释放最外层的流即可
10.字符缓冲流 BufferedReader & BufferedWriter
仅限于纯文本操作
11.转换流 InputStreamReader & OutputStreamWriter
是字节流与字符流之间的桥梁,能将字节流转换为字符流,并且能够为字节流指定字符集,可处理一个个的字符
1 package wangyue; 2 3 import java.io.*; 4 5 /** 6 * 转换流:InputStreamReader OutputStreamWriter 7 * 1、以字符流的形式操作字节流(纯文本) 8 * 2、指定字符集 9 */ 10 public class ConvertTest { 11 public static void main(String[] args) { 12 //操作System.in和System.out 13 try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); 14 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(System.out))) { 15 //循环获取键盘的输入(exit退出),输出此内容 16 String msg = ""; 17 while (!msg.equals("exit")) { 18 msg = reader.readLine();//循环读取 19 writer.write(msg);//循环写出 20 writer.newLine(); 21 writer.flush();//强制刷新,内容太少,必须强制刷新,否则数据驻留在缓存中,只有当缓存满了,才会写一次 22 } 23 } catch (IOException e) { 24 e.printStackTrace(); 25 } 26 27 } 28 } 29
1 package wangyue; 2 3 import java.io.*; 4 import java.net.URL; 5 6 /** 7 * 转换流:InputStreamReader OutputStreamWriter 8 * 1、以字符流的形式操作字节流(纯文本) 9 * 2、指定字符集 10 */ 11 public class ConvertTest02 { 12 public static void main(String[] args) { 13 //操作网络流 下载百度源码 14 try (BufferedReader reader = new BufferedReader(new InputStreamReader(new URL("http://www.baidu.com").openStream(), "UTF-8")); 15 BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("baidu.html"), "UTF-8")) 16 ) { 17 18 String temp = null; 19 while ((temp = reader.readLine()) != null) { 20 writer.write(temp); 21 writer.newLine(); 22 writer.flush(); 23 } 24 } catch (IOException e1) { 25 e1.printStackTrace(); 26 } 27 } 28 } 29
12.数据流 DataInputStream & DataOutputStream
简单说,就是保留了数据类型的字节流,操作的是一些基本 类型和字符串
最好再怼上一个字节缓冲流,提升下性能
1 package wangyue; 2 3 import java.io.*; 4 5 /** 6 * 数据流: 7 * 1、写出后读取 8 * 2、读取的顺序与写出保持一致 9 * 10 * DataOutputStream 11 * DataInputStream 12 */ 13 public class DataTest { 14 15 public static void main(String[] args) throws IOException { 16 //写出 17 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 18 DataOutputStream dos = new DataOutputStream(baos); 19 //操作数据类型+数据 20 dos.writeUTF("嘿嘿嘿"); 21 dos.writeInt(123); 22 dos.writeBoolean(false); 23 byte[] datas = baos.toByteArray(); 24 //读取 25 DataInputStream dis = new DataInputStream(new ByteArrayInputStream(datas)); 26 String UTF = dis.readUTF(); 27 int i = dis.readInt(); 28 boolean b = dis.readBoolean(); 29 System.out.println(UTF); 30 System.out.println(i); 31 System.out.println(b); 32 33 } 34 } 35
13.对象流 ObjectInputStream & ObjectOutputStream
操作所有对象。
对象的序列化和反序列化
对象要进行序列化或反序列化必须实现 Serializable 接口,Serializable接口是一个空接口,没有任何意义,只是给虚拟机的一个标识
进行数据还原时,为了避免类型转换异常,先使用 instanceof 关键字进行类型的判断
1 if(str instanceof String){ 2 String strObject = (String) str; 3 }
在一个实现了序列化接口的类中,某属性属于敏感信息,不应该被序列化,可使用 transient(透明) 关键字。标识某属性不需要序列化
1 Class Employee implements Serializable{ 2 private transient String name;//不需要序列化 3 private double salary; 4 }
14.打印流 PrintStream
15.随机流 RandomAccessFile
随机流加上多线程,可以实现对一个大文件的多线程分段下载
1 package wangyue; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.RandomAccessFile; 6 7 /** 8 * 随机读取和写入流 RandomAccessFile 9 */ 10 public class RandTest01 { 11 public static void main(String[] args) throws IOException { 12 RandomAccessFile raf = new RandomAccessFile(new File("baidu.html"), "r"); 13 //起始位置 14 int beginPos = 2; 15 //实际大小 16 int actualSize = 1026; 17 //随机读取 18 raf.seek(2); 19 byte[] flush = new byte[1024]; 20 int len = -1; 21 while ((len = raf.read(flush))!=-1) { 22 if (actualSize > len) {//获取本次读取的所有内容 23 System.out.println(new String(flush,0,len)); 24 actualSize -= len; 25 } else { 26 System.out.println(new String(flush,0,len)); 27 break; 28 } 29 } 30 raf.close(); 31 } 32 } 33
16.合并流 SequenceInputStream
17.Commons IO FileUtils使用
依赖的jar包
代码演示
1 package commons; 2 3 import org.apache.commons.io.FileUtils; 4 import org.apache.commons.io.IOUtils; 5 import org.apache.commons.io.LineIterator; 6 import org.apache.commons.io.filefilter.DirectoryFileFilter; 7 import org.apache.commons.io.filefilter.EmptyFileFilter; 8 import wangyue.FileUtil; 9 10 import java.io.File; 11 import java.io.IOException; 12 import java.net.URL; 13 import java.util.ArrayList; 14 import java.util.Collection; 15 import java.util.List; 16 17 /** 18 * 大小、列出子孙集、读取文件、写出文件 19 * 重点:拷贝 20 */ 21 public class CIOTest01 { 22 public static void main(String[] args) throws IOException { 23 //文件大小 24 long len = FileUtils.sizeOf(new File("test.png")); 25 System.out.println(len); 26 //目录大小 27 len = FileUtils.sizeOf(new File("G:/work/IOStudy")); 28 System.out.println(len); 29 //返回子孙集 30 //FileUtils.listFiles(目录,过滤文件(是否为空,后缀名,支持组合(and,or)等等),过滤目录 null代表只走一层 DirectoryFileFilter.INSTANCE表示子孙集) 31 Collection<File> files = FileUtils.listFiles(new File("G:/work/IOStudy"), EmptyFileFilter.NOT_EMPTY, DirectoryFileFilter.INSTANCE); 32 for (File file : files) { 33 System.out.println(file.getAbsolutePath()); 34 } 35 //读取文件 36 String msg = FileUtils.readFileToString(new File("test"), "UTF-8"); 37 System.out.println(msg); 38 byte[] datas = FileUtils.readFileToByteArray(new File("test")); 39 System.out.println(datas.length); 40 //逐行读取 41 List<String> msgs = FileUtils.readLines(new File("output.txt"), "UTF-8"); 42 for (String msgone : msgs) { 43 System.out.println(msgone); 44 } 45 LineIterator it = FileUtils.lineIterator(new File("output.txt")); 46 while (it.hasNext()) { 47 System.out.println(it.nextLine()); 48 } 49 //写出内容 50 FileUtils.write(new File("good.wy"), "只有不断的学习,才有机会更进一步\r\n", "UTF-8",false);//最后一个参数表示是否追加,默认false 51 FileUtils.writeStringToFile(new File("good.wy"), "只有不断的学习,才有机会更进一步\r\n", "UTF-8",true); 52 FileUtils.writeByteArrayToFile(new File("good.wy"), "只有不断的学习,才有机会更进一步\r\n".getBytes("UTF-8"),true); 53 //写出列表 54 List<String> data = new ArrayList<>(); 55 data.add("马云"); 56 data.add("马华腾"); 57 data.add("马哥"); 58 FileUtils.writeLines(new File("good.wy"),data,"-----",true); 59 60 //复制文件 61 // FileUtils.copyFile(new File("test.png"), new File("test-copy2.png")); 62 //复制文件到目录 63 // FileUtils.copyFileToDirectory(new File("test.png"),new File("lib")); 64 //复制目录到目录,是先创建lib2,然后将lib复制到lib2目录下 65 // FileUtils.copyDirectoryToDirectory(new File("lib"), new File("lib2")); 66 //复制目录,直接复制lib,粘贴时修改目录名为lib3 67 // FileUtils.copyDirectory(new File("lib"), new File("lib3")); 68 //拷贝URL内容 69 // String url = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1570559702535&di=a5b17ed682978dd64e461156092f6fa6&imgtype=jpg&src=http%3A%2F%2Ft-1.tuzhan.com%2F56215ac87b82%2Fc-1%2Fl%2F2012%2F10%2F08%2F15%2Ff955c4477ad445a184778d45f667e437.jpg"; 70 // FileUtils.copyURLToFile(new URL(url), new File("钢铁侠.jpg")); 71 String baiduStr = IOUtils.toString(new URL("http://www.baidu.com"), "UTF-8"); 72 System.out.println(baiduStr); 73 74 } 75 } 76