IO流就是存储和读取数据的解决方案
I:input O:output 流:像水流一样传输数据
作用:用于读写数据(本地文件,网络)
分类:
何为纯文本文件
用windows系统自带的记事本打开并且能够读懂的文件
1.FileOutputStream
操作本地文件的字节输出流,可以把程序中的数据写到本地文件中
书写步骤:1.创建字节输出流对象 2.写数据 3.释放资源
package IO;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo1 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileOutputStream fileOutputStream=new FileOutputStream("..\\JavaSE\\a.txt");
//2.写出数据
fileOutputStream.write(97);//输出a
//3.释放资源
fileOutputStream.close();
}
}
细节:
创建对象
1.参数时字符串表示的路径或者时file对象都是可以的
2.如果文件不存在会创建一个新的文件,目录要保证父路径是存在的
3.如果文件已经存在,则会清空文件
4.续写,在对象后面添加一个true,开关默认为false关闭状态。
写数据
1.write方法的参数时整数,但是实际上写到本机文件的参数在ASCII上对应的字符
释放资源
每次使用完流之后都要释放资源。原因:解除资源的占用
1.1写的3种数据方式
package IO;
import java.io.FileOutputStream;
import java.io.IOException;
public class demo3 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileOutputStream fileOutputStream=new FileOutputStream("..\\JavaSE\\a.txt",true);
//换行
String s="\r\n";//换行的意思
byte[] bytes = s.getBytes();
fileOutputStream.write(bytes);
String str="dsaads";
byte[] bytes1 = str.getBytes();
fileOutputStream.write(bytes1);
String s1="\r\n";//换行的意思
byte[] bytess = s1.getBytes();
fileOutputStream.write(bytess);
String str1="11sadas1";
byte[] bytes2= str1.getBytes();
fileOutputStream.write(bytes2);
//续写
//3.释放资源
fileOutputStream.close();
}
}
2.FileInputStream
操作本地文件的字节输入流,可以把本地文件中的数据读取到程序中来。
步骤:1.创建字节输入流对象 2.读数据 3.释放资源
package IO.FileInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class inputDemo1 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileInputStream fileInputStream=new FileInputStream("..\\JavaSE\\a.txt");
//2.读取数据
for (int i = 0; i < 10; i++) {
int b = fileInputStream.read();
System.out.println((char) b);
}
//3.释放资源
fileInputStream.close();;
}
}
细节:
1.如果文件不存在,直接报错
2.一次读一个字节,读出来的数据在ASCII上对应的数字
3.读到文件末尾了,read方法返回-1.
2.1循环读取
package IO.FileInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class inputDemo1 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileInputStream fileInputStream = new FileInputStream("..\\JavaSE\\a.txt");
//2.读取数据
int b;
while ((b = fileInputStream.read()) != -1) {
System.out.print((char) b);
}
//3.释放资源
fileInputStream.close();
;
}
}
练习1:文件拷贝
package IO.FileInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class inputDemo2 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileInputStream fileInputStream=new FileInputStream("..\\JavaSE\\a.txt");
FileOutputStream fileOutputStream=new FileOutputStream("..\\JavaSE\\cope.txt");
//拷贝
//边读边写
long l = System.currentTimeMillis();
int b;
byte[]bytes=new byte[1024*1024*5];
while ((b=fileInputStream.read(bytes))!=-1){
fileOutputStream.write(bytes,0,b);
}
fileOutputStream.close();
fileInputStream.close();
long end= System.currentTimeMillis();
System.out.println(end-l);
}
}
读取问题:
IO流:如果拷贝的文件过大,速度会很慢
原因:FileInputStream一次读写一个字节
2.2一次读取多个字节
一个读一个字节数组的数据,每次读取尽可能把数组装满
package IO.FileInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class inputDemo3 {
public static void main(String[] args) throws IOException {
//1.创建对象
FileInputStream fileInputStream=new FileInputStream("..\\JavaSE\\a.txt");
byte[]bytes=new byte[2];//一次读取两个字节
int r = fileInputStream.read(bytes);
System.out.println(r);
String str=new String(bytes,0,1);
System.out.println(str);
int r1 = fileInputStream.read(bytes);
System.out.println(r1);
String str2=new String(bytes,0,2);
System.out.println(str2);
int r2 = fileInputStream.read(bytes);
System.out.println(r2);
String str3=new String(bytes,0,3);
System.out.println(str3);
fileInputStream.close();
}
}
2.3异常处理
finally:里面的代码一定会被执行,除非虚拟机停止
3.字符集
Unicode字符集是UTF-8编码格式
一个英文占一个字节,二进制第一位是0,转成十进制是正数
一个中文占三个字节,二进制第一位是1,第一个字节转成十进制是负数
为什么会有乱码:
1.读取数据时未读完整个汉字
2.编码和解码时的方式不统一
如何不产生乱码:
1.不要用字节流读取文本文件
2.编码解码时使用同一个码表,同一个编码方式
Java中编码的方式
Java中解码的方式
package IO.charset;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.util.Arrays;
public class demo1 {
public static void main(String[] args) throws UnsupportedEncodingException {
//编码
String str="ai积极";
byte[] bytes1 = str.getBytes();
System.out.println(Arrays.toString(bytes1));
byte[] gbks = str.getBytes("GBK");
System.out.println(Arrays.toString(gbks));
//解码
String str2=new String(bytes1);
System.out.println(str2);
String str3=new String(bytes1,"GBK");
System.out.println(str3);
}
}
4.字符流
字符流的底层就是字节流
特点:
输入流:一次读一个字节,遇到中文时,一次读多个字节
输出流:底层会把数据按照指定的编码的编码方式进行编码,变成字节在写到文件中
使用场景:对于纯文本进行读写操作
4.1FileReader
1.创建字符输入流对象
2.读取数据
3.释放资源
4.2FileWiter
构造方法
1.创建字符输出流对象
细节:参数是字符表示的路劲或者file对象都是可以的
细节2:如果文件不存在会创建一个新的文件,但是要保证父级路径是存在的
细节3:如果文件已经存在,则会清空文件,如果不想清空可以打开续写开关
2.写数据
细节:如果writer方法的参数是整数,但是实际上写到本地文件中的是整数在字符集上对应的字符
3.释放资源
练习:加密文件和解密
package IO.MyText;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Text1 {
public static void main(String[] args) throws IOException {
//1.获取文件
FileInputStream fileInputStream=new FileInputStream("..\\JavaSE\\cope.txt");
FileOutputStream fileOutputStream=new FileOutputStream("..\\JavaSE\\copy.txt");
int len;
while ((len=fileInputStream.read())!=-1){
fileOutputStream.write(len^2);
}
fileOutputStream.close();
fileInputStream.close();
}
}
5.高级流
5.1缓冲流
5.1.1字节缓冲流
原理:底层自带了长度为8192的缓冲区提高性能
package IO.MyText;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Text1 {
public static void main(String[] args) throws IOException {
//1.获取文件
FileInputStream fileInputStream=new FileInputStream("..\\JavaSE\\cope.txt");
FileOutputStream fileOutputStream=new FileOutputStream("..\\JavaSE\\copy.txt");
int len;
while ((len=fileInputStream.read())!=-1){
fileOutputStream.write(len^2);
}
fileOutputStream.close();
fileInputStream.close();
}
}
5.1.2字符缓冲流
原理:底层自带了长度为8192的缓冲区提高性能
package IO.MyText;
import java.io.*;
public class Text2 {
public static void main(String[] args) throws IOException {
// //字符输入流
// BufferedReader bufferedReader=new BufferedReader(new FileReader("..\\JavaSE\\a.txt"));
String line=bufferedReader.readLine();
System.out.println(line);
String line1=bufferedReader.readLine();
System.out.println(line1);
//
// String line;
// while((line=bufferedReader.readLine())!=null){
// System.out.println(line);
// }
//
// bufferedReader.close();
//字符输出流
BufferedWriter bufferedWriter=new BufferedWriter(new FileWriter("b.txt" ,true));
bufferedWriter.write("123");
bufferedWriter.newLine();
bufferedWriter.write("2344");
bufferedWriter.newLine();
bufferedWriter.close();
}
}
5.2转换流
字符转换输入流:InputStreamReader
字符转换输出流:OutputStreamWriter
字符流和字节流之间的桥梁
作用1:指定字符集读写
作用2:字节流想要使用字符流中的方法
将文件中的GBK文件转成UTF-8
package IO.convteStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
public class demo3 {
public static void main(String[] args) throws IOException {
FileReader fileReader=new FileReader("..\\JavaSE\\c.txt", Charset.forName("GBK"));
FileWriter fileWriter=new FileWriter("..\\JavaSE\\e.txt",Charset.forName("UTF-8"));
int c;
while ((c=fileReader.read())!=-1){
fileWriter.write(c);
}
fileWriter.close();
fileReader.close();
}
}
利用字节流,一次读取一行,中文不能出现乱码
package IO.convteStream;
import java.io.*;
public class demo4 {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(new FileInputStream("..\\JavaSE\\a.txt")));
String c;
while ((c=bufferedReader.readLine())!=null){
System.out.println(c);
}
bufferedReader.close();
}
}
5.3序列化流
5.3.1对象操作输出流
可以把java中的对象写到本地文件中
细节:使用对象输出流将对象保存到文件时会出现NotSerializableException异常
解决方案:需要让Javabean类实现Serlizable接口
package IO.objeckStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class demo1 {
public static void main(String[] args) throws IOException {
//创建对象
student s=new student("zhangsan",18);
//2.创建序列化流的对象
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("..\\JavaSE\\a.txt"));
oos.writeObject(s);
oos.close();
}
}
package IO.objeckStream;
import java.io.Serializable;
public class student implements Serializable {
private String name;
private int age;
public student() {
}
public student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Serializable接口里面没有抽象方法,是一个标记型接口
实现了这个接口,代表当前的student类可以被序列化流
5.3.2对象操作输入流
可以把序列化搭配本地文件中的对象,读取到程序中来
package IO.objeckStream;
import Fuction.Student;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class demo2 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream oi=new ObjectInputStream(new FileInputStream("..\\JavaSE\\a.txt"));
Student o = (Student) oi.readObject();
System.out.println(o);
oi.close();
}
}
5.4打印流
PrinStream,PrinWriter两个类
特点1:打印流只操作文件目的地,不操作数据源
特点2:特有的写出方法可以实现,数据原样写出 例:打印:97 文件中:97
特点3:特有的写出方法,可以实现自动刷新,自动换行 打印一次数据=写出+换行+刷新
5.4.1字节打印流
字节流底层没有缓冲区,开不开自动刷新都一样
构造方法:
成员方法:
package IO.PrintStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.nio.charset.Charset;
public class demo1 {
public static void main(String[] args) throws FileNotFoundException {
//1.c创建对象
PrintStream ps=new PrintStream(new FileOutputStream("..\\JavaSE\\a.txt"),true, Charset.forName("UTF-8"));
ps.println(97);
ps.printf("%s爱上了%s","阿正","阿强");
ps.close();
}
}
5.4.2字符打印流
字符打印流底层有缓冲区,想要自动刷新需要开启
成员方法:
package IO.PrintStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class demo2 {
public static void main(String[] args) throws IOException {
PrintWriter printWriter=new PrintWriter(new FileWriter("..\\JavaSE\\a.txt"),true);
printWriter.println(999);
printWriter.printf("%s爱上了%s","阿正","阿强");
printWriter.close();
}
}
5.5解压缩流
5.5.1解压缩流
解压的本质:把每一个ZipEntry按照层级拷贝到本地另一个文件夹中
package IO.ZipStream;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class demo1 {
public static void main(String[] args) throws IOException {
//1.创建一个file表示要解压的压缩包
File src=new File("D:\\learn\\JavaSE\\aaa.zip");
//2.创建一个file表示解压的目的地
File dest=new File("D:\\");
upzip(src,dest);
}
//定义一个方法来解压
public static void upzip(File src,File dest) throws IOException {
//创建一个压缩流来读取压缩包中的数据
ZipInputStream zipInputStream=new ZipInputStream(new FileInputStream(src));
//获取压缩包里面的每一个zipentry对象
ZipEntry entry;
while((entry=zipInputStream.getNextEntry())!=null){
System.out.println(entry);
if(entry.isDirectory()){
//文件夹:需要在目的地dest处创建一个同样的文件夹
File file=new File(dest,entry.toString());
file.mkdirs();
}else {
//文件:需要读取到压缩包的文件,并把它存放到目的地dest文件夹中
FileOutputStream fos=new FileOutputStream(new File(dest,entry.toString()));
int b;
while ((b=zipInputStream.read())!=-1){
fos.write(b);
}
fos.close();
zipInputStream.closeEntry();
}
}
}
}
5.5.1压缩流
压缩包里面的每一个文件或者文件夹都是zipentry
压缩的本质:把每一个(文件/文件夹)堪称ZioEntry对象放到压缩包中
package IO.ZipStream;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class demo2 {
public static void main(String[] args) throws IOException {
//1.创建File对象表示要压缩的文件
File src=new File("D:\\learn\\JavaSE\\aaa\\aaa\\aaa.txt");
//2.创建file对象表示要存放的位置
File dest=new File("D:\\");
//3.调用方法来压缩
tozip(src,dest);
}
public static void tozip(File src,File dest) throws IOException {
//1.创建压缩流关联压缩包
ZipOutputStream zos=new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));
//2.创建ZipEntry对象,表示压缩包里面的每一个文件和文件夹
ZipEntry entry=new ZipEntry("a.txt");
//3.把ZipEntry对象放到压缩包当中
zos.putNextEntry(entry);
//4.读写数据
ZipInputStream zis=new ZipInputStream(new FileInputStream(src));
int b;
while ((b=zis.read())!=-1){
zos.write(b);
}
zos.closeEntry();
zos.close();
}
}
6常用的工具
6.1Commons-io
Commons-io是apache开源基金组织提供的一组有关io操作的开源工具包
作用:提高io的开发效率
使用步骤
1.在项目中创建一个文件夹:lib
2.将jar包复制粘贴到lib文件夹
3.右键点击jar包,选择Add as Library->点击ok
4.在类中导包使用
方法:
package IO.Commons;
import org.apache.commons.io.FileUtils;
import java.io.*;
import java.nio.charset.Charset;
public class demo1 {
public static void main(String[] args) throws IOException {
// File src=new File("..\\JavaSE\\txt.txt");
// File dest=new File("..\\JavaSE\\copy.txt");
// FileUtils.copyFile(src,dest);
// File src=new File("D:\\learn\\JavaSE\\aaa");
// File des=new File("D:\\bbb");
// FileUtils.copyDirectoryToDirectory(src,des);
File src=new File("..\\JavaSE\\txt.txt");
FileUtils.readFileToByteArray(src);
}
}