IO流
文章目录
1.概述
1.1 什么是 IO 流?
存储和读取数据的解决方案
I : input
O : output
流:像水流一样传输数据
1.2 IO 流的作用?
用于读写数据 ( 本地文件,网络 )
1.3 IO 流的分类?
1. IO 流按照**流向**可以分类哪两种流?==主体是程序==
  输出流 : 程序 => 文件
  输入流 : 文件 => 程序
2. IO 流按照**操作文件**的类型可以分类哪两种流?
  字节流 : 可以操作所有类型的文件
  字符流 : 只能操作纯文本文件
1.4 什么是纯文本文件?
用 windows 系统自带的记事本打开并且能读懂的文件 txt 文件,md文件,xml 文件,lrc 文件等。
1.5 IO 流的体系结构
2.字节流
2.1 FileOutputStream
-
FileOutputStream的书写细节
package com.str.box; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class demo01 { public static void main(String[] args) throws IOException { /* * 字节输出流 FileOutputStream * 实现需求:写出一段文字到本地文件中 (暂时不写中文) * 实现步骤: * 1.创建对象 * 细节1:参数是字符串表示的路径或者是File对象都是可以的。 * 细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的 * 细节3:如果文件已经存在,则会清空文件 * 2.写出数据 * 细节:write方法的参数是整数,但是实际上写到本地文件中的是整数在ASCII上对应的字符 * 3.释放资源 * 细节:每次使用完流之后都要释放资源 * */ // 1.创建对象:指定文件的相对路径 FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt"); // 2.写出数据 fos.write(97); fos.write(57); fos.write(55); // 3.释放资源 fos.close(); } }
-
FileOutputStream写数据的3种方式
package com.str.box;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
// 1.创建对象
FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
// 2.写出数据
fos.write(97); //a
fos.write(98); //b
byte[] bytes = {97,98,99,100,101};
fos.write(bytes);
fos.write(bytes,0,2);
// 3.释放资源
fos.close();
}
}
- 换行写、续写
package com.str.box;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo04 {
public static void main(String[] args) throws IOException {
/*换行写:再次写出一次换行符即可
* Windows: \r\n
* Linux: \n
* Mac: \r
* 细节:
* 在windows操作系统当中,java对回车换行进行了优化,
* 虽然完整的是\r\n,但是我们写其中一个\r或者\n,
* java也可以实现换行,因为java在底层会补全
* 建议: 不要省略,还是写全。
* */
/*
* 续写(追加写入):
* 如果想要续写,打开续写开关即可开关位置:创建对象的第二个参数默认
* false:表示关闭续写,此时创建对象会清空文件
* 手动传递true:表示打开续写,此时创建对象不会清空文件
* */
// 1.创建对象
FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt",true);
// 2.写出数据
String str = "kankelaoyezuishuai";
byte[] bytes1 = str.getBytes();
fos.write(bytes1);
String wrap = "\r\n";
byte[] bytes = wrap.getBytes();
fos.write(bytes);
String str2 = "666";
byte[] bytes2 = str2.getBytes();
fos.write(bytes2);
// 3.释放资源
fos.close();
}
}
2.2 FileInputStream
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中。
package com.str.box.FileIntputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class demo01 {
public static void main(String[] args) throws IOException {
/*
* 字节输入流 FileInputStream
* 实现需求:读取文件中的数据(暂时不写中文)
* 实现步骤:
* 创建对象;读取数据;释放资源
* */
FileInputStream fis = new FileInputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
int b1 = fis.read();
System.out.println(b1);
System.out.println((char) b1);
fis.close();
}
}
- 字节输入流的细节
- 创建字节输入流对象
细节1 : 如果文件不存在,就直接报错;Java为什么会这么设计呢?
输出流 : 不存在,创建文件并把数据写到文件当中
输入流 : 不存在,因为创建出来的文件是没有数据的,没有读取的意义。所以Java就没有设计这种无意义的逻辑,文件不存在直接报错。- 写数据
细节1 : 一次读一个宁节,读出来的是数据在ASCII上对应的数
细节2 : 读到文件末尾了,read方法返回 -1- 释放资源
细节:每次使用完流之后都要释放资源
- FileInputStream的循环读取
package com.str.box.FileIntputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
// 2. 循环读取
int b;
while ((b = fis.read()) != -1){
System.out.print((char) b);
}
/*read:表示读取数据,而且是读取一个数据就移动一次指针
* */
fis.close();
}
}
2.3 文件拷贝
- 文件拷贝的基本代码
package com.str.box.FileIntputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo03 {
public static void main(String[] args) throws IOException {
/*
* 文件拷贝
* 把D:\练习\电赛\预览效果.mp4拷贝到当前模块下
*
* 注意:
* 选择一个比较小的文件,不要太大。大文件拷贝看下一个demo
* */
// 1.创建对象
FileInputStream fis = new FileInputStream("D:\\练习\\电赛\\预览效果.mp4");
FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\copy.mp4");
// 2.拷贝
// 核心思想:边读边写
int b;
while ((b = fis.read()) != -1){
fos.write(b);
}
// 3.释放资源
// 规则:先开的最后关闭
fos.close();
fis.close();
}
}
-
package com.str.box.FileIntputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class demo05 { public static void main(String[] args) throws IOException { /* demo03改进版 * 文件拷贝 * 把D:\练习\电赛\预览效果.mp4拷贝到当前模块下 * * 注意: * 选择一个比较小的文件,不要太大。大文件拷贝看下一个demo * */ long start = System.currentTimeMillis(); // 1.创建对象 FileInputStream fis = new FileInputStream("D:\\练习\\电赛\\预览效果.mp4"); FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\copy.mp4"); // 2.拷贝 int len; byte[] bytes = new byte[1024 * 1024 * 5]; while ((len = fis.read(bytes)) != -1){ fos.write(bytes,0,len); } // 3.释放资源 fos.close(); fis.close(); long end = System.currentTimeMillis(); // 拷贝时间 System.out.println(end-start); } }
2.4 IO 流中不同的JDK版本捕获异常的方法
-
-
package com.str.box.FileIntputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; public class demo06 { public static void main(String[] args){ /* * 利用try...catch...finally捕获拷贝文件中代码出现的异常 * */ FileInputStream fis = null; FileOutputStream fos = null; try { // 1.创建对象 fis = new FileInputStream("D:\\练习\\电赛\\预览效果.mp4"); fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\copy.mp4"); // 2.拷贝 int len; byte[] bytes = new byte[1024 * 1024 * 5]; while ((len = fis.read(bytes)) != -1){ fos.write(bytes,0,len); } }catch (IOException e){ e.printStackTrace(); }finally { // 3.释放资源 if (fos != null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
- 接口:AutoCloseable
- 特点:特定情况下,可以自动释放资源
3. 字符集
3.1 字节流读取中文会出现乱码
- 计算机存储:最小存储单元:字节
- 读取数据时未读完整个汉字(字节流一次读取一个字节,汉字在字符集中为三个或者2个字节)
- 编码和解码时的方式不统一
- 字节流读取中文会乱码,但是拷贝的时候为什么不会乱码?(因为没有丢失数据,同时记事本使用同一种字符集)
3.2 ASCII字符集
2.3 GB*字符集
2.4 Unicode 字符集
Unicode : 万国码
研发方 : 统一码联盟(也叫Unicode组织)
总部位置 : 美国加州
研发时间 : 1990年
发布时间 : 1994年发布1.0版本,期间不断添加新的文字
最新的版本是2022年9月13日发布的15.0版本
联盟组成,世界各地主要的电脑制造商、软件开发商、数据库开发商、政府部门、研究机构、国际机构、及个人组成
UTF-8不是一个字符集,是Unicode的一种编码方式。
- Unicode 字符集的 UTF-8 编码格式
- 一个英文占一个字节,二进制第一位是0,转成十进制是正数
- 一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数
2.5 Java中编码和解码的代码实现
-
package com.str.box.Charset; import java.io.UnsupportedEncodingException; import java.util.Arrays; public class demo01 { public static void main(String[] args) throws UnsupportedEncodingException { /* * Java中编码的方法 public byte[] getBytes() 使用默认方式进行编码 public byte[] getBytes(String charsetName) 使用指定方式进行编码 Java中解码的方法 String(byte[] bytes) 使用默认方式进行解码 String(byte[] bytes, string charsetName) 使用指定方式进行解码 * */ // 1.编码 String str = "bala巴拉"; byte[] bytes1 = str.getBytes(); System.out.println(Arrays.toString(bytes1)); byte[] bytes2 = str.getBytes("GBK"); System.out.println(Arrays.toString(bytes2)); // 2.解码 String str2 = new String(bytes1); System.out.println(str2); String str3 = new String(bytes1,"GBK"); System.out.println(str3); } }
4. 字符流
4.1 字符流的概述
4.2 字符流的体系架构
4.3 FileReader
-
package com.str.box.FileReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class demo01 { public static void main(String[] args) throws IOException { // 1.创建对象关联读取本地文件 FileReader fileReader = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt"); // 2.读取数据 read() // 字符流的底层也是字节流,默认一个字节一个字节的读取的,如果遇到中文就会一次读取多个字节; // GBK字符集:一次读取两个字节;UTF_8:一次读取三个字节 /* read的细节 * 1.read():默认也是一个字节一个字节读取的,如果遇到中文就会一次性的读取多个 * 2.在读取之后,read方法的底层还会进行解码并转出十进制 * 最终把这个十进制的数据也表示在字符集上的数字 * 3.想看到中文的汉字,就要把这些十进制数据在进行强转即可。 * */ int ch; while ((ch = fileReader.read())!= -1){ System.out.print((char) ch); } // 3.释放资源 fileReader.close(); } }
-
package com.str.box.FileReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class demo02 { public static void main(String[] args) throws IOException { // 1.创建对象关联读取本地文件 FileReader fileReader = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt"); // 2.读取数据 // read(char):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中 char[] chars = new char[2]; int len; while ((len=fileReader.read(chars)) != -1){ // 把数组中的数据变成字符串在进行打印 System.out.print(new String(chars,0,len)); } } }
4.4 FileWriter
package com.str.box.FileWriter;
import java.io.FileWriter;
import java.io.IOException;
public class demo01 {
public static void main(String[] args) throws IOException {
// 1.构造
FileWriter fileWriter = new FileWriter("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
//fileWriter.write(25105);
//fileWriter.write("白日依山尽,");
char[] chars = {'白','日','依','山','尽'};
fileWriter.write(chars);
fileWriter.close();
}
}
- 内存有缓存区,每次从缓冲区读取数据,增加读取速率。
package com.str.box.FileWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class demo02 {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
fileReader.read(); // 会把文件中的数据放到缓冲区当中
// 清空文件
FileWriter fileWriter = new FileWriter("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt");
// 请问,如果我再次使用fileReader进行读取,会读取到数据嘛?
// 正确答案:会,但是只能读取到缓存区中的数据,文件中剩余的数据无法再次读取。
int ch;
while ((ch = fileReader.read()) != -1){
System.out.println((char) ch);
}
fileWriter.close();
fileReader.close();
}
}
- flush()和close()的区别
5. 字节流和字符流的应用场景
-
package com.str.box.FileWriter; import java.io.*; public class demo03 { public static void main(String[] args) throws IOException { // 拷贝一个文件夹,考虑子文件夹 // 1.创建对象表示数据源 File src = new File("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\src"); // 2.创建对象表示目的地 File dest = new File("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\dest"); // 3.调用方法开始拷贝 copydir(src,dest); } /* * 作用:拷贝文件夹 * 参数一:数据源 * 参数二:目的地 * */ private static void copydir(File src, File dest) throws IOException { dest.mkdir(); // 递归 // 1.进入数据源 File[] files = src.listFiles(); // 2.遍历数组 for (File file : files) { if (file.isFile()){ // 3.判断文件,拷贝,文件开始,文件结束 FileInputStream fis = new FileInputStream(file); FileOutputStream fos = new FileOutputStream(new File(dest,file.getName())); byte[] bytes = new byte[1024]; int len; while ((len = fis.read(bytes)) != -1){ fos.write(bytes,0,len); } fos.close(); fis.close(); }else { // 4.pd文件夹,递归 copydir(file,new File(dest,file.getName())); } } } }
-
文件加密
为了保证文件的安全性,就需要对原始文件进行加密存储,再使用的时候再对其进行解密处理
加密原理:
对原始文件中的每一个字节数据进行更改,然后将更改以后的数据存储到新的文件中
解密原理:
读取加密之后的文件,按照加密的规则反向操作,变成原始文件 -
package com.str.box.FileWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; public class demo04 { public static void main(String[] args) throws IOException { /* * ^ 异或 * 两边相同:false 0 * 两边不同:TRUE 1 * * System.out.println(100^10); // 110 System.out.println(110^10); // 100 * */ /* FileInputStream fis = new FileInputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\1.png"); FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\ency.png"); */ FileInputStream fis = new FileInputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\ency.png"); FileOutputStream fos = new FileOutputStream("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\redu.png"); int b; while ((b= fis.read()) != -1){ fos.write(b^2); } fos.close(); fis.close(); } }
练习:修改文件中的数据
文本文件中有以下的数据 : 2-1-9-4-7-8
将文件中的数据进行排序,变成以下的数据 : 1-2-4-7-8-9
-
package com.str.box.FileWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; public class demo05 { public static void main(String[] args) throws IOException { // 1.读取数据 FileReader reader = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt"); StringBuilder sb = new StringBuilder(); int ch; while ((ch = reader.read()) != -1){ sb.append((char) ch); } reader.close(); System.out.println(sb); // 2.排序 String str = sb.toString(); String[] arrStr = str.split("-"); ArrayList<Integer> list = new ArrayList<>(); for (String s : arrStr) { int i = Integer.parseInt(s); list.add(i); } Collections.sort(list); System.out.println(list); // 3.写入 FileWriter fw = new FileWriter("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt"); for (int i = 0; i < list.size(); i++) { if (i == list.size()-1){ fw.write(list.get(i)+""); }else { fw.write(list.get(i)+"-"); } } fw.close(); } }
-
改进版:
package com.str.box.FileWriter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Arrays; import java.util.stream.Stream; public class demo06 { public static void main(String[] args) throws IOException { // 1.读取数据 FileReader fr = new FileReader("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt"); StringBuilder sb = new StringBuilder(); int ch; while ((ch = fr.read()) != -1){ sb.append((char) ch); } fr.close(); System.out.println(sb); // 2.排序 Integer[] arr = Arrays.stream(sb.toString() .split("-")) .map(Integer::parseInt) .sorted(). toArray(Integer[]::new); System.out.println(Arrays.toString(arr)); // 3.写入 FileWriter fw = new FileWriter("D:\\笔记\\Java笔记\\JavaSE\\IO流\\ByteStreamDemo01\\a.txt"); String s = Arrays.toString(arr).replace(",","-"); String result = s.substring(1,s.length()-1); fw.write(result); fw.close(); } }