什么是IO流?
I:Input
O:Output
通过IO可以完成硬盘文件的读和写。
IO流的分类?
有多种分类方式:
一种是按照流的方向分类:
往内存中去,叫做输入(Input)。或者叫做读(Read)。
从内存里出来,叫做输出(Output)。或者叫做写(Write)。
另一种是按照读取数据方式不同进行分类:
有的流是按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制。这种流是万能的,什么类型的文件都可以读取,包括:文本文件,图片,声音文件,视频文件。
有的流是按照字符的方式读取数据的,一次读取一个字符,这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片,声音,视频等文件。只能读取纯文本文件,连word文件都无法读取。
综上所述:流的分类
输入流,输出流,
字节流,字符流
Java中所有的流都是在:java.io.*;下。
Java IO流四大家族:
java.io.InputStream 字节输入流
java.io.OutoutStream 字节输出流
java.io.Reader 字符输入流
java.io.Wirter 字符输出流
所有的流都实现了:java.io.Closeable接口,都是可关闭的,都有close()方法。
所有的输出流都实现了:java.io.Flushable接口,都是可刷新的,都有flush()方法。养成一个好习惯,输出流在最终输出之后,一定要记得flush()刷新以下。这个刷新表示将管道当中剩余未输出的数据强行输出完(清空管道),刷新的作用就是清空管道。
如果没有flush()可能会导致丢失数据。
注意:在Java中只要“类名”以Stream结尾的都是字节流。以“Reader/Wirter"结尾的都是字符流。
java.io包下需要掌握的流有16个:
文件专属:
java.io.FileInputStream
java.io.FileOutputStream
转换流:(将字节流转换为字符流)
java.io.InputStreamReader
java.io.OutStreamWriter
缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream
数据流专属:
java.io.DataInputStream
java.io.DataOutputStream
标准输出流:
java.io.PritsWriter
java.io.PrintStream
对象专属流:
java.io.ObjectInputStream
java.io.ObjectOutputStream
1 文件流
FileInputStream
文件字节输入流,万能的,任何类型的文件都可以采用这个流来读。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest01 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\Study\\Java\\test");
int readdate = fis.read();//读取字节本身
System.out.println(readdate);//97 第一个字节
readdate = fis.read();
System.out.println(readdate);//98 第二个字节
readdate = fis.read();
System.out.println(readdate);//99 第二个字节
readdate = fis.read();
System.out.println(readdate);//-1 三个字节已经读完
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {//避免空指针异常
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamTest02 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\Study\\Java\\test");
while (true) {
int readata = fis.read();
if (readata == -1) {
break;
}
System.out.println(readata);
}
//改造while循环
int rdata = 0;
while ((rdata = fis.read()) != -1) {
System.out.println(rdata);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
一次读取一个字节byte,这样内存和硬盘交互太频繁,基本上时间/资源都耗费在交互上面了。
int read(byte[] b)
一次最多读取b.Lengh个字节。
减少硬盘和内存的交互,提高程序的执行效率。往byte[]数组中读。
import java.io.FileInputStream;
import java.io.IOException;
public class FileImputStreamTest03 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\Study\\Java\\test");
//准备一个长度为4的数组
byte[] bytes = new byte[4];
//把byte数组转换成字符串,读到多少就转换多少
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, readCount));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
available();还剩下多少字节没有读
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileInputStreamtest04 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\Study\\Java\\test");
//读取一个字节
int readdata = fis.read();
System.out.println("还剩下多少个字节没有读:" + fis.available());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
skip();跳过几个字节不读取
fis.skip(2);//跳过几个字节不读
System.out.println(fis.read());
FileOutpitStream
文件字节输出流,负责写
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputStreamTest01 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//没有文件会新建
//fos = new FileOutputStream("D:\\Study\\Java\\test");
//追加
fos = new FileOutputStream("D:\\Study\\Java\\test", 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();
}
}
}
}
}
使用FileInputStream+FileOutputStream完成文件的拷贝
拷贝过程一边读,一边写
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Copy01 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("D:\\Study\\Java\\test");
fos = new FileOutputStream("D:\\Study\\Java\\copy");
//准备数组
byte[] bytes = new byte[1024 * 1024];//1M(一次最多拷贝1M)
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1) {
fos.write(bytes, 0, readCount);
}
//刷新,输出流最后要刷新
fos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
FileReader
文本字符输入流,只能读取普通文本。
读取文本内容,比较方便,快捷。
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest01 {
public static void main(String[] args) {
FileReader reader = null;
try {
reader = new FileReader("D:\\Study\\Java\\test");
char[] chars = new char[2];
int readerCount = 0;
while ((readerCount = reader.read(chars)) != -1) {
System.out.print(new String(chars, 0, readerCount));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
FileWriter
文件字符输出流:写
只能输出普通文本。
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest01 {
public static void main(String[] args) {
FileWriter out = null;
try {
//追加后面加true
//out = new FileWriter("D:\\Study\\Java\\test",true);
out = new FileWriter("D:\\Study\\Java\\test");
//重写会覆盖
out.write("提莫队长正在待命!");
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用FileReader+FilwWriter拷贝文件
一边读一边写
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Copy02 {
public static void main(String[] args) {
FileReader reader = null;
FileWriter writer = null;
try {
reader = new FileReader("D:\\Study\\Java\\test");
writer = new FileWriter("D:\\Study\\Java\\copy");
char[] chars = new char[1024 * 512];
int readCount = 0;
while ((readCount = reader.read(chars)) != -1) {
writer.write(chars, 0, readCount);
}
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2 缓冲流
BufferedReader
带有缓冲区的字符输入流
使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组。自带缓冲。
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderTest01 {
public static void main(String[] args) throws IOException {
FileReader reader = new FileReader("D:\\Study\\Java\\test");
//当一个流的构造方法中需要一个流的时候,被传进来的流叫做:节点流。
//外部负责包装的这个流,叫做:包装流,还有一个名字叫做:处理流。
//FileReader 节点流 BufferedReader 包装流/处理流
BufferedReader br = new BufferedReader(reader);
//读第一行 不带换行符
String firstLine = br.readLine();
System.out.println(firstLine);
//到达文件末尾会返回一个null
String s = null;
while ((s = br.readLine()) != null) {
System.out.println(s);
}
//关闭流
//对于包装流来说,只需要关闭最外层的流即可,里面的节点流会自动关闭。
br.close();
}
}
通过转换流转换(将字节流转换为字符流)
import java.io.*;
/**
* @author wcs
* @date 2021/8/12 18:52
*/
public class BufferedReaderTest02 {
public static void main(String[] args) throws IOException {
//字节流
FileInputStream in = new FileInputStream("D:\\Study\\Java\\test");
//字节流不能给BufferedReade
// BufferedReader reader = new BufferedReader(in);
//通过转换流转换(将字节流转换为字符流)
InputStreamReader reader = new InputStreamReader(in);
BufferedReader br = new BufferedReader(reader);
System.out.println(br.readLine());
String s = null;
while ((s = br.readLine()) != null){
System.out.println(s);
}
br.close();
}
}
BufferedWriter
带有字符缓冲的字符流
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterTest01 {
public static void main(String[] args) throws IOException {
FileWriter writer = new FileWriter("D:\\Study\\Java\\test", true);
BufferedWriter br = new BufferedWriter(writer);
br.write("德玛西亚之力");
br.append("\n");
br.write("德玛西亚之力");
br.append("A");
br.flush();
br.close();
}
}
3 数据流
DataOutputStream
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class DataOutputStreamTest01 {
public static void main(String[] args) throws IOException {
DataOutputStream dos = new DataOutputStream(new FileOutputStream("D:\\Study\\Java"));
//写数据
byte b = 100;
short t = 200;
char c = 'a';
long l = 400L;
float f = 3.14f;
int i = 300;
//写
dos.writeByte(b);
dos.writeShort(t);
dos.writeInt(i);
dos.writeLong(400L);
//刷新
dos.flush();
}
}
DataInputStream
数据字节输入流。
DataOutStream写的文件,只能使用DataInputStream去读。并且读的时候你需要提取知道写入的顺序。
读的顺序和写的顺序一致,才能正常取出数据。
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
public class DataInputStreamTest01 {
public static void main(String[] args) throws IOException {
DataInputStream dis = new DataInputStream(new FileInputStream("D:\\Study\\Java"));
byte b = dis.readByte();
short t = dis.readShort();
int i = dis.readInt();
long l = dis.readLong();
System.out.println(b);
System.out.println(t);
System.out.println(i);
System.out.println(l);
dis.close();
}
}
4 标准输出流
PrintStream
标准的字节输出流。默认输出到控制台。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintStreamTest01 {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("hello world");
PrintStream ps = System.out;
ps.println("jack");
ps.println(123);
//标准输出流不需要关闭
//改变输出方向
//标准输出流不再指向控制台,指向test文件
System.setOut(new PrintStream(new FileOutputStream("D:\\Study\\Java\\test")));
System.out.println("hello");
System.out.println("jack");
}
}
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日志工具
*指向一个日志文件
*/
public class Logger {
public static void main(String[] args) throws FileNotFoundException {
System.setOut(new PrintStream(new FileOutputStream("D:\\Study\\Java\\log.txt")));
Date nowtime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String strTime = sdf.format(nowtime);
System.out.println(strTime);
}
}
4 对象流
ObjectOutputStream
参与序列化和反序列化的对象必须实现Serializable接口。
这个接口起到标识作用,Java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。
import java.io.*;
public class ObjectOutputStreamTest01 {
public static void main(String[] args) throws IOException {
//创建Student对象
Student s = new Student(111, "jack");
//序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("students"));
//序列化对象
oos.writeObject(s);
//刷新
oos.flush();
//关闭
oos.close();
}
}
class Student implements Serializable {
int no;
String name;
public Student() {
}
public Student(int no, String name) {
this.no = no;
this.name = name;
}
}
ObjectInputStream
反序列化
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ObjectInputStreamTest01 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("students"));
;
//开始反序列化
Object obj = ois.readObject();
//反序列化回来是一个学生对象,所以会调用学生对象的toString方法
System.out.println(obj);
ois.close();
}
}
也可以把对象放到集合当中,序列集合,可以达到一个序列化多个对象。
5 File类
文件和目录表示的抽象形式
File类中常用方法:
import java.io.File;
import java.io.IOException;
public class FileTest01 {
public static void main(String[] args) throws IOException {
//创建file对象
File f1 = new File("D:\\user");
//判断是否存在
System.out.println(f1.exists());
//如果不存在 新建
// if (!f1.exists()){
// //以文件的形式新建
// f1.createNewFile();
// }
//如果不存在以目录的形式新建
// if (!f1.exists()){
// f1.mkdir();
// }
//创建多层目录
// File f2 = new File("D:\\user\\a\\c");
// if (!f2.exists()){
// f2.mkdirs();
// }
File f3 = new File("D:\\Study\\Java\\log.txt");
//获取文件父路径
String path = f3.getParent();
System.out.println(path);
File pf = f3.getParentFile();
System.out.println(pf);
//获取绝对路径
System.out.println(f3.getAbsolutePath());
}
}
import java.io.File;
public class FileTest02 {
public static void main(String[] args) {
File f1 = new File("D:\\Study\\Java\\log.txt");
//获取文件名
System.out.println(f1.getName());
//判断是否是一个目录
System.out.println(f1.isDirectory());//false
//判断是否是一个文件
System.out.println(f1.isFile());//trye
//获取文件最后一次修改时间
System.out.println(f1.lastModified());//long类型毫秒数
//获取文件大小
System.out.println(f1.length());
}
}
import java.io.File;
public class FileTest03 {
public static void main(String[] args) {
//获取当前目录下所有子文件
File f = new File("D:/Study");
File[] files = f.listFiles();
for (File s : files){
System.out.println(s);
}
}
}
拷贝目录
import java.io.File;
public class CopyAll {
public static void main(String[] args) {
File src = new File("D:\\Study\\Java");
File dest = new File("C:\\test");
copyDir(src, dest);
}
private static void copyDir(File src, File dest) {
//获取源下面的子目录
File[] files = src.listFiles();
if (src.isFile()) {
return;
}
for (File f : files) {
//System.out.println(f.getAbsoluteFile());
if (f.isDirectory()) {
String srcDir = f.getAbsolutePath();
String destDir = (dest.getAbsolutePath().endsWith("\\") ? dest.getAbsolutePath() : dest.getAbsolutePath() + "\\") + srcDir.substring(3);
File newFile = new File(destDir);
if (!newFile.exists()) {
newFile.mkdirs();
}
}
//递归调用
copyDir(f, dest);
}
}
}
6 IO+Properties的联合使用
以后经常改变的数据,可以单独写道一个文件中,使程序动态获取。
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;
public class IOPropertiesTest {
public static void main(String[] args) throws IOException {
/*
Properties是一个Map集合,key和value都是String类型。
将userinfo文件中的数据加载到Properties对象中。
*/
//新建一个输入流对象
FileReader reader = new FileReader("D:\\Study\\Java\\Project\\IO流\\IO+Properties\\userinfo");
//新建一个Map对象
Properties pro = new Properties();
//调用Properties对象的load方法将文件中的数据加载到Map对象
pro.load(reader);
System.out.println(pro.getProperty("username"));
System.out.println(pro.getProperty("password"));
}
}