IO流
一,文件
1,什么是文件
文件时保存数据的地方,比如大家经常使用的word文档,txt文件,excel文件...都是文件。它既可以保存一张图片,也可以保存视频,声音.........
2.文件流

3.常见的文件操作
1.创建文件对象相关构造器和方法

2.创建文件的三种方式
public class FileCreate { //方式 1 new File(String pathname) @Test public void creat01(){ String filePath = "e:\\new01.txt"; //这里的 file 对象,在java 程序中,只是一个对象 //只有执行了 createNewFile 方法,才会真正的,在磁盘创建该文件 File file = new File(filePath); try { file.createNewFile(); System.out.println("文件new01.txt创建成功"); } catch (IOException e) { e.printStackTrace(); } } //方式 2 new File(File parent,String child) //根据父目录文件+子路径构建 @Test public void creat02(){ File parentPath = new File("e://"); String childPath = "new02.txt"; File file = new File(parentPath, childPath); try { file.createNewFile(); System.out.println("new02.txt创建成功"); } catch (IOException e) { e.printStackTrace(); } } //方式 3 new File(String parent,String child) //根据父目录+子路径构建 @Test public void creat03(){ String parentPath = "e:\\"; String childPath = "new03.txt"; File file = new File(parentPath, childPath); try { file.createNewFile(); System.out.println("new03.txt文件创建成功"); } catch (IOException e) { e.printStackTrace(); } } }
3. 获取文件的相关信息

//获取文件信息 @Test public void info(){ //创建文件对象 File file = new File("e:\\new01.txt"); //调用相应的方法,获取文件信息 System.out.println("文件名字 :" + file.getName()); //文件名字 :new01.txt //getName 、getAbsolutePath 、getParent 、length 、exists 、isFile 、isDirectory System.out.println("文件绝对路径:" + file.getAbsolutePath()); //文件绝对路径:e:\new01.txt System.out.println("文件父级目录 :" + file.getParent()); //文件父级目录 :e:\ System.out.println("文件大小(字节)=" + file.length()); //文件大小(字节)=0 System.out.println("文件是否存在=" + file.exists());// 文件是否存在=true System.out.println("是不是一个文件=" + file.isFile());// 是不是一个文件=true System.out.println("是不是一个目录=" + file.isDirectory());// 是不是一个目录=false }
4. 目录的操作和文件的删除
mkdir创建一级目录,madirs创建多级目录,delete删除空目录或文件
//判断文件new03.txt是否存在,存在就删除 @Test public void delete01(){ String path = "e://new03.txt"; File file = new File(path); if (file.exists()){ if (file.delete()){ System.out.println(file + "删除成功"); }else { System.out.println(file + "删除失败"); } }else { System.out.println("文件不存在"); } } //判断文件是否存在,存在就删除,否则提示不存在e:\\demo\\a\\b\\c判断文件new03.txt是否存在,存在就删除 @Test public void mkdir01(){ String path = "e:\\demo\\a\\b\\c"; File filePath = new File(path); if (filePath.exists()){ System.out.println(filePath + "文件存在"); }else { if (filePath.mkdirs()){ System.out.println(filePath + "创建成功"); }else { System.out.println(filePath + "创建失败"); } } }
5, 筛选”.jpg" 文件 和 遍历e盘
public class File01 { //筛选含有“.jpg"的照片 public static void main(String[] args) throws IOException { File file = new File("e:/test"); file.createNewFile(); FilenameFilter filenameFilter = new FilenameFilter(){ @Override public boolean accept(File dir, String name) { if (name.lastIndexOf(".jpg") == -1){ return false; }else { return true; } } }; String[] list = file.list(filenameFilter); System.out.println(Arrays.toString(list)); } }
@SuppressWarnings({"all"})
public class File02 {
public static void main(String[] args) {
File file = new File("e:\\"); //遍历e盘下的文件
String[] list = file.list();
for (String s : list) {
System.out.println(s); //只遍历
}
File[] files = file.listFiles();
for (File file1 : files) {
System.out.println(file1); //带绝对路径的遍历
}
}
}
public class File02 { public static void main(String[] args) { File file = new File("e:\\test"); String[] list = file.list(); //遍历文件夹 for (String str : list) { //找到最后一次出现“.”的位置 int lastIndexOf = str.lastIndexOf("."); //截取 String substring = str.substring(lastIndexOf); //比较 if (substring.equals(".jpg")){ System.out.println(str); } } } }
二,IO流的原理及分类
1. JAVA IO 流原理


2. 流的分类

3. IO 流体系图-常用的类

文件VS流
三,常用的类


1. FileInputStream 字节输入流
public class FileInputSteam_ { @Test public void readFile(){ String path = "e:\\hello.txt"; FileInputStream inputStream = null; int readData = 0; //接收读出来的数据 try { inputStream = new FileInputStream(path); //从该输入流读取一个字节的数据。 如果没有输入可用,此方法将阻止。 //如果返回- 1 , 表示读取完毕 try { while ((readData = inputStream.read()) != -1){ System.out.print((char) readData); } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally { try { //关闭文件流,释放资源. inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } @Test public void readFile01() { String path = "e:\\hello.txt"; byte[] buf = new byte[8]; //字节数组 一次读取8个字节 int readData = 0; FileInputStream inputStream = null; try { inputStream = new FileInputStream(path); //从该输入流读取最多 b.length 字节的数据到字节数组。 此方法将阻塞,直到某些输入可用。 // 如果返回- 1 , 表示读取完毕 //如果读取正常, 返回实际读取的字节数 while ((readData = inputStream.read(buf)) != -1){ System.out.print(new String(buf,0,readData)); } } catch (IOException e) { e.printStackTrace(); }finally { try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }
2. FileOutputStream 字节输出流
请使用 FileOutputStream 在 a.txt 文件,中写入 “hello ,world”
@Test public void writerFile(){ String path = "e:\\a.txt"; FileOutputStream outputStream = null; try { //1. new FileOutputStream(filePath) 创建方式,当写入内容是,会覆盖原来的内容 // 2. new FileOutputStream(filePath, true) 创建方式,当写入内容是,是追加到文件后面 outputStream = new FileOutputStream(path,true); try { //1.写入一个字节 // outputStream.write('H'); String str = "hello word"; ////写入字符串 //2. 写一个字符串 //str.getBytes() 可以把 字符串-> 字节数组 // outputStream.write(str.getBytes()); //3. write(byte[] b, int off, int len) 将 len 字节从位于偏移量 off 的指定字节数组写入此文件输出流 outputStream.write(str.getBytes(),0,str.length()); } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally { try { outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
文件的拷贝
@Test public void readWriterFile(){ String strFile = "e:\\123.jpg"; //1. 创建文件的输入流 , 将文件读入到程序 String destFile = "e:\\321.jpg";//2. 创建文件的输出流, 将读取到的文件数据,写入到指定的文件. FileInputStream inputStream = null; FileOutputStream outputStream = null; try { inputStream = new FileInputStream(strFile); outputStream = new FileOutputStream(destFile); byte[] buf = new byte[8]; //定义一个字节数组,提高读取效果 int readLine = 0; try { while ((readLine = inputStream.read(buf)) != -1){ //读取到后,就写入到文件 通过 fileOutputStream //即,是一边读,一边写 outputStream.write(buf,0,readLine); } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally { try { if (inputStream != null){ inputStream.close(); } if (outputStream != null){ outputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } }
3. FileReader (字符输入流) 和 FileWriter(字符输出流) 介绍

1). FileReader 相关方法:

public class FileReader_ { @Test public void reader01(){ //通过单个字符读取 String path = "e:\\hello.txt"; FileReader reader = null; int readLin = 0; try { reader = new FileReader(path); try { while ((readLin = reader.read()) != -1){ System.out.print((char)readLin); } } catch (IOException e) { e.printStackTrace(); } } catch (FileNotFoundException e) { e.printStackTrace(); }finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } @Test public void reader02() { //第二种多个字符读取 String path = "e:\\hello.txt"; FileReader reader = null; int readLin = 0; char[] but = new char[8]; try { //循环读取 使用 read(buf), 返回的是实际读取到的字符数 //如果返回- 1, 说明到文件结束 reader = new FileReader(path); while ((readLin = reader.read(but)) != -1){ System.out.print(new String(but,0,readLin)); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
2) ,FileWriter 常用方法

public class FileWriter_ { public static void main(String[] args) { String path = "e:\\node.txt"; FileWriter writer = null; char[] chars = {'a','v','c'}; try { writer = new FileWriter(path,true); writer.write("你好"); writer.write("你好啊 ,好好学java".toCharArray(),0,5); writer.write('s'); writer.write(chars); writer.write("风雨过后见彩虹",0,6); } catch (IOException e) { e.printStackTrace(); }finally { try { writer.flush(); } catch (IOException e) { e.printStackTrace(); } } System.out.println("程序结束"); } }
四,节点流和处理流
1.基本介绍
节点流可以从一个特定的数据源读写数据,如fileReader,FileWriter
处理流也叫包装流,是‘连接’在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader,BufferedWriter
2. 节点流和处理流一览图

3. 节点流和处理流的区别和联系

4.处理流的功能主要体现在以下几个方面

5.BufferReader 和 BufferWriter 字符包装流
public class BufferReader { public static void main(String[] args) throws Exception { String path = "e:\\hello.txt"; BufferedReader bufferedReader = new BufferedReader(new FileReader(path)); String line; while ((line =bufferedReader.readLine()) != null){ System.out.println(line); } bufferedReader.close(); } }
public class BufferedWriter_ { public static void main(String[] args) throws IOException { //1. new FileWriter(filePath, true) 表示以追加的方式写入 //2. new FileWriter(filePath) , 表示以覆盖的方式写入 String path = "e:\\ok.txt"; BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(path)); bufferedWriter.write("好好学习java"); bufferedWriter.close(); } }
字符包装流拷贝文件
public class BufferedCopy_ { public static void main(String[] args) { //1. BufferedReader 和 BufferedWriter 是安装字符操作 //2. 不要去操作 二进制文件[声音,视频,doc, pdf ], 可能造成文件损坏 String path = "e:\\hello.txt"; String newPath = "e:\\hello01.txt"; BufferedReader br = null; BufferedWriter bw = null; String line; try { br = new BufferedReader(new FileReader(path)); bw = new BufferedWriter(new FileWriter(newPath)); while ((line = br.readLine()) != null){ //每读取一行,就写入 bw.write(line); //插入一个换行 bw.newLine(); } System.out.println("拷贝完毕..."); } catch (IOException e) { e.printStackTrace(); }finally { try { if (br != null){ br.close(); } if (bw != null){ bw.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
6. 字节处理流-BufferedInputStream 和 BufferedOutputStream
public class BufferedCopy02 { public static void main(String[] args) { String srcPath = "e:\\123.jpg"; String destFilePath = "e:\\231.jpg"; //创建 BufferedOutputStream 对象 BufferedInputStream 对象 BufferedInputStream bis = null; BufferedOutputStream bos = null; try { //因为 FileInputStream 是 InputStream 子类 bis = new BufferedInputStream(new FileInputStream(srcPath)); bos = new BufferedOutputStream(new FileOutputStream(destFilePath)); //循环的读取文件,并写入到 destFilePath int resLine = 0; byte[] bytes = new byte[1024]; while ((resLine = bis.read(bytes)) != -1){ bos.write(bytes,0,resLine); } System.out.println("拷贝完成"); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bis != null){ bis.close(); } if (bos != null){ bos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
7. 对象流-ObjectInputStream 和 ObjectOutputStream
1.序列化和反序列化
1)序列化就是保存数据时,保存数据的值和数据类型
2)反序列化就是在恢复数据时,恢复数据的值和数据类型
3)需要让某个对象支持序列化机制,则必须让其子类时可序列化的,为了让某个类时可序列化的,该类必须实现如下两个接口之一:
Serializable 这个是标记接口,没有方法
Externalizable 该接口有方法需要实现,因此我们一般实现上面的Serializable接口

2. 对象流介绍
功能:提供了对基本类型或对象类型的序列化和反序列化的方法
ObjectOutputStream 提供 序列化功能
ObjectInputStream 提供 反序列化功能


序列化 代码
public class ObjectOutStream_ { public static void main(String[] args) throws Exception { //序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存 String path = "e:\\data.dat"; ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path)); //序列化数据到 e:\data.dat oos.writeInt(100); // int -> Integer (实现了 Serializable) oos.writeDouble(9.8);// double -> Double (实现了 Serializable) oos.writeChar('v');// char -> Character (实现了 Serializable) oos.writeUTF("疾控寂痕"); //String oos.writeObject(new Dog("小花",18)); //保存一个 dog 对象 oos.close(); System.out.println("序列化完毕.............."); } } //序列化的类必须实现这个接口 class Dog implements Serializable { private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
反序列化代码
public class ObjectInputStream_ { public static void main(String[] args) throws Exception { //指定反序列化的文件 String path = "e:\\data.dat"; //1.创建流对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path)); //2.读取的顺序(反序列化)应该和你保存数据(序列化)的顺序一直 System.out.println(ois.readInt()); System.out.println(ois.readDouble()); System.out.println(ois.readChar()); System.out.println(ois.readUTF()); System.out.println(ois.readObject()); //3.关闭 ois.close(); System.out.println("反序列化完成"); } }

8. 标准输入输出流

public class System01 { public static void main(String[] args) { //System 类里面的 public final static InputStream in = null; //System.in 编译类型 InputStream //System.in 运行类型 class java.io.BufferedInputStream //表示的是标准输入 键盘 System.out.println(System.in.getClass()); // public final static PrintStream out = null; // 编译类型 PrintStream //运行类型 class java.io.PrintStream //表示的是标准输出 显示器 System.out.println(System.out.getClass()); } }
9,转换流-InputStreamReader 和 OutputStreamWriter


介绍
1) InputStreamReader: Reader 的子类,可以将InputStream(字节流)包装成(转换成)Reader(字符流)
2) OutputStreamWriter: Writer的子类,实现将OutputStream(字节流)包装成Writer (字符流)
3)当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换城字符流
4) 可以在使用时指定编码格式(比如 utf-8 ,gbk , gb2312等)
案例一:将字符流FileInputStream 包装成字符流InputStreamReader,对 文件进行读取(按照 utf-8/ gbk格式),进而在包装成BufferReader
public class InputStreamReader_ { public static void main(String[] args) throws Exception { // 演示使用 InputStreamReader 转换流解决中文乱码问题 // 将字节流 FileInputStream 转成字符流 InputStreamReader, 指定编码 gbk/utf-8 String path = "e:\\abc.txt"; // //1. 把 FileInputStream 转成 InputStreamReader // //2. 指定编码 gbk // InputStreamReader isr = new InputStreamReader(new FileInputStream(path),"utf-8"); // //3. 把 InputStreamReader 传入 BufferedReader // BufferedReader br = new BufferedReader(isr); //123合并写 BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream(path),"utf-8")); //4 读取 String s = br.readLine(); System.out.println(s); //关闭外层流 br.close(); } }
案例二 : 字节流FileOutputStream 包装成字符流OutputStreamWriter,对文件进行写入
public class OutputStreamWrite_ { public static void main(String[] args) throws Exception { String path = "e:\\hsp.txt"; String charSet = "utf-8"; // 1.创建流对象 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d:\\a.txt"), charSet); // 2.写入 osw.write("hello,韩顺平教育~"); // 3.关闭 osw.close(); System.out.println("按照" + charSet + "保存成功"); } }
10, 打印流-PrintStream 和 PrintWriter
1. 打印流只有输出流没有输入流


2. PrintStream 字节输出流
public class PrintStream_ { //字节输出流 public static void main(String[] args) throws IOException { PrintStream out = System.out; //在默认情况下,PrintStream 输出数据的位置是 标准输出,即显示器 out.print("你好"); //因为 print 底层使用的是 write , 所以我们可以直接调用 write 进行打印/输出 out.write("好好学java".getBytes()); out.close(); //我们可以去修改打印流输出的位置/设备 //1. 输出修改成到 "e:\\a.txt" System.setOut(new PrintStream("e:\\a.txt")); System.out.println("好好学习 天天向上"); } }
3 PrintWriter字符输出流
public class PrintWriter_ { public static void main(String[] args) throws IOException { // PrintWriter printWriter = new PrintWriter(System.out);//里面传的是打印的位置 //更改写入的位置 PrintWriter printWriter = new PrintWriter(new FileWriter("e:\\a.txt")); printWriter.print("你好 北京"); printWriter.close(); } }
11. Properties 类
引入外部文件传统方式,比较麻烦 上代码
public class Properties01 { public static void main(String[] args) throws Exception { //读取 mysql.properties 文件,并得到 ip, user 和 pwd BufferedReader br = new BufferedReader(new FileReader("src\\mysql.properties")); String line = ""; while ((line = br.readLine()) != null){//循环读取 String[] split = line.split("="); //如果我们要求指定的 ip 值 if("ip".equals(split[0])) { System.out.println(split[0] + "值是: " + split[1]); } } br.close(); } }
1. 基本介绍:


废话不多说 上代码
public class Properties02 { public static void main(String[] args) throws IOException { //1. 创建 Properties 对象 Properties properties = new Properties(); //2. 加载指定配置文件 properties.load(new FileReader("e:\\123.properties")); //3. 把 k-v 显示控制台 properties.list(System.out); //4. 根据 key 获取对应的值 String user = properties.getProperty("user"); String pwd = properties.getProperty("pwd"); System.out.println("名字" + user + "密码" + pwd); } }
将修改保存配置文件操作
public class Properties03 { public static void main(String[] args) throws Exception { //使用 Properties 类来创建 配置文件, 修改配置文件内容 Properties properties = new Properties(); //创建 //1.如果该文件没有 key 就是创建 //2.如果该文件有 key ,就是修改 properties.setProperty("name","博文");////注意保存时,是中文的 unicode 码值 properties.setProperty("age","28"); properties.setProperty("user","123456"); //将k-v 存储文件中即可 properties.store(new FileOutputStream("e:\\123.properties"),null); System.out.println("文件配置成功"); } }
无论是那种流, 用完之后都需要关闭 close掉
垃圾回收器(GC garbage collector) 只能回收纯内存资源
但是流对象 的堆内存中 有一部分是指向本地操作系统的文件的
如果这个链接不断开
那么对象地址断开了 也不会变成垃圾对象
因为堆内存的流对象依然针对本地文件有链接操作
不同操作系统有对应的换行符
windows里面的换行符号是 \r\n
linux操作系统是 \n
macos操作系统是 \r
注意:
字节是指当前数据在计算机内存中所占的空间
字符是指 一个汉字或者一个字母 都算是一个字符
由于Idea开发工具的原因 目前我们使用的编码是UTF-8(后面讲)
UTF-8编码下 一个汉字占3个字节 一个字母占1个字节
注意: 如果关联的文件不存在则自动创建, 路径不存在则报错.
//输出 好java 一个汉字三个字节 你好java
// ops.write("你好java".getBytes(),3,6);ops.close();
/*
编码表
由字符及其对应的数值组成的一张表
常见编码表
ASCII:美国标准信息交换码。
用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表
用一个字节的8位表示。
GB2312:国标, 中国的中文编码表。
GBK(相对其他两个用的比较多):中国的中文编码表升级,融合了更多的中文文字符号。 一个汉字用两个字节存储
GB18030:GBK的取代版本
BIG-5码 :通行于台湾省、香港地区的一个繁体字编码方案,俗称“大五码”。
Unicode:国际标准码,融合了多种文字。 相对其他的编码, 一个符号占用的字节往往要更多一点
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8(所有编码中目前用的最多的):最多用三个字节来表示一个字符。 各取所长, 一个汉字三个字节, 一个字母一个字节
编码
把看得懂的变成看不懂的 字符串 -> byte数组
解码
把看不懂的变成看得懂的 byte数组 -> 字符串
乱码:
1.编码与解码中间 码表发生了切换 字符串编码解码的时候会说到
2.漏了一些字节
3.使用不支持这个字符的编码表
字符串编码与解码
注意: 如果本身这个编码表就不支持中文, 强行用这种编码表编码中文, 也会出现乱码问题
注意: 只要是编码或者解码, 只要是把能看懂的变成看不懂的, 就一定是参照了某种编码表的

浙公网安备 33010602011771号