IO流:
1.定义:
IO流(input/output):对文件的输入和输出。从内存写入到磁盘就是输出流,从磁盘的文件写入到内存中就是输入流。(以程序为参照物的)
2.File文件的操作
public class FileTest01 {
public static void main(String[] args) {
File file = new File("D:\\yao.txt");
FileTest01 t= new FileTest01();
t.createFile(file);
t.showFileInfo(file);
}
private void showFileInfo(File file) {
System.out.println("得到的绝对路径"+file.getAbsolutePath());
System.out.println("得到的相对路径"+file.getPath());
System.out.println("文件大小"+file.length()+"字节");
System.out.println("文件上级目录"+file.getParent());
}
private void createFile(File file) {
if (!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}else {
System.out.println("该文件已经存在!");
}
}
3.IO流分类:
一种是字节流另一种是字符流:字节流就是以字节(系统最小的存储单位)为单位输入输出流,比如文件、音频、视频等都可以做输入输出,字符流是以字符为为单位输出输入 (abcd 张三)比如文字,中英文等;并且字符流有缓存区,可以一行一行的读取字符,效率也要比字节流更高
4.继承关系图
5.字节流
字节输出流
public class FileOutputTest01 {
public static void main(String[] args) {
//File file = new File("D:/yao.txt");
OutputStream fos = null;
try {
//字节输出流 fos = new FileOutputStream(file,true);
fos = new FileOutputStream("D:/yao.txt", true);
String str = "我是全南昌最帅的程序员";
//字节输出流,需要将字符串打散成字节数组,以字节为单位写入到磁盘文件中
byte[] bytes = str.getBytes();
fos.write(bytes);
System.out.println("写入成功!");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null){
try {//关闭流,销毁资源
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字节输入流
public class FileInputTest01 {
public static void main(String[] args) {
//File file = new File("D:/yao.txt");
FileInputStream fis = null;
try {
//InputStream fis = new FileInputStream (file);
fis = new FileInputStream("D:/yao.txt");
int data;
//fis.read()取到的每一个字节通过AscII转换到的数是0-255之间的整数,没有值就返回-1
while ((data = fis.read()) != -1) {
//(char) data:把十进制的数据转换成对应的字符
//因为中文的字符可能是一个字节,两个字节
//无法判断该字符几个字节,所以字节单位区读取可能会乱码
System.out.println(data);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4、通过字节流实现二进制流
二进制流以二进制为单位,可以实现音频传输
public class DataInputStreamTest {
public static void main(String[] args) {
InputStream fis=null;
OutputStream fos=null;
DataInputStream dis = null;
DataOutputStream dos = null;
try {
fis = new FileInputStream("D:\\leizong.png");
fos = new FileOutputStream("D:\\leizong2.png");
//借助字节输入流创建二进制输入流
dis = new DataInputStream(fis);
//借助字节输入流创建二进制输出流
dos = new DataOutputStream(fos);
int data;
while ((data = fis.read())!=-1){
fos.write(data);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dos!= null){
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dis!= null){
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5.InputStreamReader桥接器
InputStreamReader类是从字节流到字符流的桥接器,他使用指定的字符集编码来读取字节,并将他们解码为字符,它使用的字符集编码可以通过名字指定,或者不指定就是平台的默认字符集
字节流到字符流的桥接过程?
1,计算机存储的单位是字节,如txt文本中有这样的中文字符,但是对计算器而言是以字节来存储的,
2.字节流读取的是单字节读取,但是不同的编码集解码成字符需要不同的字节个数,因此字节流读取字符流回乱码,
3.那么就需要一个流可以把字节流读取的字节流进行缓冲而后在通过字符解码将字符返回,因而形式上看作是字符流
4.InputStreamReader就是这样的作用,从而实现了从字节流到字符流的转换
package stream;
import java.io.*;
public class StreamReaderTest {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//字节流
fis = new FileInputStream("D:\\yao.txt");
//创建字节流到字符流中间的桥接器,用它设置字节流到字符流的编码格式
InputStreamReader is =new InputStreamReader(fis,"UTF-8");
//创建字符流对象
BufferedReader br =new BufferedReader(is);
String line;
while((line = br.readLine())!=null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
6.字符流
因为字节流是以字节为单位进行读写,中文无法判断该字符几个字节,所以以字节为单位去读取中文数据可 能会乱码,所以读写中文的时候建议用字符流,并且字符流可以设置缓存区一行一行的去读取,效率也比字 节流更高
案例1:字符输入流
public class FileReaderDemo {
public static void main(String[] args) {
try {
Reader fr = new FileReader("D:\\yao.txt");
char words[] =new char[1024];
// StringBuffer sb =new StringBuffer();
try {
System.out.println(new String(words,0,fr.read(words)));
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
案例2:通过字符流设置缓存区提高获取效率
public class BufferReaderDemo {
public static void main(String[] args) {
FileReader fr = null;
BufferedReader br =null;
try {
//创建字符流缓存区,把字符一个一个取到后先放到缓存区够一行在去写入到程序里面
fr = new FileReader("D:/yao.txt");
br=new BufferedReader(fr) ;
//通过缓存区取到一行数据
String line = br.readLine();
while (line!=null){
System.out.println(line);
line = br.readLine();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (br!=null){
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
案例3:通过字符输出流设置缓存区输出到文件
public class BufferedWriterDemo {
public static void main(String[] args) {
try {//创建字符输入流
FileWriter fw = new FileWriter(new File("D:/yao.txt"));
//借助字符输出流创建了缓存区
BufferedWriter bw= new BufferedWriter(fw);
bw.write("我的家在东北");
bw.write("松花江上");
bw.newLine();
bw.write("那里有满山遍野");
bw.newLine();
System.out.println("写入成功");
bw.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
7.总结
1.流分两大类,字节流和字符流
2.英文字符、音频、图片、视频等都可以字节为单位读写
3.中文汉字以字节获取会乱码,建议字符流读写
8.序列化
1.序列化的作用
什么是序列化?为什么需要序列化?
java序列化就是指将java对象转换为字节序列的过程,而反序列化则是将字节序列转换成目标对象的过程,我们都知道,在进行浏览器访问的时候,我们看到的文本,图片,音频,视频等都是通过二进制序列传输的,那么要将java对象进行传输的时候,是不是也应该先将对象序列化?答案是肯定的,我们需要先iangjava对象进行序列化过,然后通过网络,IO进行传输,当到达目的地之后,再进行反序列化获取我们需要的java对象,最后完成通信
序列化的作用:
1.将对象转换为字节序列存放在磁盘上进行持久化保存
2.可以通过网络传输
3.注意:我们后期项目中用到的javaBean文件都应该序列化
2.如何实现序列化
实现Serializable接口就能实现序列化,Serializable接口是一个标记接口,不用实现任何方法,一旦实现了此接口,该类的对象就是可序列化的。
案例:
public class Test {
public static void main(String[] args) {
Student student = new Student("狗剩", 21, "男的");
ObjectOutputStream oos = null;
try {
//对象输出流实现序列化,将student对象存储到D:\\student.txt文件中
oos = new ObjectOutputStream(new FileOutputStream("D:\\studnet.txt"));
oos.writeObject(student);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3.如何实现反序列化
反序列化就是将字节码序列转换成java对象的过程
public class Test02 {
public static void main(String[] args) {
try {
//创建对象输入流通过字节输入流将文件序列化的文件以字节为单位获取到对象
ObjectInputStream ojs = new ObjectInputStream(new FileInputStream("D:\\studnet.txt"));
Student student = (Student) ojs.readObject();
System.out.println("姓名:"+student.getName());
System.out.println("年龄:"+student.getAge());
System.out.println("性别:"+student.getGender());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
4.transient关键字
添加了transient关键字的属性不会被序列化。
语法:
private transient String gender;//性别
5.InvalidClassException异常
1.当序列化对象后,Student.class中会存储一个序列号ID并且在序列化的student.txt中也会生成相同的序列号ID,反序列化的时候是通过Student.class的序列号ID区查找student.txt文件中对应的序列号ID,如果ID匹配上就能够反序列化成功,否则就报InvalidClassException异常,如果当序列化成功后修改了Student类中的代码,student.class重新编译后会生成新的序列化ID,那么新的序列化ID和之前存储在Student.txt中序列化不匹配就会报InvalidClassException异常,解决的方式有两种:一种是序列化之后不要去修改Student类,另一种是在序列化类student类中定义private static final long serialVersionUID =12345;常量,因为是常量,那么每次生成的序列号ID都是一样的,因此不会报InvalidClassException错误了