IO流
input输入
output输出
场景1:读写配置文件、日志文件
场景2:客户端与服务端的通讯
场景3:文件上传和下载
io流体系结构
字节流
万能流,适合除纯文本文件外的储存
字符流
纯文本文件
字节流
FileOutputStream字节输出流
构造
FileOutputStream fos=new FileOutputStream("F:\\ceshi\\A.txt");
FileOutputStream fos1=new FileOutputStream(new File("F:\\ceshi\\A.txt"));
fos.write(122);
写数据write
fos.write(int i);
fos.write(byte[]bys);
fos.wirte(byte[]bys,int off,int len);//哪个地方开始,和长度
String.getBytes();//可以将Stirng按照字节的形式写入
细节
如果文件不存在,会自动创建出来,
存在的话,会把之前的内容删除,在进行写入操作
如果不想进行删除可以加个true,就是开启追加写入模式
FileOutputStream fos=new FileOutputStream("F:\\ceshi\\A.txt",true);
关闭
需要进行一下close,否则会占用资源
实际上就是fos.close();
io流处理异常的方式
jdk7
File f1=new File("F:\\ceshi\\A.txt");
FileOutputStream fos=null;
try{
System.out.println(10/0);
fos=new FileOutputStream("F:\\ceshi\\A.txt",true);
fos.write("abc".getBytes());
}
catch(IOException e){
System.out.println(e);
}
finally{
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
jdk8
try(FileOutputStream fos=new FileOutputStream("F:\\ceshi\\A.txt",true)){
fos.write("abc".getBytes());
}catch(IOException E){
E.printStackTrace();
}
try小括号
放在小括号里面的类,需要继承AutoCloseable接口
FileInputStream字节输入流
构造
构造跟那个输入流差不多
FileInputStream fis=new FileInputStream("F:\\ceshi\\A.txt");
//没有找到文件会返回异常
//文件如果不可以访问也会返回异常
//记得把异常抛出
读取数据read
单个字节
int i1=fis.read();
System.out.println(i1);
如果把东西全部读完就会返回-1;
int i;
while((i=fis.read())!=-1){
System.out.print((char)i);
}
多个字节
FileInputStream fis=new FileInputStream("F:\\ceshi\\A.txt");
byte[] b=new byte[2];//准备一个菜篮子,准备装取字节
// 将读到的字节,存入到数组容器当中,并返回读取到的要有效的字节个数
int len=0;
//System.out.println(len);
while((len=fis.read(b))!=-1){
String s=new String(b,0,len);
System.out.println(s);
}
fis.close();
小案例
//将一个东西copy到另外一个文件里面
File now=new File("F:\\ceshi\\B.txt");
now.createNewFile();
//创建输入流对象读取数据
FileInputStream fis=new FileInputStream("F:\\ceshi\\A.txt");
//创建输出流对象关联数据
FileOutputStream fos=new FileOutputStream("F:\\ceshi\\B.txt");
byte[] buf=new byte[1024];
int len;
while((len=fis.read(buf))!=-1){
fos.write(buf,0,len);
}
fos.close();;
fis.close();
字节缓冲流
可以不学,但是一定得会
字节缓冲流在源代码中内置了字节数组,可以提高读写的效率
不具备读写功能,他们只是对普通的流对象进行包装,真正和对象建立关联的,还是普通的流对象
BufferedInputStream字节缓冲输入流
构造
BufferedInputStream(InputStream in);
//抽象类,需要构建他的子类,
案例
//字节缓冲输入流
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("F:\\ceshi\\A.txt"));
//字节缓冲输出流
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("F:\\A.txt",true));
//读写操作
int i;
while((i=bis.read())!=-1){
System.out.println(i);
bos.write(i);
}
bis.close();
bos.close();
好处
速度更快,底层有字节数组8192
所以每一次会直接读取8192个字节,所以比较快
就像上面这个案例,它实际上是直接读取8192个字节
在写出的时候,它实际上是将数组给装满,然后一股脑的数据进行写入,所以效率比较高
在进行关闭及为close的时候,会把剩余的放在里面没有进行的剩余的数据再写入;
案例
普通流单个字节拷贝 361719
普通流+自定义数组拷贝 581
缓冲区单个字节拷贝 2121
缓冲流+自定义数组拷贝 163
164mb
字符类
因为字节流在操作纯文本文件的时候,可能会出现乱码的情况
但是字符流不会,字符流只能操作纯文本文件
因此可以解决汉字类问题/
一个汉字的字节码文件长度为3,可以建立一个长度为3的byte,但是,这样只能够读取到汉字,不能读取其他的,所以也是有问题的,
FileReader字符输入流
用于读取纯文本文件,解决中文乱码问题
使用
单个
FileReader fr = new FileReader("F:\\ceshi\\A.txt");
int i;
while ((i = fr.read()) != -1) {
System.out.print((char) i);
}
fr.close();
多个
FileReader fr = new FileReader("F:\\ceshi\\A.txt");
char []arr = new char[100];
int len ;
while ((len = fr.read(arr)) != -1) {
System.out.print(new String(arr,0,len));
}
fr.close();
字符集
指的是多个字符的集合
比如ASCII字符代码表,但是这些还是不够的
我们主要使用Unicode字符集,国际标准字符集,他将世界各种语言的妹妹个字符定义为唯一的
字符编码
指的是一种映射规则
,根据这个规则可以将某个字符映射到其他形式的数据以便在计算机中存储和传输
GBK:每个中文占用两个字节,英文占一个
Unicode:每个中文占用三个字节:也是目前java正在使用的
UTF-8:使用1-4个字节进行保存
编码与解码
编码:字符转字节
getBytes();
getBytes(String charsetName);
String s="你好,你好";
byte[]arr=s.getBytes();
System.out.println(Arrays.toString(arr));
重点记忆
//重点记忆:中文字符,通常都是负数的字节进行组成的,
//特殊情况:可能会出现正数,但是就是有正数,他的第一个字节也一定是负数
解码:字节转字符
String(byte[] bytes);//按照平台默认的编码方式utf-8
String(byte[] bytes,String charsetName);//后面是自定义的
String s="你好,你好";
byte[]arr=s.getBytes();
System.out.println(Arrays.toString(arr));
String s1=new String(arr);
System.out.println(s1);
//当然,也可以在后面加上个gdk,
//出现乱码的原因大部分是你使用的编译方式不一样,改一下就可以了
FileWriter字符输出流
构造
FileWriter fw=new FileWriter("F:\\ceshi\\A.txt");
FileWriter fw1=new FileWriter(new File("F:\\ceshi\\B.txt"));
成员方法
write(int c);
write(char []cbuf);
write(char []cbuf,int off,int len);
write(String off);
write(String str,int off,int len);
注意事项
字符输出流写出数据,需要用flush或者是close,数据才会写出,
因为它实际上会写入底层的缓冲区的代码!!
区别,flush是刷新,管道没有被关闭掉,仍然可以继续写入数据,但是close关闭之后就是真正进行关闭了
案例
图片文件加密
实际上就是获取之前的图片的字节码文件,进行一些转化之后,在进行写入就可以进行写入
统计每个字节的个数
文件夹的copy
public static void main(String[] args) throws IOException {
File src =new File("F:\\ceshi");
File dest =new File("G:\\");
copyDir(src,dest);
}
public static void copyDir(File src, File dest) throws IOException {
//获取数据,创建文件夹
File newDir=new File(dest,src.getName());
//创建多级文件夹
newDir.mkdirs();
//从数据源中获取数据(File对象);
File[]files=src.listFiles();
for(File file:files){
//判断是否是文件
if(file.isFile()){
//是的话直接拷贝
FileInputStream f1=new FileInputStream(file);
//父级路径,子级路径
FileOutputStream f2=new FileOutputStream(new File(newDir,file.getName()));
int len;
byte[] buf=new byte[1024];
while((len=f1.read(buf))!=-1){
f2.write(buf,0,len);
}
f1.close();
f2.close();
}
else{
copyDir(file,newDir);
//如果是文件夹,递归调用方法
}
}
}
字符缓冲流
注意
缓冲流本事不具备读写功能,只是对普通的流对象进行包装
源代码当中也是内置了8192个数组
构造
BufferedReader br = new BufferedReader(new FileReader(""));
BufferedWriter bw = new BufferedWriter(new FileWriter(""));
使用
int i;
while ((i = br.read()) != -1) {
bw.write((char) i);
}
br.close();
bw.close();
特点
BufferedReader
String readLine();
读入一行字符串,读取到末尾返回Null
String line;
while ((line = br.readLine()) != null) {//不会读取到换行符
System.out.println(line);
}
BufferedWriter
void newLine();//写出换行符,具有跨平台性
案例
注意一点,读取和输出必须注意:
对于输出流out,文件存在会把内容清空
写入对象并且析出
public static void main(String[] args) throws IOException {
ArrayList<Student> students = new ArrayList<Student>();
BufferedWriter f1=new BufferedWriter(new FileWriter("F:\\A.txt"));
Student a1=new Student("张三",12);
Student a2=new Student("里斯",13);
Student a3=new Student("把爱",14);
f1.write(a1.getName()+"-"+ Integer.toString(a1.getAge()));
f1.newLine();
f1.write(a2.getName()+"-"+ Integer.toString(a2.getAge()));
f1.newLine();
f1.write(a3.getName()+"-"+ Integer.toString(a3.getAge()));
f1.close();
BufferedReader f2=new BufferedReader(new FileReader("F:\\A.txt"));
String s;
while((s=f2.readLine())!=null){
String[]st=s.split("-");
students.add(new Student(st[0],Integer.parseInt(st[1])));
}
System.out.println(students);
}
转换流
InputStreamReader
OutputStreamWriter
作用
1.按照指定的字符编码进行读写操作
2.将字节流转化为字符流进行操作
因为有一些流对象并不是我们需要的技术进行创建的
构造加使用
//构造
//可以在后面加上编码
InputStreamReader isr = new InputStreamReader(new FileInputStream("F:\\ceshi\\A.txt"),"gbk");
int i=0;
while((i=isr.read())!=-1){
System.out.print((char)i);
}
isr.close();
字符缓冲流,写入内容的时候,是不需要进行转化的emm,需要转化为字符串,不能直接写入数字
序列化流
在流中,可以以字节的形式直接读入对象;
构造
ObjectInputStream(InputStream in);
ObjectOutputStream(OutputStream out);
成员方法
Object readObject();//反序列化操作
void writeObject();//序列化操作
写入对象,
注意
需要继承Serializable接口;
但是该接口并没有成员方法,因此不要进行重写
注意2
如果,我们将数据进行存入之后,但是我们并没有将数据读出,并且,我们将存入的类进行了一些成员的修改,所以会进行报错
因为在底层的时候,它实际上是是水机生成了了个序列号,在每一类进行修改的时候,该类底层的id就会进行修改,所以就发生了错误
private static final long SerialVersionUID=1L;
加上这个就可以了,实际上就是将底层的uid写死,那么我每一次拿出来的时候实际上就是将这个东西固定了,也就是,每一次都可以吸入了
transient
当在变量前面加上这个,那么该变量就不会参与序列化操作了,就完美了
案例
public class main1 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Student s1=new Student("张三",12);
Student s2=new Student("张2",14);
Student s3=new Student("张3",13);
File x=new File("");
// System.out.println(x);
// x.c
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(x.getAbsolutePath()+"\\A.txt"));
oos.writeObject(s1);
oos.writeObject(s2);
oos.writeObject(s3);
oos.close();
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(x.getAbsolutePath()+"\\A.txt"));
while(true){
try {
Object obj=ois.readObject();
System.out.println(obj);
} catch (Exception e) {
break;
}
}
ois.close();
}
}
当然,写可以直接写入Arraylist集合,那么我们就可以不需要再进行多次操作抛出异常了
当然,是需要进行向下转型的
打印流
打印流可以实现方便、高效的打印数据到文件中去,并且可以指定字符编码,
可以实现打印什么数据就是什么数据
System.out.println();实际上也是打印流的方法
默认指向的是控制台
构造
PrintStream(OutputStream os);
PrintStream(File f);
PrintStream(String filepath);
写出
write();写出一个字节,不建议使用
print();//写出
println();//带有换行的输出
根据编码表进行写出
PrintStream ps=new PrintStream("path","gdk");
如果需要追加写入,那么需要在后面写上(append)true;
PrintWriter
都是一样的
PrintWriter pw=new PrintWriter("path");