核心类,接口
File---------------------------------文件流
InputStream-----------------------字节输入流----字节流可以处理一切,比如文本,音像,图片等
OutputStream---------------------字节输出流
Reader-----------------------------字符输入流----字符流只能处理纯文本,可以转换成字节流,但字节流不一定能转化成字符流,比如音像,图片等
Writer------------------------------字符输出流
Closeable--------------------------关闭流接口----java通知操作系统可以释放资源了
Flushable--------------------------刷新流接口----避免数据驻留在内存中
Serializable------------------------序列化接口
用户的当前目录
System.out.println(System.getProperty("user.dir'));
I/O----java.io
流:是一个抽象,动态的概念,是一连串连续动态的数据集合。
数据源;提供原始数据的原始媒介,常见的:数据库,文件,其他程序,内存,网络链接,I/O设备。
(1).如果对于File对象来说,输入和输出操作只能针对文件,不能针对目录
(2).IO操作不仅仅使针对文件,它可以从网路中输入和输出。。。。
(3).输入:
输出:----参照物使当前程序
例如:
把数据写到文件中:输出操作,把数据从程序中输出到文件
从文件读取数据:输入操作
例如:
服务器发送数据到客户段:
对于服务器来说是输出
对于客户段来说是输入
2.IO分类
(1).方向
输入流和输出流
(2).操作数据单位
字节流和字符流
字节流:以字节为单位byte
字符流:以字符为单位char
字符流:只能用于读/写纯文本数据
纯文本数据:内容全是字符
.txt,.html,.properties等是纯文本文件
.doc,.xls,.ppt都不是
字节流:适应于任何类型文本
如果全是纯文本用字符流快
(3).功能角色不同
节点流和处理流
节点流:和每个节点关联,例如:文件流。。
处理流:在节点流的基础上,加其他的处理功能,加装饰功能的,例如:缓冲流,序列化与反序列化
3.IO流有四大抽象基类/超类/父类
(1).InputStream:字节输入流
(2).OutputStream;字节输出流
(3).Reader:字符输入流
(4).Writer:字符输出流
例如:文件IO流:
(1).FileInputStream:文件字节输入流
(2).FileOutputStream;文件字节输出流
(3).FileReader:文件字符输入流
(4).FileWriter:文件字符输出流
例如:缓冲IO流
(1).BufferedInputStream:字节缓冲输入流
(2).BufferedOutputStream;字节缓冲输出流
(3).BufferedReader:字符缓冲输入流
(4).BufferedWriter:字符缓冲输出流
文件的IO操作
1.读取一个纯文本的文件
步骤:
public class Test{
public void test01(){
//1.创建源
File file = new File("a.txt");
//2.选择流----因为是去读一个纯文本文件,所以选自字符流
FileReader fileReader = new FileReader(file);
//3.操作---读,数据从a.txt中---->fileReader流中---->从流中开始读取
char[] arr = new char[10];
int len = fileReader.read(arr); //将a.txt中的数据读入arr中,返回的是读取的字符个数
System.out.println(new Sstring(arr));
//4.关闭流
fileReader.close();
}
}
2.写一些数据到纯文本文件中
步骤:
public class Test{
public void test01{
//1.创建源
File file = new File("b.txt");
//3.选择流
FileWriter fileWriter = new FileWriter(file);
//3.操作---写,将程序中的数据写入b.txt中
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一句话:");
String str = scanner.nextLine();
char[] ch = str.toCharArray();
fileWriter.write(ch); //将ch中的数据写入到b.txt中
fileWriter.flush(); //刷新
System.out.println(new String(ch));
//4.关闭流
fileWriter.close();
scanner.close();
3.纯文字之间的复制,即将将a.txt中的文件复制到b.txt中
package com.iotest.FileWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* 实现边读边写
*/
public class FileReader_WriterSample2 {
public static void main(String[] args) throws IOException {
String s1 = "a.txt";
String s2 = "b.txt";
FileReader_WriterSample2 fi = new FileReader_WriterSample2();
fi.test(s1, s2);
}
public void test(String srcFileName,String descFileName) throws IOException{
//创建源
File file1 = new File(srcFileName);
File file2 = new File(descFileName);
//选择流
FileReader fr = new FileReader(file1);
//FileWriter fw = new FileWriter(file2); //这样会将b.txt中的原有的资料覆盖
FileWriter fw = new FileWriter(file2, true);
fw.append("\n");
//操作流
char[] ch = new char[(int)file1.length()];
int len;
while ((len = fr.read(ch)) != -1) {
fw.write(ch, 0, len);
fw.flush();
}
//关闭流
fw.close();
fr.close();
}
}
4.使用字节流,来读取文件(非纯文本文件)
package com.iotest.FileInputoutput;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* 测试,边读边写
*
*/
public class FileInput_OutputStreamSample {
public static void main(String[] args) throws IOException {
String s1 = "a.docx";
String s2 = "b.docx";
FileInput_OutputStreamSample fi = new FileInput_OutputStreamSample();
fi.test(s1, s2);
}
public void test(String srcFileName,String descFileName) throws IOException{
//创建源
File file1 = new File(srcFileName);
File file2 = new File(descFileName);
//选择流
InputStream input = new FileInputStream(file1);
OutputStream output = new FileOutputStream(file2);
//操作流
byte[] ch = new byte[(int)file1.length()];
int len;
while ((len = input.read(ch)) != -1) {
output.write(ch, 0, len);
output.flush();
}
//关闭流
output.close();
input.close();
}
}
a.docx中:
纯文字:
“甩锅”大戏正式开始!万茜账号被盗事件,网易已然被动“接锅”
导语:“击鼓传花”开始!万茜账号被盗事件,知乎已成功“甩锅”网易,“甩锅”大戏正式开始!
前两天,万茜点赞宁静和郁可唯“黑评”的事引起了网友的热议。
在这条评论中,宁静被称为爱出风头的娱乐圈“黑洞”,而郁可唯则被称为宁静的“死忠”。
图片:
MP4:
b.docx中
纯文字:
“甩锅”大戏正式开始!万茜账号被盗事件,网易已然被动“接锅”
导语:“击鼓传花”开始!万茜账号被盗事件,知乎已成功“甩锅”网易,“甩锅”大戏正式开始!
前两天,万茜点赞宁静和郁可唯“黑评”的事引起了网友的热议。
在这条评论中,宁静被称为爱出风头的娱乐圈“黑洞”,而郁可唯则被称为宁静的“死忠”。
图片:
MP4:
5.缓冲IO流:
是处理流,负责在其他IO流基础上增加缓冲功能
BufferedReader--->Reader
BufferedWriter---->Writer
BufferedInputStream---->InputStream
BufferedOutputStream--->outputStream
BufferedReader除了继承Reader的那些读的方法,还增加了一个:String readLine()读取一行,这里不会换行
while(str = bi.readLine() != null){
bo.write(str);
}---这里因为readLine不会换行,所以每读取一行的字符会在一起,需要手动加入换行:
1.bo.write(str + "\n");---不建议使用,因为在记事本中打开,不起作用,因为记事本是由C++写的,换行符为\r\n---\r表示本行结束,\n把光标移动到下一行
2.bo.newLine(); ----两种方法
BufferedWriter除了继承Writer的那些写的方法,还增加了一个:String newLine()相当于换行
为什么使用缓冲流可以加快速度?
默认的缓冲大小:8192字节/字符
案例:将A盘下的CentOS-7-x86_64-DVD-1810.iso复制到A盘的1.iso
package com.iotest.buffer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileBufferedInput_OutputStream {
public static void main(String[] args) throws IOException {
String srcFile = "A:\\CentOS-7-x86_64-DVD-1810.iso";
String desFile = "A:\\1.iso";
long start = System.currentTimeMillis();
FileBufferedInput_OutputStream.copy(srcFile, desFile);
long end = System.currentTimeMillis();
System.out.println("运行的时间为:" + (end - start));
}
public static void copy(String srcFile,String desFile) throws IOException{
//1.创建源
File file1 = new File(srcFile);
File file2 = new File(desFile);
//2.选择流
/*
* 这里相当于从file1--->fi--->bi读
*/
FileInputStream fi = new FileInputStream(file1);
BufferedInputStream bi = new BufferedInputStream(fi);
/*
* 这相当于从bo--->fo--->file2写
*/
FileOutputStream fo = new FileOutputStream(file2);
BufferedOutputStream bo = new BufferedOutputStream(fo);
//3.操作流
byte[] bs = new byte[(int)file1.length()];
while (bi.read(bs, 0, bs.length) != -1) {
bo.write(bs);
bo.flush();
}
//4.关闭流
/*
* 这里关闭流是有次序的
*/
bi.close();
fi.close();
bo.close();
fo.close();
}
}
6.转换流---InputStreamReader和OutputStreamWriter
1.在字符串中的解码和编码
字符-----字节:编码
字节-----字符:解码
编码:字符串---字节
public class A{
public static void main(String[] args){
String str = "性命生命使命a";
//编码
byte[] byte = str.gteBytes();
System.out.println(byte.length); //19,因为是默认的字符集为utf-8,每一个汉字占三个字节,一个字母占1个字节
byte[] byte = str.getBytes("UTF-16LE);
System.out.println(byte.length); //14,因为UTF-16LE 汉字占2个字节,字母占2个字节
byte[] byte = str.getBytes("gbk")
System.out.println(byte.length); //13,因为gbk汉字占2个字节,字母占1个字节
解码:字节---字符串
str = new String(byte,0,byte.length,"utf-8");
System.out.println(str.toString);
乱码问题:
1.字节数不够
str = new String(byte,0,byte.length -3,"utf-8");
System.out.println(str.toString);
2.字符集不统一
str = new String(byte,0,byte.length,"gbk"); //eclipse中默认的字符集为utf-8,现在传进来的字符集为gbk
System.out.println(str.toString);
2.解码:字节输入流转换为字符输入流
InputStreamReader:把字节转换为字符,同时还能指定编码方式
案例:
FileInputStream fi = new FileInputStream("d:/io.txt");
//将fi中的字节流按照GBK进行解码为字符流
InputStreamReader fis = new InputStreamReader(fi,"GBK");
//解绑:d:/io.txt(GBK)-->fi(纯字节)-->fis(GBK)解成字符流--->按字符读取
char[] ch = new Char[3];
int len = fis.read(ch);
System.out.println(new String(ch,0,len));
//关闭流
fis.close();
fi.close();
3.编码:字符--->字节,把字符流转换为字节流
OutputStreamWriter:把字符流转为字节流,并且可以指定编码
案例:
String str = "和附近的哈哈飞机获得加分加分";
FileOutputStream fo = new FileOutputStream("d:/io.txt");
OutputStreamWriter fos = new OutputStreamWriter(fo,"GBK");
//数据:str(字符)-->fos(字符)按照GBK编码为字节流--->fos--->io.txt
fos.writer(str);
//关闭流
fos.close();
fo.close();
7字节数组流---ByteArrayInputStream和ByteArrayOutputStream
package com.iotest.bytearray;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.channels.NonWritableChannelException;
/*
* 实现ByteArrayInputStream
* 实现ByteArrayOutputStream
* A ByteArrayInputSteam包含一个内部缓冲区,其中包含可以从流中读取的字节。
* 关闭一个ByteArrayInputStream没有效果
* 1.相当于操作的是内存中的数据
2.不用手动释放,垃圾回收器回收
3.任何东西都可以转成字节数组,方便在网络上进行传输
4.不建议数据量过大
*/
public class ByteArrayInput_OutputStream {
public static void main(String[] args) {
ByteArrayInput_OutputStream byteArray = new ByteArrayInput_OutputStream();
byteArray.ByteArrayInputStreamSample("files//a.txt");
byteArray.ByteArrayOutputStreamSample();
}
public void ByteArrayInputStreamSample(String str){
//创建源
File file = new File(str);
byte[] ch = new byte[(int) file.length()];
InputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
try {
inputStream.read(ch);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
byte[] bs = new String(ch).getBytes();
//选择流
ByteArrayInputStream byteArray = new ByteArrayInputStream(bs); //使用bs作为其缓冲区数组
try {
byteArray.read(bs);
String string = new String(bs);
System.out.println(string);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void ByteArrayOutputStreamSample(){
//创建源
byte[] bs = "\n放假回家哈十分巨大的JFK接口对接".getBytes();
//选择流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
//操作流
try {
outputStream.write(bs);
outputStream.flush(); //刷新
String string = new String(outputStream.toByteArray());
System.out.println(string);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
8.数据IO流---DataInputStream和DataOutputStream
package com.iotest.data;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
* 程序中有这样一组数据:
* int num = 10;
* char c = '好';
* double d = 88.88;
* String info = "尚硅谷真好!";
* boolean good = true;
* 程序运行过程中,想要临时退出,下次希望从这个状态继续恢复执行。
* 希望Java能够输出各种数据类型的数据,读取时,能还原各种数据类型的数据。
* 因为这些数据不是纯文本,那么只能选择字节流。
* java中IO流的类的体系设计,隐含了一个设计模式:装饰着设计模式
* DataOutputStream在OutputStream的基础上,增加了很多方法:
* writeXxx()...
* DataOutputStream在InputStream的基础上,增加了喝多方法;
* Xxx readXxx()...
* 要求:
* 用DataOutputStream写的文件或数据,得用DataInputStream来读取。
* 并且要求读的顺序和写的顺序一致
*/
public class DataInput_OutputStream {
/*
* 文件a.dat中的数据为:
* int num = 10;
char c = '好';
double d = 188.88;
String info = "尚硅谷真好!";
boolean good = true;
*/
public static void main(String[] args) throws IOException {
String desFile = "abc.txt";
DataInput_OutputStream.dataWriter(desFile);
}
public static void dataWriter(String desFile) throws IOException{
int num = 10;
char c = '好';
double d = 188.88;
String info = "尚硅谷真好!";
boolean good = true;
//1.创建源
File file2 = new File(desFile);
//2.选择流
/*
* dop--->fo--->file2
*/
FileOutputStream fo = new FileOutputStream(file2);
DataOutputStream dop = new DataOutputStream(fo);
//3.操作流
/*
* 将上面的数据写入desFile文件中
*/
dop.writeInt(num);
dop.writeChar(c);
dop.writeDouble(d);
dop.writeUTF(info);
dop.writeBoolean(good);
//关闭流
dop.close();
fo.close();
}
}
8.对象的序列化和反序列化----ObjectInputStream和ObjectOutputStream
user类
package com.iotest.object;
import java.io.Serializable;
public class User implements Serializable{
private int id;
private String name;
private String password;
public User(int id,String name,String password){
this.id = id;
this.name = name;
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
对象序列化和反序列化类
/*
* 序列:排队,
* 把对象转为字节序列,序列化的过程
什么是序列化
序列化是对象进行持久化处理,也就是说,将对象转化成一个字节流进行存储(比如存储为一个字节文件)或传输(通过网络传输字节)。同时,我们也可以从字节中反序列化一个对象出来。这是Java程序中一个重要的概念,因为网络应用中通常需要将对象序列化成字节传输。每一个需要序列化的对象,都要实现 Serializable 接口
*
* ObjectOutputStream:用于输出对象,把对象转成字节数据输出,对象的输出过程称为序列化。
* ObjectOutputStream比OutputStream多了很多方法,其中一个是 writeObject(obj)
*
* 只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
writeObject 方法用于将对象写入流中。所有对象(包括 String 和数组)都可以通过 writeObject 写入。可将多个对象或基元写入流中。必须使用与写入对象时相同的类型和顺序从相应 ObjectInputstream 中读回对象。
在d.txt中存储的数据:
*
*
* ObjectInputstream:用于输入对象,把字节序列转为对象读取,对象的读取过程称为反序列化。
* ObjectInputstream比InputStream多了很多方法,其中一个是 Object readObject()
*/
package com.iotest.object;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class ObjectInput_OutputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInput_OutputStream object = new ObjectInput_OutputStream();
String desFile = "d.txt";
object.objectOutputStreamTest(desFile);
String srcFile = "d.txt";
object.objectInputStreamTest(srcFile);
}
public void objectOutputStreamTest(String desFile) throws IOException{
User user = new User(2, "张三", "123456");
//1.创建源
File file = new File(desFile);
//2.选择流
/*
* 程序--->obj---->fi---->file
*/
FileOutputStream fi = new FileOutputStream(file);
ObjectOutputStream obj = new ObjectOutputStream(fi);
//操作流
/*这里会报错:
即,没有实现序列化接口的类都不能序列化,解决方法:
obj.writeObject(user);
//关闭流
obj.close();
fi.close();
}
public void objectInputStreamTest(String srcFile) throws ClassNotFoundException, IOException{
//创建源
File file = new File(srcFile);
//选择流
FileInputStream fi = new FileInputStream(file);
ObjectInputStream obj = new ObjectInputStream(fi);
//操作流
/*
这里会报:ClassNotFoundException
* 把字节流中的数据,转为一个对象,读取过程中会创建对象,new对象时需要找对象的类型
User user = (User)obj.readObject();
System.out.println(user.getPassword());
//关闭流
obj.close();
fi.close();
}
}
注意:这里需要注意序列化本版ID:
1.在user类中增加一个属性:---address
2.在ObjectInput_OutputStream中:
3.报错:
报这个错的原因是:流中关于类的serialVersionUID与本地类的serialVersionUID对不上,就会报InvalidClassException错误,
* 如何解决?
* (1)修改本地的serialVersionUID为流中的serialVersionUID
运行之后,不再报错
* (2)或者,在当初实现Serializable接口时,就固定一个serialVersionUID,这样每次编译就不会自动生成一个新的serialVersionUID
当没有固定序列版本id时,user类会有警告
解决方式:
---这里个1可以是任意数字
注意:对象中的有些属性不需要序列化
1.加入了transient 关键字的属性
Goods类---商品类
package com.iotest.object;
import java.io.Serializable;
public class Goods implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private float price; //价格
private transient int sales; //销售量
public Goods(String name,float price,int sales){
this.name = name;
this.price = price;
this.sales = sales;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public int getSales() {
return sales;
}
public void setSales(int sales) {
this.sales = sales;
}
@Override
public String toString() {
return "Goods [name=" + name + ", price=" + price + ", sales=" + sales + "]";
}
}
GoodObjectInput_OutputStream类
package com.iotest.object;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class GoodObjectInput_OutputStream {
public static void main(String[] args) throws IOException, ClassNotFoundException {
GoodObjectInput_OutputStream good = new GoodObjectInput_OutputStream();
String desFile = "e.txt";
String srcFile = "e.txt";
good.goodsOutputStream(desFile);
good.goodsInputStream(srcFile);
}
public void goodsOutputStream(String desFile) throws IOException{
Goods goods = new Goods("连衣裙",88,100);
//创建源
File file = new File(desFile);
//选择流
FileOutputStream fi = new FileOutputStream(file);
ObjectOutputStream obj = new ObjectOutputStream(fi);
//操作流
obj.writeObject(goods);
//关闭流
obj.close();
fi.close();
}
public void goodsInputStream(String srcFile) throws IOException, ClassNotFoundException{
//创建源
File file = new File(srcFile);
//选择流
FileInputStream fi = new FileInputStream(srcFile);
ObjectInputStream obj = new ObjectInputStream(fi);
//操作流
Goods goods = (Goods)obj.readObject();
System.out.println(goods.toString());
//关闭流
obj.close();
fi.close();
}
}
结果为:
如果想sales中的值不序列化,就是在这个属性中加入transient关键字
transient:表示sale属性不需要序列化
结果为:
2.加入了static关键字的属性
---加入静态的brand属性
在GoodObjectInput_OutputStream类中:
注意:当将Goods.setBrand("安踏")加入上面的位置时,结果如下:
无论是放在前面还是在后面,结果都一样
这是因为都在同一个机器(而且是同一个进程),因为这个jvm已经把brand加载进来了,所以你获取的是加载好的brand
看下面:
而在Test3类中:
package com.iotest.object;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Test3 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Test3 t = new Test3();
t.goodsInputStream("e.txt");;
}
public void goodsInputStream(String srcFile) throws IOException, ClassNotFoundException{
//创建源
File file = new File(srcFile);
//选择流
FileInputStream fi = new FileInputStream(srcFile);
ObjectInputStream obj = new ObjectInputStream(fi);
//操作流
Goods goods = (Goods)obj.readObject();
System.out.println(goods.toString());
//关闭流
obj.close();
fi.close();
}
}
结果为:
----即可知道static修饰的属性,没有被序列化,反证明如下:
1.将brand属性不设置为static
2.在GoodObjectInput_OutputStream类中:
结果为:
3.在Test3类中:
![](https://i-blog.csdnimg.cn/blog_migrate/dc6f3df08f0c83038c0de0830f9dd563.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f2f686d7ea48f44bbecb888d06a76094.png)
![](https://i-blog.csdnimg.cn/blog_migrate/be12ac4b33f185b2e1c10722bf8d95ea.png)