目录
3.1FileInputStream和FileOutputStream
3.3ObjectInputStream和ObjectOutputStream
4.3BufferedReader和BufferedWriter
4.4BufferedInputStream和BufferedOutputStream
5.1DataInputStream和DataOutputStream
6.1InputStreamReader和OutputStreamWriter
1 IO流
1.1介绍
java中I/O的操作主要是靠java.io
包下面的类和接口来实现的,进入输入,输出操作.输入也可以叫做读取数据,输出也可以叫做写入数据.
1.2流的分类
- 按照数据流向分为输入流(InputStream)和输出流(OutputStream)。
- 按照数据类型分为字节流(Byte Stream)和字符流(Character Stream)。
- 按照流的角色不同分为包装流和节点流
1.3IO体系图
2 文件
2.1文件的创建(三种方法)
public class FlieCreate01 {
public static void main(String[] args) {
File file = new File("D:\\word.txt");
if(file.exists()){
file.delete();
System.out.println("文件已删除");
}else{
try{
file.createNewFile();
System.out.println("文件已建立");
}catch (Exception e){
e.printStackTrace();
}
}
}
}
public class FileCreate02 {
public static void main(String[] args) {
//父目录的根目录+子路径
File file = new File("D:\\");
String fileName="word2.txt";
File word2 = new File(file,fileName);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class FileCreate03 {
public static void main(String[] args) {
//根据new(String parent,String child) 父目录+子路径
String parentPath="D:\\";
String fileName="word3.txt";
File file = new File(parentPath, fileName);
try {
file.createNewFile();
System.out.println("文件创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
2.2文件的操作
public class Demo {
public static void main(String[] args) {
File file = new File("D:\\a.txt");
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("是否是文件"+file.isFile());
System.out.println("是否被隐藏"+file.isHidden());
System.out.println("文件是否存在"+file.exists());
System.out.println("文件的字节长度"+file.length());
System.out.println(file.mkdirs());
System.out.println("文件的绝对路径"+file.getAbsolutePath());
System.out.println("文件是否可读"+file.canRead());
System.out.println("文件的名字是"+file.getName());
System.out.println("父路径为"+file.getParent());
}
}
运行结果如下:
2.3mkdirs和mkdir方法
查阅API可知两者都是:创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录。返回值为boolean类型。
mkdirs可以创建多级目录而mkdir只能创建单个目录。
可以配合 public File[] listFiles() 方法进行使用,用来遍历目录。
3 文件输入/输出
3.1FileInputStream和FileOutputStream
二者都用来操作磁盘文件,如果用户的文件读取需求比较简单,则可以使用FileInputStream,该类继承在InputStream,FileInputStream和FileOutputStream有着相同的参数构造方法,创建一个FileOutputStream对象时,可以指定不存在的文件名,但此文件不能是一个已被其他程序打开的文件,下面实例就是使用FileInputStream和FileOutputStream实现文件的读取和写入功能的。
public class Demo1 {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("D:\\test.txt");
byte[] bytes="我有一个小毛驴,我从来也不骑".getBytes();
fileOutputStream.write(bytes);
fileOutputStream.close();
byte[] bytes1 = new byte[8];
FileInputStream fileInputStream = new FileInputStream("D:\\test.txt");
int cnt=fileInputStream.read(bytes1);
System.out.println("文件中的信息是:"+new String(bytes1,0,cnt));
fileInputStream.close();
}
}
程序运行后会向D盘根目录下的test.txt文件写入一段文字,并且在控制台输出。
说明
虽然Java在程序结束时会自动关闭所有打开的流,但是当使用完流后,显式的关闭所有打开的流是一个好习惯,一个被打开的流有可能会用尽系统资源,这却决于平台和实现,如果没有将打开的流关闭,当另一个程序试图打开另一个流时,可能会得不到需要的资源。
3.2FileReader和FileWriter
使用 FileReader和FileWriter对应了FileInputStream和FileOutputStream,FileReader顺序读取文件,只要不关闭流,每次调用read方法就顺序的读取了源中剩余内容,直到源末尾
public void readFile() {
System.out.println("~~~readFile ~~~");
String filePath = "e:\\story.txt";
FileReader fileReader = null;
int readLen = 0;
char[] buf = new char[8];
//1. 创建FileReader对象
try {
fileReader = new FileReader(filePath);
//循环读取 使用read(buf), 返回的是实际读取到的字符数
//如果返回-1, 说明到文件结束
while ((readLen = fileReader.read(buf)) != -1) {
System.out.print(new String(buf, 0, readLen));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fileReader != null) {
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
close和flush的区别
简单来说,close包含flush功能,但是flush具备刷新完,还可以继续写操作,close执行完了就流关闭了,不能再写入,所以,不能用close来代替flush。 查看close的源码可得
@SuppressWarnings("try")
public void close() throws IOException {
try (OutputStream ostream = out) {
flush();
}
}
3.3ObjectInputStream和ObjectOutputStream
① 功能:提供了对基本类型或对象类型的序列化和反序列化的方法;
② ObjectOutputStream 提供 序列化功能;
③ ObjectInputStream 提供 反序列化功能。
//ObjectOutStream_类
public class ObjectOutStream_ {
public static void main(String[] args) throws Exception {
//序列化后,保存的文件格式,不是存文本,而是按照他的格式来保存
String filePath = "D:\\data.dat";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filePath));
//序列化数据到 e:\data.dat
oos.writeInt(100);// int -> Integer (实现了 Serializable)
oos.writeBoolean(true);// boolean -> Boolean (实现了 Serializable)
oos.writeChar('a');// char -> Character (实现了 Serializable)
oos.writeDouble(9.5);// double -> Double (实现了 Serializable)
oos.writeUTF("abc");//String
//保存一个dog对象
oos.writeObject(new Dog("旺财", 10));
oos.close();
System.out.println("数据保存完毕(序列化形式)");
}
}
//如果需要序列化某个类的对象,实现 Serializable
public class Dog implements Serializable {
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// ObjectInputStream_类
public class ObjectInputStream_ {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//指定反序列化的文件
String filePath = "D:\\data.dat";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filePath));
//1. 读取(反序列化)的顺序需要和你保存数据(序列化)的顺序一致
//2. 否则会出现异常
System.out.println(ois.readInt());
System.out.println(ois.readBoolean());
System.out.println(ois.readChar());
System.out.println(ois.readDouble());
System.out.println(ois.readUTF());
//dog 的编译类型是 Object , dog 的运行类型是 Dog
Object dog = ois.readObject();
System.out.println("运行类型=" + dog.getClass());
System.out.println("dog信息=" + dog);//底层 Object -> Dog
//这里是特别重要的细节:
//1. 如果我们希望调用Dog的方法, 需要向下转型
//2. 需要我们将Dog类的定义,放在到可以引用的位置
Dog dog2 = (Dog)dog;
System.out.println(dog2.getName()); //旺财..
//关闭流, 关闭外层流即可,底层会关闭 FileInputStream 流
ois.close();
}
}
注意事项
1.读写顺序要一致
2.要求序列化对象实现Serializable
3.序列化对象中建议添加SerialVersionUID,可以提高兼容性
4.被transient修饰的成员不会被序列化或反序列化
4 节点流和处理流
4.1介绍
1)节点流可以从一个特定的数据源【数据源就是存放数据的地方】读写数据,如FileReader、FileWriter;
2)处理流(也叫包装流)是“连接”在已存在的流(节点流或处理流)之上,为程序提供更为强大的读写功能,也更加灵活,如BufferedReader、BufferedWriter。
4.2区别和联系
(1)节点流是底层流/低级流,直接跟数据源相接;
(2)处理流包装节点流,既可以消除不同节点流的实现差异,也可以提供更方便的方法来实现输入输出;
(3)处理流(包装流)对节点流进行包装,使用了 修饰器设计模式,不会直接于数据源相连。
4.3BufferedReader和BufferedWriter
下面代码演示用BufferedReader和BufferedWriter拷贝文件
public class Demo {
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\a.txt"));
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\b.txt"));
String a="";
while((a=bufferedReader.readLine())!=null){
//bufferedReader.readLine()的返回值是一个字符串所以判断条件是null
//而read()的返回值是int,判断条件是是否为-1
bufferedWriter.write(a);
bufferedWriter.newLine();
}
bufferedReader.close();
bufferedWriter.close();
}
}
4.4BufferedInputStream和BufferedOutputStream
BufferedInputStream是字节流,在创建BufferedInputStream时,会创建内部缓冲区数组。
public class BufferedCopy02 {
public static void main(String[] args) {
String srcFilePath = "D:\\a.java";
String destFilePath = "D:\\a3.java";
//创建BufferedOutputStream对象BufferedInputStream对象
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
//因为 FileInputStream 是 InputStream 子类
bis = new BufferedInputStream(new FileInputStream(srcFilePath));
bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
//循环的读取文件,并写入到 destFilePath
byte[] buff = new byte[1024];
int readLen = 0;
//当返回 -1 时,就表示文件读取完毕
while ((readLen = bis.read(buff)) != -1) {
bos.write(buff, 0, readLen);
}
System.out.println("文件拷贝完毕~~~");
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭流 , 关闭外层的处理流即可,底层会去关闭节点流
try {
if(bis != null) {
bis.close();
}
if(bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
5 数据输入/输出流
5.1DataInputStream和DataOutputStream
DataInputStream和DataOutputStream允许应用程序以与机器无关的方式从底层输入流中读取基本Java数据类型,不必再关心是哪个字节。
分别通过DataOutputStream类的writeUTF(),writeDouble(),riteInt()和writeBoolean()方法向指定的word.txt文件中写入不同类型的数据,并通过DataInputStream类相应方法输出到控制台
5.2代码实现
public class DataDemo {
public static void main(String[] args) {
File file = new File("D:\\word.txt");
try {
FileOutputStream fileOutputStream = new FileOutputStream(file);
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
dataOutputStream.writeUTF("使用UTF方法写入数据");
dataOutputStream.writeDouble(19.5);
dataOutputStream.writeInt(10);
dataOutputStream.writeBoolean(true);
dataOutputStream.close();
FileInputStream fileInputStream = new FileInputStream(file);
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
System.out.println("readUTF()读取数据:"+dataInputStream.readUTF());
System.out.println("readDouble()读取数据:"+dataInputStream.readDouble());
System.out.println("readInt():"+dataInputStream.readInt());
System.out.println("readBoolean()读取数据:"+dataInputStream.readBoolean());
} catch (IOException e) {
e.printStackTrace();
}
}
}
6 转换流
6.1InputStreamReader和OutputStreamWriter
(1)InputStreamReader:Reader的子类,可以将InputStream(字节流)包装成(转换)Reader(字符流);
(2)OutputStreamWriter:Writer的子类,实现将OutputStream(字节流)包装成Writer(字符流);
(3)当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换为字符流;
(4)可以在使用时指定编码格式(比如utf-8、gbk、gb2312、ISO8859-1等)
6.2代码实现
/**
* 演示使用 InputStreamReader 转换流解决中文乱码问题
* 将字节流 FileInputStream 转成字符流 InputStreamReader, 指定编码 gbk/utf-8
*/
public class InputStreamReader_ {
public static void main(String[] args) throws IOException {
String filePath = "D:\\test.txt";
//解读
//1. 把 FileInputStream 转成 InputStreamReader
//2. 指定编码 gbk
//InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), "gbk");
//3. 把 InputStreamReader 传入 BufferedReader
//BufferedReader br = new BufferedReader(isr);
//将2 和 3 合在一起
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath), "gbk"));
//4. 读取
String s = br.readLine();
System.out.println("读取内容=" + s);
//5. 关闭外层流
br.close();
}
}
/**
* 演示 OutputStreamWriter 使用
* 把FileOutputStream 字节流,转成字符流 OutputStreamWriter
* 指定处理的编码 gbk/utf-8/utf8
*/
public class OutputStreamWriter_ {
public static void main(String[] args) throws IOException {
String filePath = "D:\\test.txt";
String charSet = "utf-8";
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(filePath), charSet);
osw.write("hi, 哈哈哈");
osw.close();
System.out.println("按照 " + charSet + " 保存文件成功~");
}
}