1. 什么是IO?
I:input 输入 通常做读取操作(将不同数据源的数据读入到内存中,也叫读取流)
O:output 输出通常做写入操作(将内存中的数据写入到不同的数据源,也叫写入流)
2. 理解流的概念。
想像一下自来水公司要把水输到用户家里,应该先把自来水公司到用户家里的连接水管建好,再将水输出去。管道里输送的是水,但IO里输送的是字节。
u流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数据源可以是文件,内存,或是网络连接.
u类似的,当程序需要写入数据的时候,就会开启一个通向目的地的流。这时候你就可以想象数据好像在这其中“流”动一样
我们使用JAVA的IO操作,必须要使用java.io里的类,所以在使用之前先要导入这个包
3.了解java.io包下的整体结构层次
按层次高低划分 由低---高
3-1.字节流
•抽象父类是 InputStream 和OutputStream
3-2.字符流
抽象父类是 Reader 和 Writer
3-3.对象流
流的命名很有规律,一般是数据源加上流的名字,如:文件读取流就是FileInputStream,对象流就是ObjectInputStream。
需要注意的是字节流和字符流的区别
3-4..字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串(比如对图片文件的操作就只能用字节流)
3-5.一个字符可以是1个字节,也可以是2个或多个字节 一个字节就是8个位,也就是对同一数据源的操作用字符流可能效率更高
3-6.字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以(使用用字节流来传输字符文件会产生乱码)
注意,不管是哪一种流,在数据传输的底层,还是以字节方式传输。
4、操作流的步骤:
1、 建立流
2、 执行操作
3、 关闭流
5.掌握常用的输入流读取操作方法
– int read() //读取一个字节,返回字节的ASC码
–
int read(char cbuf[]) //读取字节进入chuf字符数组,返回读取的字节数
–
int read(char cbuf[], int offset, int length) //读取字节进入chuf字符数组,返回读取的字节数,offset为数据起始位置,length读入字节长度
–
– int available( );//获得读入流的字节长度
–
– close( );//关闭流
对于读入流,在建立流的时候,要求数据源必须存在。如建一个文件流:
FileInputStream fin = new FileInputStream("c:/2.mp3");
这时候,如果c盘下的2.mp3不存在的话会抛出一个FileNotFoundException异常。表示文件未找到。
6.掌握常用的输出流写入操作方法
– void write(int b)//写入一个字节进输出流。注意int b是这个字节的ASC码。
– void close()//关闭流
– void flush()//刷新流。
对于写入流,在建立流的时候,如果数据源不存在,系统会自动创建。如建立一个写入流。
FileOutputStream fout = new FileOutputStream("c:/2.mp3");
这时候,如果文件c:/2.mp3不存在的话,系统会自动创建一个2.mp3的文件,而不会抛出异常。
在操作写入流时要注意:写入流里的数据必须经过flush刷新或关闭流之后,数据才能写入目标数据源。如果不关闭或刷新流,则可能写不进数据源。如建立了一个文件写入流,如果在写入时不关闭或刷新流,则文件里的内容可能是空的。
7、流的操作
需求:将一个文件复制到另一个文件
代码示例:
public class IOTest {
public static void main(String[] args) {
FileInputStream fin=null;//申明一个读入流对象
FileOutputStream fout=null; //申明一个写入流对象
//注意申明时必须这样写,这是因为在建立流时要抛出一个FileNotFoundException异常,这是编译期异常,必须捕获。如果在try块里申明流对象,那么最后在关闭流时就访问不到了。
try {
//建立读入流,要求c:/2.mp3必须存在,如果不存在,会抛出文件找不到的异常
fin = new FileInputStream("c:/2.mp3");
//建立写入流,如果c:/2.mp3不存在,那么系统会自动创建,不会抛出异常
fout=new FileOutputStream("c:/3t3t.mp3");
} catch (FileNotFoundException e) {//捕捉文件找不到异常,这是编译期异常
e.printStackTrace();
}
try {
// byte[] info=new byte[fin.available()];//建立和读入流一样大小的字节数组
// fin.read(info);//读入流读取文件所有的字节进字节数组。
// fout.write(info);//将字节数组里的数据放入写入流
// int x=0;
// while((x=fin.read())!=-1){//利用读入流读取字节,返回的x为字节的ASC码,当x为-1时,文件读取完毕
// fout.write(x);//将这个字节写入输出流
// }
byte[] info=new byte[512];//创建一个大小为512的字节数组
int x=0;
while((x=fin.read(info))!=-1){//将字节读入到数组中,返回的x表示读入了多少个字节,当x是-1的时候,文件读取完毕
fout.write(info); //将字节数组里的数据放入写入流
}
} catch (IOException e) {//文件操作会抛出IO异常,这是编译期异常,必须捕捉
e.printStackTrace();
}
finally{
try {
fin.close();//关闭读入流
fout.close();//关闭写入流,如果不关闭,则文件可能是空的。
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
8、File类
u提供定位本地文件系统、描述文件和目录的功能
掌据常见的文件操作方法
//文件处理
String getName( ); //获得当前文件对象的文件名,不包括路径
String getParent(); //获得当前文件对象的路径,不包括文件名
String getAbsolutePath();//获得当前文件对象的绝对路径,包括文件名和路径
String renameTo(File newName);//将当前文件重命名,利用这个方法可以实现文件的移动
//文件属性测试
boolean exists( ); //判断当前文件对象对应的文件是否存在
boolean isFile( ); //判断当前文件对象是否是文件
boolean isDirectory( );//判断当前文件对象是否是目录
//文件信息 目录操作
long lastModified( );//返回文件最后修改时间
long length( ); //返回文件长度,即文件有多少个字节
boolean delete( );//删除当前文件对象对应的文件
boolean mkdir( ); //创建当前文件对象对应的目录
String[ ] list( );//返回当前文件对象对应目录所有的文件对应的信息
File[] listFiles();//返回当前文件对象对应目录所有的文件对应的文件对象
9、字符流
我们很多时候操作的对象都是字符和字符串,字符流可以让我们更有效的访问我们所需的字符和字符串,而不用再将字节转化成我们想要的字符串,从而简化我们的操作。
字符流抽象父类是Reader和writer。记的时候注意规律性,
对于字符流,我们需要掌握最常用的BufferedReader和BufferedWriter
字符读入流代码示例:
FileReader read=null;//申明文件字符读入流对象
BufferedReader br=null;//申明缓冲字符读流对象
try {
read=new FileReader("c:/e.txt");//创建文件字符读入流对象
br=new BufferedReader(read);//创建缓冲字符读流对象
String temp=null;//申明字符串临时变量
//循环行读取文件字符串,当临时字符串变量为null时,读取结束
while((temp=br.readLine())!=null){
System.out.println(temp);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
字符写入流代码示例:
//申明字符输出流对象,这个对象介于字符流和字节流之间
OutputStreamWriter fout=null;
BufferedWriter bw=null;//申明缓冲字符输出流对象
try {
fout = new OutputStreamWriter(
new FileOutputStream("c:/e.txt",true));
//创建缓冲字符输出流对象
bw=new BufferedWriter(fout);
bw.write("abc");//向流写入字符
bw.newLine();//换一新行
bw.write("23");
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
bw.close();
fout.close();
} catch (IOException e) {
e.printStackTrace();
}
}
10、对象流
对象序列化:
u所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象
想象一下电脑城买电脑桌,为了方便运输,事先将电脑桌拆成木块,到家里时再进行组装,这时候需要一张图低,告诉我们怎样把木块组装成桌子。
不管是哪一种流,在传输时都是以字节方式进行传输,对象流也不例外,先将对象变成字节以方便传输,到达目地的的时候再还原成对象。这样的话,对象序列化极为重要,利用它可以实现我们把字节以一定的方式重新还原成对象。对于远程对象传输和对象的文件操作都必须将对象序列化。
如何实现序列化:
u所有需要实现对象序列化的对象必须首先实现Serializable接口
代码示例:
public class Logon implements Serializable
在对象序列时,属性的修饰符可以为transient,它表示在对象进行传输时,该属性不做传输
对象流代码示例:
class Test implements Serializable {
transient int age;//transient表示在对象传输时,该属性不被传输
String name;
String sex;
Test(int age, String name, String sex) {
this.age = age;
this.name = name;
this.sex = sex;
}
}
//对象流操作示例:
Test test = new Test(2, "3333", "男");// 创建Test对象
ObjectOutputStream objOut = null;// 申明对象写入流对象
ObjectInputStream objIn = null;// 申明对象读取流对象
try {
objOut = new ObjectOutputStream(new FileOutputStream("c:/obj.txt"));// 创建对象写入流对象
objOut.writeObject(test);// 将对象写入文件
}catch(IOException e){
e.printStackTrace();
}
finally{
try{
objOut.close();
}catch(IOException e){
e.printStackTrace();
}
}
try{
objIn = new ObjectInputStream(new FileInputStream("c:/obj.txt"));// 创建对象读取流对象
Object obj = null;// 申明对象
try {
obj = objIn.readObject();// 从对象读取流对象中获得对象
} catch (ClassNotFoundException e) {
// TODO 自动生成 catch 块
e.printStackTrace();
}
Test temp = (Test) obj;// 将对象强转为Test类型
System.out.println(temp.age);
// 输出姓名,打印"3333"
System.out.println(temp.name);
// 输出性别,打印"男"
System.out.println(temp.sex);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {// 关闭流
try {
objIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}