IO
1.概念
输入:硬盘--->内存 (读)
输出:内存---->硬盘 (写)
有的流是按照字节的方式读取数据,一次读取一个字节Byte,这种流是万能的,什么类型的数据文件都可以读取,包括:文本、图片、声音、视频
有的流是按照字符的方式读取数据,一次读取一个字符,这种流是为了方便读取普通文本文件而存在,只能读取“TXT”,连word都不行
? 类名以Stream结尾是字节流、以Reader/Writer结尾是字符流
java.io.InputStream
java.io.OutputStream
java.io.Reader
java.io.Writer
//全为抽象类
-
所有流都实现了java.io.Closeable接口,都是可以关闭的,都有close()方法,流使用完必须要关闭,以免浪费资源,finally中的close分开抓捕异常,以免其中一个异常导致另一个无法关闭,并且遵循先开后关原则!
-
所有输出流都实现了java.io.Flushable接口,都是可刷新的,都有flush()方法,输出流在最终输出后一定要刷新,将管道清空(把其中剩余未输出的数据强行输出),否则可能导致数据丢失
2.分类
-
文件专属:
FileInputStream FileOutputStream FileReader FileWriter
-
转换流:字节流转换成字符流
InputStreamReader OutputStreamReader
-
缓冲流
BufferedReader BufferedWriter BufferedInputStream BufferedOutputStream
-
数据流专属
DataInputStream DataOutputStream
-
标准输出流
PrintWriter PrintStream
-
对象专属流
ObjectInputStream ObjectOutputStream
3.FileInputStream
public static void main(String[] args) {
FileInputStream fis =null;//外面声明,在finally中才能调用
try {
fis=new FileInputStream("C:\\Users\\Monster y\\Desktop\\movie.txt");
while(true){
int readData= fis.read();//返回字符的ASCII值
if(readData==-1)break;
System.out.println(readData);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fis!=null){//关闭输入流
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
byte[] bytes=new byte[4];
while(true){
int readCount=fis.read(bytes);
System.out.println(readCount);
for (int a:bytes) {
System.out.println(a);
}
if (readCount==-1)break;
}
//当文件中是:abcdef
//第一次读:abcd readCount=4
//第二次读:ef readCount=2 ef会替换掉ab
//第三次读:readCount=-1
其他方法
- int available()返回流当中剩余的没有督导的字节数量
- long skip(long n) 跳过n个字节不读
4.FileOutputStream
public class Demo03 {
public static void main(String[] args) {
FileOutputStream fos =null;//外面声明,在finally中才能调用
try {
fos=new FileOutputStream("C:\\Users\\Monster y\\Desktop\\456.txt",true);
//若文件不存在会自己新建文件
//这里加true表示原文件非空时,在后面追加,没有true则在清空后写入,但一次程序的多次写入不会清空
byte[] bytes={97,98,99,100};
fos.write(bytes);//写出数组
fos.flush();//写完后刷新
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos!=null){//关闭输入流
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
5.FileReader和FileWriter
用法和上面类似,注意数组换成char类型!!!
6.BufferedReader
带有缓冲区的字符输入流,使用这个流时不需要自定义char[]数组/byte[]数组,自带缓冲
public class Demo04 { public static void main(String[] args) throws IOException { FileReader reader= new FileReader("C:\\Users\\Monster y\\Desktop\\456.txt"); BufferedReader bufferedReader=new BufferedReader(reader);//包装流 String s=null; if (((s=bufferedReader.readLine())!=null)) System.out.println(s); bufferedReader.close();//关闭外层流 } }
若当一个流的构造方法需要传进来一个流的时候,传进来的叫节点流,负责外部包装的流叫包装流/处理流
对于包装流,关闭外层流后节点流默认关闭
7.InputStringReader
FileInputStream fileInputStream=new FileInputStream("路径");//字节流
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream);
//字节流--->字符流
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
//这里是字符输入缓冲流,只能传入字符流
bufferedReader.close();//关闭最外层
8.数据流专属
DataOutputStream写的文件只能用DataInputStream去读,并且读的时候需要提前知道写入的顺序。读的顺序与写的顺序一致才能正常取出数据
这两个都是包装流
public class Demo05 {
public static void main(String[] args) {
FileInputStream fileInputStream=null;
FileOutputStream fileOutputStream=null;
DataInputStream dataInputStream=null;
DataOutputStream dataOutputStream=null;
try {
fileInputStream=new FileInputStream("C:\\Users\\Monster y\\Desktop\\456.txt");
fileOutputStream=new FileOutputStream("C:\\Users\\Monster y\\Desktop\\456.txt");
dataInputStream=new DataInputStream(fileInputStream);
dataOutputStream=new DataOutputStream(fileOutputStream);
//写~~~~~~~
dataOutputStream.writeByte(12);
dataOutputStream.writeChar(‘a‘);
dataOutputStream.writeLong(1234l);
//读~~~~~~~
byte b=dataInputStream.readByte();
char c=dataInputStream.readChar();
long l=dataInputStream.readLong();
System.out.println(b);
System.out.println(c);
System.out.println(l);
dataOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (dataInputStream!=null)try {
dataInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
if (dataOutputStream!=null) {
try {
dataOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
9.标准输出流
PrintStream :标准字节输出流,默认输出到控制台,该流不需要手动关闭
System.out.println("hello"); //等价于 PrintStream ps=System.out; ps.println("hello");
PrintStream ps=new PrintStream(new FileOutputStream("路径") ); System.setOut(ps); //标准输出流不再指向控制台,而是指向给出的路径标准输出流不再指向控制台,而是指向给出的路径
10.File类
File类不能完成文件的读和写,File对象代表:目录和文件路径名的抽象表示形式
public class TestFile01 {
public static void main(String[] args) {
File file = new File("E:\\模电三\\1\\a\\b\\d");//创建File对象
if (!(file.exists())){//判断file是否存在
try {
file.createNewFile();//以文件形式创建出来
} catch (IOException e) {
e.printStackTrace();
}
}
file.mkdir();//以目录(文件夹)
file.mkdirs();//创建多重目录 路径为E:\1\a\b\d,文件夹1、a、b、d都不存在,可一次性创建
}
}
-
获取父路径
File file1=new File("E:\\模电三\\1\\a\\b\\d"); String parentPath=file1.getParent();//获取父路径 //E:\模电三\1\a\b File parentFile=file1.getParentFile(); System.out.println(parentFile.getAbsoluteFile());//获取绝对路径 E:\模电三\1\a\b
-
常用方法
String getName();//获取文件名 olean isDirectory();//判断是否为目录 olean isFile();//判断是否为文件 ng lastModified();//最后修改时间,返回自1970以来的毫秒数 ng length();//获取文件的大小 le[] listFiles();//获取当前目录下所有子文件
11.序列化与反序列化
序列化:Serialize java对象存储到文件中
反序列化:DeSerialize 硬盘上的数据恢复到内存中,恢复成java对象
java.io.NotSerializableException :java对象不支持序列化异常
参与序列化和反序列化的对象必须实现Serializable接口,此接口为标志接口,没有任何方法,主要用来给JVM识别,JVM会自动为其生成一个序列化版本号。参与序列化的集合和集合中的元素也都要实现此接口。
public class Demo06 {
public static void main(String[] args) {
ObjectOutputStream oos= null;
ObjectInputStream ois=null;
Object o = new User(15);
try {
oos = new ObjectOutputStream(new FileOutputStream("E:\\模电三\\1\\a\\b\\d\\c"));
ois=new ObjectInputStream(new FileInputStream("E:\\模电三\\1\\a\\b\\d\\c"));
oos.writeObject(o);//序列化(写)
Object oo=ois.readObject();//反序列化(读)
System.out.println(oo.toString());
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class User implements Serializable {
private int age;
//无参数构造方法
public User() { }
//有参数构造方法
public User(int age) {
setAge(age);
}
public void setAge(int age) {
if(age<0|age>150){
System.out.println("您的年龄输入不合法!");
return;
}
this.age = age;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Age : "+age;
}
}
若希望某个属性不参与序列化,加上transient 关键字。
序列化版本号可以用来区分类名一样的两个类(类体不同),自动生成缺点:一旦代码确定,后续不可修改,因为修改后版本号不同,JVM会将其识别为另一个类,导致以前序列化的对象无法反序列化。建议实现Serializable接口的类都手动给出固定的序列化版本号:
private static final long serialVersionUID=132l;