IO流
IO流;存储和读取数据的解决方案。
纯文本文件:Windows自带的记事本打开能读懂的文件,word和Excel不是纯文本文件,txt和md是纯文本文件。
小结
IO流体系
FileOutputStream
public class Demo1 {public static void main(String[] args) throws IOException {//创建对象FileOutputStream fos = new FileOutputStream("javaseday28Io\\a.txt");//传输数据(字节),根据asicii码为 afos.write(97);//关闭资源fos.close();}
}
a
FileOutputStream细节
FileOutputStream写数据的3种方式
public class Demo2 {public static void main(String[] args) throws IOException {//创建对象FileOutputStream fos = new FileOutputStream("javaseday28Io\\a.txt");//传输数据(字节),根据asicii码为 a
// fos.write(97);//传输byte数组byte[] bytes = {97,98,99,100,101,102};
// fos.write(bytes);fos.write(bytes,1,3);/*** 参数一:要写入的数组* 参数二:写入的起始索引* 参数三:写入的个数*///关闭资源fos.close();}
}
换行和续写
public class Demo3 {public static void main(String[] args) throws IOException {/*** 不同的操作系统的换行符号不同* windos \r\n*linux \n* mac \r*//*** 续写 在创建FileOutputStream对象时调用不用的构造方法即可* FileOutputStream fos = new FileOutputStream("javaseday28Io\\a.txt",true);即为保存数据的续写*///创建对象FileOutputStream fos = new FileOutputStream("javaseday28Io\\a.txt",true);//传输数据(字节),根据asicii码为 a//换行和续写//换行String s1 = "duzhelaiyizhengshui";byte[] bytes1 = s1.getBytes();fos.write(bytes1);//将换行符号使用字符串表示并写入String s2 = "\r\n";byte[] bytes2 = s2.getBytes();fos.write(bytes2);String s3 = "666";byte[] bytes3 = s3.getBytes();fos.write(bytes3);//关闭资源fos.close();}
}
FileOutputStream的小结
FileInputStream
public class Demo1 {public static void main(String[] args) throws IOException {/*** 如果读取到空值则返回-1*/FileInputStream fos = new FileInputStream("javaseday28Io\\a.txt");int r1 = fos.read();System.out.println((char) r1);int r2 = fos.read();System.out.println((char) r2);int r3 = fos.read();System.out.println((char) r3);int r4= fos.read();System.out.println((char) r4);int r5 = fos.read();System.out.println((char) r5);int r6 = fos.read();//-1System.out.println(r6);fos.close();}
}
细节
FileInputStream的循环读取
public class Demo2 {public static void main(String[] args) throws IOException {/*** 如果读取到空值则返回-1*/FileInputStream fos = new FileInputStream("javaseday28Io\\a.txt");int r1;while ((r1 = fos.read()) != -1){System.out.println((char)r1);}fos.close();}
}
FileInputStream的拷贝文件
public class Demo3 {public static void main(String[] args) throws IOException {/*** 如果读取到空值则返回-1*/FileInputStream fis = new FileInputStream("C:\\Users\\20724\\Desktop\\123.jpg");FileOutputStream fos = new FileOutputStream("javaseday28Io\\123.jpg");int r1;//将读取到的信息写入目标文件while ((r1 = fis.read()) != -1){fos.write(r1);}//关闭资源fos.close();fis.close();}
}
文件拷贝的弊端和解决方法
文件拷贝单个字符拷贝较慢,可以使用数组进行拷贝。
public class Demo4 {public static void main(String[] args) throws IOException {/*** 如果读取到空值则返回-1*/FileInputStream fis = new FileInputStream("C:\\Users\\20724\\Desktop\\123.jpg");FileOutputStream fos = new FileOutputStream("javaseday28Io\\123.jpg");//创建一个5MB的数组存储数据byte[] bytes = new byte[1024*1024*5];//记录每次数组中写入的数据的长度,一遍输出的时候知道输出几个字符int len;//将读取到的信息写入目标文件//将数据读取到数组是是将读取的字符覆盖数组中已有的字符,如果没有被覆盖到就会保留while ((len = fis.read(bytes)) != -1){//由于没有被覆盖到就会保留,所以向文件写入时要根据读取数据的长度写入fos.write(bytes,0,len);}//关闭资源fos.close();fis.close();}}
IO流中不同JDK版本捕获异常的方式
基本写法:
public class Demo5 {public static void main(String[] args) throws IOException {/*** 如果读取到空值则返回-1*/long start = System.currentTimeMillis();//由于代码块中的变量只能在本块中访问,为了在final中关闭流因此定义在外面。//定义之后不赋值会出现未初始化错误所以赋值为nullFileInputStream fis = null;FileOutputStream fos = null;try {fis = new FileInputStream("C:\\Users\\20724\\Desktop\\123.jpg");fos = new FileOutputStream("javaseday28Io\\123.jpg");byte[] bytes = new byte[1024*1024*5];int len;while ((len = fis.read(bytes)) != -1){fos.write(bytes,0,len);}} catch (IOException e) {throw new RuntimeException(e);} finally {//关闭资源//判断是否为空,即是否成功创建了流对象if (fos != null){//捕获关闭流时的异常try {fos.close();} catch (IOException e) {throw new RuntimeException(e);}}//判断是否为空,即是否成功创建了流对象if (fis != null){//捕获关闭流时的异常try {fis.close();} catch (IOException e) {throw new RuntimeException(e);}}}long end = System.currentTimeMillis();System.out.println((end-start)/1000.0);}
}
public class Demo6 {public static void main(String[] args) throws IOException {/*** 如果读取到空值则返回-1*//*** JDK7 的写法* 不需要关闭流*/try(FileInputStream fis = new FileInputStream("C:\\Users\\20724\\Desktop\\123.jpg");FileOutputStream fos = new FileOutputStream("javaseday28Io\\123.jpg")) {byte[] bytes = new byte[1024*1024*5];int len;while ((len = fis.read(bytes)) != -1){fos.write(bytes,0,len);}} catch (IOException e) {throw new RuntimeException(e);}}
}
public class Demo7 {public static void main(String[] args) throws IOException {/*** 如果读取到空值则返回-1*//*** JDK9 的写法* 不需要关闭流*/FileInputStream fis = new FileInputStream("C:\\Users\\20724\\Desktop\\123.jpg");FileOutputStream fos = new FileOutputStream("javaseday28Io\\123.jpg");try(fis;fos) {byte[] bytes = new byte[1024*1024*5];int len;while ((len = fis.read(bytes)) != -1){fos.write(bytes,0,len);}} catch (IOException e) {throw new RuntimeException(e);}}
}
字符集
ASCII
GBK
小结
Unicode
小结
出现乱码的原因
扩展
java中的编码和解码
public class Demo1 {public static void main(String[] args) throws UnsupportedEncodingException {String str = "hao读者";//使用默认编码方法即utf8byte[] bytes1 = str.getBytes();System.out.println(Arrays.toString(bytes1));//[104, 97, 111, -24, -81, -69, -24, -128, -123]//使用GBK编码byte[] bytes2 = str.getBytes("GBK");System.out.println(Arrays.toString(bytes2));//[104, 97, 111, -74, -63, -43, -33]//解码String s2 = new String(bytes1);System.out.println(s2);//hao读者//使用错误的解码方式String s3 = new String(bytes1,"GBK");System.out.println(s3);//出现乱码 hao璇昏��String s4 = new String(bytes2,"GBK");System.out.println(s4);//hao读者}
}
字符流
FileReader
public static void main(String[] args) throws IOException {/*第一步:创建对象public FileReader(File file) 创建字符输入流关联本地文件public FileReader(String pathname) 创建字符输入流关联本地文件第二步:读取数据public int read() 读取数据,读到末尾返回-1public int read(char[] buffer) 读取多个数据,读到末尾返回-1第三步:释放资源public void close() 释放资源/关流*///1.创建对象并关联本地文件FileReader fr = new FileReader("myio\\a.txt");//2.读取数据 read()//字符流的底层也是字节流,默认也是一个字节一个字节的读取的。//如果遇到中文就会一次读取多个,GBK一次读两个字节,UTF-8一次读三个字节//read()细节://1.read():默认也是一个字节一个字节的读取的,如果遇到中文就会一次读取多个//2.在读取之后,方法的底层还会进行解码并转成十进制。// 最终把这个十进制作为返回值// 这个十进制的数据也表示在字符集上的数字// 英文:文件里面二进制数据 0110 0001// read方法进行读取,解码并转成十进制97// 中文:文件里面的二进制数据 11100110 10110001 10001001// read方法进行读取,解码并转成十进制27721// 我想看到中文汉字,就是把这些十进制数据,再进行强转就可以了int ch;while((ch = fr.read()) != -1){System.out.print((char)ch);}//3.释放资源fr.close();}
带参数的Reader方法
public static void main(String[] args) throws IOException {/*第一步:创建对象public FileReader(File file) 创建字符输入流关联本地文件public FileReader(String pathname) 创建字符输入流关联本地文件第二步:读取数据public int read() 读取数据,读到末尾返回-1public int read(char[] buffer) 读取多个数据,读到末尾返回-1第三步:释放资源public void close() 释放资源/关流*///1.创建对象FileReader fr = new FileReader("myio\\a.txt");//2.读取数据char[] chars = new char[2];int len;//read(chars):读取数据,解码,强转三步合并了,把强转之后的字符放到数组当中//空参的read + 强转类型转换while((len = fr.read(chars)) != -1){//把数组中的数据变成字符串再进行打印System.out.print(new String(chars,0,len));}//3.释放资源fr.close();}
FileWriter
构造方法
成员方法
书写细节
public static void main(String[] args) throws IOException {//保存文件中的数据FileWriter fw = new FileWriter("javaseday28Io\\a.txt",true);// fw.write(97);String st = "asd哈哈哈";
// fw.write(st);
// fw.write(st,2,4);char[] chars = {'a','c','b','你','好'};
// fw.write(chars);fw.write(chars,1,4);fw.close();}
字符流的原理解析
输入流解析
public static void main(String[] args) throws IOException {FileReader fr = new FileReader("myio\\b.txt");fr.read();//会把文件中的数据放到缓冲区当中//清空文件FileWriter fw = new FileWriter("myio\\b.txt");//请问,如果我再次使用fr进行读取//会读取到数据吗?//会把缓冲区中的数据全部读取完毕//正确答案://但是只能读取缓冲区中的数据,文件中剩余的数据无法再次读取int ch;while((ch = fr.read()) != -1){System.out.println((char)ch);}fw.close();fr.close();}
输出流解析
flush和close方法
public static void main(String[] args) throws IOException {FileWriter fw = new FileWriter("myio\\a.txt");fw.write("我的同学各个都很厉害");fw.write("说话声音很好听");fw.flush();fw.write("都是人才");fw.write("超爱这里哟");fw.close();fw.write("B站");}
使用场景
综合练习
练习一:拷贝
public class Test {public static void main(String[] args) throws IOException {/*** 拷贝文件*///目标文件夹File f1 = new File("C:\\Users\\20724\\Desktop\\FileTest");File f2= new File("C:\\Users\\20724\\Desktop\\123");copyfile(f1,f2);}//复制方法private static void copyfile(File f1, File f2) throws IOException {//创建文件夹防止无法存放文件f2.mkdir();//使用递归的方法//遍历数组//判断File[] files = f1.listFiles();for (File file : files) {if (file.isFile()){FileInputStream fis = new FileInputStream(file);FileOutputStream fos = new FileOutputStream(new File(f2,file.getName()));int len;byte[] bytes = new byte[1024];while ((len = fis.read(bytes)) != -1){fos.write(bytes,0,len);}fos.close();fis.close();}else {//为文件夹进行递归copyfile(file,new File(f2,file.getName()));}}}
}
练习二:文件加密
public class Test {public static void main(String[] args) throws IOException {//文件加密,解密都可以使用只需要修改输入文件和输出文件FileInputStream fis = new FileInputStream("javaseday28Io\\cnpy.jpg");FileOutputStream fos = new FileOutputStream("javaseday28Io\\678.jpg");int len;while (( len = fis.read()) != -1){fos.write(len ^ 1920);}fos.close();fis.close();}
}
练习三:修改文件数据
方法一:
public class Test1 {public static void main(String[] args) throws IOException {//普通方法写//获取文件,读取数据FileReader fr = new FileReader("javaseday28Io\\a.txt");//接受数据StringBuilder sb = new StringBuilder();int len;while ((len = fr.read()) != -1){sb.append((char)len);}fr.close();String string = sb.toString();System.out.println();//修改数据//读去数据ArrayList<Integer> list = new ArrayList<>();String[] split = string.split("-");for (String s : split) {list.add(Integer.parseInt(s));}//修改数据Collections.sort(list);//写入数据//获取写入文件的地址FileWriter fw = new FileWriter("javaseday28Io\\b.txt");for (int i = 0; i < list.size(); i++) {if (i!=list.size()-1){fw.write(list.get(i)+"");fw.write("-");}else {fw.write(list.get(i)+"");}}fw.close();}
}
方法二:
public class Test2 {public static void main(String[] args) throws IOException {//普通方法写//获取文件,读取数据FileReader fr = new FileReader("javaseday28Io\\a.txt");//接受数据StringBuilder sb = new StringBuilder();int len;while ((len = fr.read()) != -1){sb.append((char)len);}fr.close();//修改数据//读去数据//使用Stream流进行操作Integer[] array = Arrays.stream(sb.toString().split("-"))//.map(new Function<String, Integer>() {// @Override// public Integer apply(String s) {// return Integer.parseInt(s);// }// })//将String类型转换为Int类型,Map进行类型转换.map(Integer::parseInt).sorted().toArray(Integer[]::new);//写入数据//获取写入文件的地址FileWriter fw = new FileWriter("javaseday28Io\\b.txt");//将 , 的间隔符装换位 - 的间隔符String s = Arrays.toString(array).replace(", ","-");//将头尾的中括号剪裁掉String res = s.substring(1, s.length() - 1);fw.write(res);fw.close();}
}