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码为 a
fos.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();//-1
System.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中关闭流因此定义在外面。
//定义之后不赋值会出现未初始化错误所以赋值为null
FileInputStream 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读者";
//使用默认编码方法即utf8
byte[] 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() 读取数据,读到末尾返回-1
public 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() 读取数据,读到末尾返回-1
public 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();
}
}