目录
- 一、IO流的分类:
- 二、IO流使用注意事项:
- 三、java.io包下需要掌握的流:
- 四、FileInputStream:*重点*
- 五、FileOutputStream:*重点*
- 六、文件复制案例:
- 七、FileReader/FileWriter:
- 八、BufferedReader/BufferedWriter/BufferedInputStream/BufferedOutputStream:
- 九、InputStreamReader/OutputStreamWriter:
- 十、DataInputStream/DataOutputStream:
- 十一、PrintStream:
- 十一、File:
- 十二、ObjectInputStream/ ObjectOutputStream:
一、IO流的分类:
1.按照流的方向进行分类:
(1) 输入流:数据硬盘到内存,叫Input输入,或者叫Read读。
(2) 输出流:数据内存到硬盘,叫做Output输出,或者叫Write写。
2. 按照读取数据方式进行分类:
(1) 字节流:一次读取1byte,等同于一次读取8个二进制位,这种流是万能的,什么类型的文件都可以读取。
(2)字符流:一次读取1个字符,这种流只能读取纯文本文件txt。
3. Java中 顶级IO流抽象类:
- java.io.InputStream 字节输入流
- java.io.OutputStream 字节输出流
- java.io.Reader 字符输入流
- java.io.Writer 字符输出流
二、IO流使用注意事项:
- 创建的每一个流都是在内存和硬盘之间建立连接,用完一定要调用close()方法关闭连接。
- 所有输出流在输出之后一定要调用flush()方法刷新。
三、java.io包下需要掌握的流:
以Stream结尾的叫字节流,以Reader/Writer结尾的叫字符流。
1. 文件专属:
java.io.FileInputStream 重点
java.io.FileOutputSteam 重点
java.io.FileReader
java.io.FileWriter
2. 转换流(字节流转换为字符流):
java.io.InputStreamReader
java.io.OutputStreamWriter
3. 缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputSteam
4. 数据流专属:
java.io.DataInputStream
java.io.DataOutputSteam
5. 标准输出流:
java.io.PrintWriter
java.io.PrintStream
6. 对象专属流:
java.io.ObjectInputStream
java.io.ObjectOutputSteam
四、FileInputStream:重点
1. 步骤:
(1)创建字节输入流对象。
(2)调用对象的read()方法一个一个读取字节。
(3)关闭流。
2. 读数据代码:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Test{
public static void main(String[] args) {
FileInputStream fis = null;
try {
//创建字节输入流对象
fis = new FileInputStream("D:\\test.txt");//这是绝对路径,相对路径则以工程所在文件夹为起始
int readData = 0;
while((readData = fis.read()) != -1){//循环读取,每次读取1个字节,返回值是字节本身的ASCII码
System.out.println(readData);
}
}catch(FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//finally语句块中确保流一定关闭
if(fis != null){
//关闭流的前提是:流不为空
try {
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
}//结果:97 98 99 100 101 102
3. 注意事项:
(1)对象read()方法返回值是int类型,即字节的ASCII码。
(2)read()方法初始指针指向第一个字节,每次调用read()方法只能读取1个字节,读取完后指针自动后移一位指向下一字节。
(3)若所有字节都已经读完,下一次调用read()方法会返回-1。
(4)创建字节输入流对象、调用read()方法、调用close()方法都需要捕获异常,可以用IDEA自动生成代码。
(5)关闭流的前提是:流不为空。
(6)一开始创建的对象为null是为了判断流是否为空,方便判断流是否需要关闭。
(7)可以使用绝对路径。如果要使用相对路径,工程Project的路径即为默认起点。
4. 代码改进:
上述代码一次只能读取一个字节,效率低。我们可以一次读取多个字节,提高程序执行效率。
int read(byte[ ] b);
一次读取b.length个字节,读到byte数组中。
返回值是读取到的字节数量,读不到任何数据返回-1。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Test{
public static void main(String[] args) {
FileInputStream fis = null;
byte[] bytes = new byte[4];
try {
//创建字节输入流对象
fis = new FileInputStream("D:\\test.txt");
int readCount = 0;
while((readCount = fis.read(bytes)) != -1){
System.out.println(new String(bytes,0,readCount));//把本次读入到bytes数组中的字节转换成字符串,本次读入的字节即数组0~readCount中的内容。
//为什么要这样?假如有文本中6个字节abcdef,第一次读4个输出为abcd,第二次只需要输出ef,如果不限制输出0~readCount这个范围的话第二次输出的就是efcd了。
}
}catch(FileNotFoundException e){
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//finally语句块中确保流一定关闭
if(fis != null){
//关闭流的前提是:流不为空
try {
fis.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
}
}//结果:abcd ef
5. 该类中其他常用方法:
(1)返回流中剩余的没有读到的字节数量
int available();//文件大小不是太大的情况下,可以将byte数组设置为这个大小,一次就读完了,不需要循环。
(2)跳过n个字节不读取
long skip(long n);
五、FileOutputStream:重点
1. 步骤:
(1)创建字节输出流对象。
(2)调用对象的read()方法一个一个读取字节。
(3)刷新流。
(4)关闭流。
2. 写数据代码:
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test{
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//没有该文件时会自动新建
//fos = new FileOutputStream("D:\\TestWrite.txt");//这个构造方法会将源文件清空,然后重新写入
fos = new FileOutputStream("D:\\TestWrite.txt",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();
}
}
}
}
}
3. 注意事项:
(1)对象write()方法写的是byte类型,若要写字符串需要使用字符串的getVByte()方法转为字节数组 。
(2)所有write()方法执行完后一定要使用flush()方法刷新。
(3)构造方法new FileOutputStream(name)创建的对象在write()的时候会先将文件内容清空后再写(只是清空原文件内容,第二次调用write的时候第一次write的内容不清空)。而构造方法new FileOutputStream(name,append)将append置true创建的对象在write()的时候会在原文件内容的末尾追加写,不会删除原文件内容。
(4)创建字节输出流对象、调用write()方法、调用flush()方法、调用close()方法都需要捕获异常,可以用IDEA自动生成代码。
(5)关闭流的前提是:流不为空。
(6)一开始创建的对象为null是为了判断流是否为空,方便判断流是否需要关闭。
(7)可以使用绝对路径。如果要使用相对路径,工程Project的路径即为默认起点。
六、文件复制案例:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Test{
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("D:\\IOcopy.jpeg");
fos = new FileOutputStream("D:\\IOcopy1.jpeg",true);
byte[] bytes = new byte[10 * 1024];//10kb
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();
}finally{
if (fos != null) {//分开try关闭流,不然一个流出了异常另一个流就关不了了
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
七、FileReader/FileWriter:
- 字符流读写,代码类似FileInputStream/FileOutputStream,不过byte数组要换成用char数组,因为读写的是字符。
- void write()方法里可以加字符串。
- 只能操作普通.txt文件.java文件.html文件,效率高。
1.字符流写数据代码:
//产生1000个随机数并存储到txt文件中
public static void wirteRadom(String path){
BufferedWriter bw = null;
Random random = new Random();
try {
//这样创建的字符流可以防止写入乱码的情况
bw = new BufferedWriter(
new OutputStreamWriter(
new FileOutputStream(path,true), "UTF-8"));
int i = 0;
while (i<1000){
bw.write(String.valueOf(random.nextInt(100)));
i++;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (bw != null){
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
2.字符流写数据代码:
//读取格式为“52,45,12,65,87,94”的txt文件,并赋值给int[]数组
public static int[] readRadom(String path) {
FileReader fr = null;
int res[] = new int[1000];
String datas = "";
try {
fr = new FileReader(path);
int data = 0;
while ((data = fr.read()) != -1) {
datas += (char)data;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
String temps[] = datas.split(",");
for (int i = 0; i < temps.length; i++) {
res[i] = Integer.parseInt(temps[i]);
}
return res;
}
八、BufferedReader/BufferedWriter/BufferedInputStream/BufferedOutputStream:
1. 缓冲流定义:
- 使用这些流的时候不需要创建字符数组和字节数组,自带缓冲区,缓冲区满了才读,效率高。
- 主要学习BufferedReader类的readLine()方法:读一行,无行可读返回null。
- 当一个流的构造方法中需要一个流的时候,被传进来的流叫节点流,外部流叫包装流,关闭流时只需要关闭包装流。
2. 读数据代码:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test{
public static void main(String[] args) {
BufferedReader br = null;
try {
FileReader fw = new FileReader("D:\\test.txt");
br = new BufferedReader(fw);
String readCount = " ";
while((readCount = br.readLine()) != null){
System.out.println(readCount);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
九、InputStreamReader/OutputStreamWriter:
1.定义:
- 字节流转字符流。
2. 代码:
FileInputStream fis = new FileInputStream("D:\\test.txt");//字节输入流
InputStreamReader reader = new InputStreamReader(fis);//转为字符输入流
FileOutputStream fos = new FileOutputStream("D:\\test.txt");//字节输出流
OutputStreamWriter writer = new OutputStreamWriter(fos);//转为字符输出流
十、DataInputStream/DataOutputStream:
1.定义:
- 这个流可以将数据类型一并写入文件,从这个文件中读到的数据也包含数据类型。
- DataOutputStream写的文件,只能用DataInputStream去读,读的顺序还要和写的顺序一致,记事本也打不开这种文件。
2. DataOutputStream:
3. DataInputStream:
十一、PrintStream:
1.定义:
- 标准的字节输出流,默认输出到控制台。
- 标准输出流不需要手动关闭。
2.代码:
import java.io.PrintStream;
public class Test{
public static void main(String[] args){
System.out.println("go!");
/*等同于*/
PrintStream ps = System.out;
ps.println("go!");
}
}
我们可以改变标准输出流的输出方向,标准输出流不再指向控制台,将标准输出流输出到log文件。应用:写日志文件。
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class Test{
public static void main(String[] args) throws FileNotFoundException {
PrintStream ps = new PrintStream(new FileOutputStream("D:\\test.txt",true));
System.setOut(ps);//修改输出流方向
System.out.println("go!");
}
}
十一、File:
1. 定义:
(1)File类和四大顶级IO抽象类没有什么关系,所以File不能完成文件的读写。
(2)一个File对象是一个文件名或目录名的抽象表示形式,是一个容器。例如:D:\Program Files ,D:\Program Files\test.txt都是File对象。
2. File类中常用方法:
(1)判断是否存在:
file.exists()
(2)创建文件:
file.createNewFile()
(3)创建目录:
file.mkdir()
(4)创建多重目录:
file.mkdirs()
(5)获取文件的父路径,返回String类型:
file.parentPath()
(6)获取文件的父路径,返回File类型:
file.parentFile()
(7)获取绝对路径:
file.getAbsolutePath()
(8)获取文件名:
file.getName()
(9)判断是否是目录:
file.isDirectory()
(10)判断是否是文件:
file.isFile()
(11)获取文件最后一次修改时间,返回毫秒数:
file.lastModified()
(12)获取文件字节大小:
file.length()
(13)获取当前目录下所有子文件,返回File数组:
file.listFiles()
十二、ObjectInputStream/ ObjectOutputStream:
1. 序列化:
Java对象存储到文件中,将Java对象的状态保存下来的过程。类需要继承Serializable接口。成员变量加transient关键字表示该变量不参与序列化,即保存的的对象中该变量的值为null.。
序列化版本号:实现Serializable接口时Java虚拟机会自动生成序列化版本号(唯一性),用于区分同一个包下的同名类。相同序列化版本号的类才能进行序列化和反序列化。建议手动添加序列化版本号,不然修改代码后虚拟机会修改序列化版本号:
private static final long serialVersionUID = _____;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Test{
public static void main(String[] args) throws IOException {
List<User> list = new ArrayList<>();
list.add(new User("张三",001));
list.add(new User("李四",002));
list.add(new User("王五",003));
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\Users"));
oos.writeObject(list);//序列化
oos.flush();
oos.close();
}
}
class User implements Serializable{
private String name;
private int id;
public User() {
}
public User(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}
2. 反序列化:
将硬盘上的数据重新恢复到内存中,恢复成Java对象。
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Test{
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\Users"));
List<User> list = (List<User>) ois.readObject();//反序列化
for(User user:list){
System.out.println(user.toString());
}
}
}
class User implements Serializable{
private String name;
private int id;
public User() {
}
public User(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
'}';
}
}