1、IO流分类
有三种分类方式:
1、按流的方向
以内存为参照物,
- 往内存中去:输入:Input、Read
- 从内存中出:输出:Output、Write
2、按读取数据的方式
- 字节形式读取:一次读取一个字节,即8个二进制位,这种流是万能的,什么文件都能读,包括文本、视频、图片等等。
- 字符形式读取:一次读取一个字节,这种流是为了方便读取普通文本文件而存在的,这种流只能读取纯文本文件,即使word文件也不能读取。用记事本能正常打开的都是普通文本文件
“a啊a”:字符流一次读一个字符,第一次读“a”,第二次读“啊”(能自动识别一个一个的字符)。字节流每次读8个二进制位,第一次读“a“,第二次读”啊“的前一半,第三次读”啊“的后一半!
3、按功能不同分为 节点流、处理流
当一个流的构造方法需要一个流为参数时,这个作为参数的流叫节点流,该流叫处理流
- 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,
关闭时只需要关闭最外层的处理流
2、Java IO整体结构
1、Java IO四大家族:
字符:
- Java.io.Reader
- Java.io.Writer
字节:
- Java.io.InputStream
- Java.io.OutputStream
注意:
- 所有的流都继承这四个抽象类,在java中只要类名"以 stream结尾的都是字节流。以 Reader/ Writer结尾的都是字符流
- 他们都实现了Closeable接口,有close方法。只有输出实现了flushable接口,有flush方法,刷新输出管道
2、我们需要熟悉的类:
文件专属
- java.io FileInputstream
- java. io Fileoutputstream
- java.io FileReader
- java.io FileWriter
转换流:(将字节流转换成字符流)
- java.io. InputstreamReader
- java. io. Outputstreamwriter
缓冲流专属
- java. io BufferedReader
- java. io Bufferedwriter
- java. io BufferedInputstream
- java. io. Bufferedoutputstream
数据流专属:
- java. io DataInputstream
- java.io Dataoutputstream
标准输出流:
- java. io Printwriter
- java.io Printstream
对象专属流(对象需要序列化)
- java.io objectInputstream
- java.io Objectoutputstream
3、文件专属FileInput(Output)Stream
FileInputStream使用方式:
1、使用read()方法挨个读取
FileInputStream input = new FileInputStream(绝对/相对路径);//相对路径:从当前工程的根目录开始
while(input.read() != -1){//到文件末尾返回-1,否则返回读到的字节大小本身
操作
}
这样读取方式太慢,因为每次都是读一个字节,内存与硬盘交互太频繁,非常耗资源。
2、使用read(byte[] bytes)方法多个读取
public class Main{
public static void main(String args[]){
byte[] bytes = new byte[100];
/**
* 如果文件中待读取的字节数大于bytes长度,一次性就读length(4)个字节,小于则读取剩余个字节
* 剩余已经没有字节可读就返回-1。新的一次读会覆盖原byte数组的前几个数据
* 返回值就是实际读取到的字节数
*/
try(FileInputStream input = new FileInputStream("C:\\面试\\test.txt")){
int count = 0;
//获取文件剩余没读的字节数,可以直接通过这个获取文件总字节数然后创建一个对应大小的byte数组
//不适合大文件
//input.available();
while((count = input.read(bytes)) != -1){
String str = new String(bytes, 0, count);//不能全部转化为字符串,只转化读取到前count个数的
System.out.println(str);
}
}catch (Exception e){
e.printStackTrace();
return null;
}
}
}
FileOutputStream
//不设置append为true会清空源文件从头再写,文件不存自动创建
try(FileOutputStream output = new FileOutputStream("test.txt", true)){
String str = "hello world";
byte[] bytes = str.getBytes();
output.write(bytes);//bytes全部写出,也可以和前面一样使用部分写出
output.flush();//写完记得刷新
}catch (Exception e){
e.printStackTrace();
}
FileReader和FileWriter与上面两个使用一样,读到char数组里面,从char数组或Sting对象写到文件里面。(只能操作内容为普通文本的文件)
4、缓冲流Bufferedwriter和BufferedReader
封装FileReader和FileWriter进行一些操作,不需要像以前只使用FileReader等需要自己加个char数组等操作。
5、数据流
将数据连同数据的类型写入文件,记事本无法打开这个文件。读这种文件时的顺序必须和写的顺序一致
6、标准输出流
System.out就是一个标准输出流PrintStream,默认PrintStream是输出到控制台,可以自己new个PrintStream并设置输出到一个文件
调用System.setOut(PrintStream ps)设置System的out对象,这样后面调用System.out.print()就是输出到PrintStream设置的输出文件了。
7、File类
File类主要是JAVA为文件这块的操作(如删除、新增等)而设计的相关类
常用方法
判断文件或目录是否存在、创建文件或目录
public class Main{
public static void main(String args[]) {
File file = new File("C://file//file1//file2");
System.out.println(file.exists());
if(!file.exists()){
// try {
//以文件形式创建
// file.createNewFile();
// } catch (IOException e) {
// e.printStackTrace();
// }
//以目录形式创建,如果是多重目录则创建失败
// file.mkdir();
//以多重目录形式创建
file.mkdirs();
}
}
}
其它的各种骚操作用的时候再查api,比如:获取文件名、判断当前file是文件还是目录呀、获取最后一次修改时间丫等等
8、FileInput(output)Stream结合File实现目录拷贝
public void copyDir(File srcDir, File targetDir){
if(srcDir是文件){
使用FileInputStream和FileOutputStream进行文件拷贝
return ;递归结束
}
//如果是目录
1、得到该目录所有子目录及文件的File
2、遍历所有子目录与子文件,
if(判断子File是目录){
创建目录:将File决定地址与目的地址拼接
}
递归调用copyDir(子目录,targetDir)
}