-
一般用于操作二进制文件,数据的单位是byte(视频,音频,图片,exe,dll等文件)
-
以InputStream或OutputStream结尾
-
一般用于操作文本数据,数据的单位是char(txt,xml,html等文件)
-
以Reade或Writer结尾
-
从磁盘文件或网络流到java程序中,用于读取数据
-
所有字节输入流的父类是InputStream;
-
所有字符输入流的父类是Reade;
-
从java程序流向磁盘文件或网络写入文件
-
所有字节输出流的父类是OutputStream;
-
所有字符输出流的父类是Writer;
由于经常需要使用IO流来操作硬盘上的文件,JDK将硬盘上的文件映射为java.io.File类,所以我们先要学习如何使用这个类。
File类以抽象的方式代表文件名和目录路径名。该类主要用于文件和目录的创建、文件的查找和文件的删除等。
File对象代表磁盘中实际存在的文件和目录。通过以下构造方法创建一个File对象。
-
常用构造方法
new File(File parent,String child ); new File(String parent,String child); new File(String pathName);
-
常用方法
| 方法名 | 描述 |
|---|---|
| String getName() | 获取文件(夹)名 |
| String getPath() | 获取文件(夹)路径 |
| boolean exists() | 文件(夹)是否存在 |
| boolean isFile() | 是否是一个文件 |
| boolean isDirectory() | 是否是一个目录(文件夹) |
| boolean createNewFile() | 创建一个文件 |
| boolean mkdir() | 创建一个具体的文件夹 |
| boolean mkdirs() | 创建多级文件夹 |
| boolean delete() | 删除某个文件(夹) |
| String [] list() | 返回某个文件夹下的所有文件(夹)名 |
| File [] listFiles() | 获取某个文件夹下所有的文件(夹) |
代码演示:
package yrh;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
public class FileTest {
public static void main(String[] args) throws IOException {
File file=new File("D:/fff.txt");
//输出文件是否存在
System.out.println(file.exists());
if (!file.exists()) {
//创建这个文件
file.createNewFile();
}
//判断是否是一个文件
System.out.println(file.isFile());
//是否是一个目录
System.out.println(file.isDirectory());
//获取文件的名字
System.out.println(file.getName());
//获取文件路径
System.out.println(file.getPath());
//删除此文件
file.delete();
//返回dir目录的所有文件,以string[]数组保存
File file2=new File("D:/dir");
file2.mkdir();
String[] list = file2.list();
System.out.println(Arrays.toString(list));
//返回dir目录的所有文件,以File[]数组保存
File[] listFiles = file2.listFiles();
for (File file3 : listFiles) {
System.out.println(file3);
}
//删除目录
file2.delete();
}
}
代码演示:
要求:将盘中的qq.exe(D:ablb.jpg) 通过程序复制到另一个路径下(D:bqq.exe)。
package yrh;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class TetsIO {
public static void main(String[] args) {
// TODO Auto-generated method stub
//要求:将盘中的qq.exe(D:ablb.jpg)
//通过程序复制到另一个路径下(D:bqq.exe)。
//创建输入输出流接口
InputStream fis=null;
OutputStream fos=null;
File f1=new File("d:/PCQQ2020.exe");
File f2=new File("d:/test/PCQQ2020.exe");
//创建目标文件
if (!f2.exists()) {
try {
f2.createNewFile();
//从f1读取文件流
fis=new FileInputStream(f1);
//写到f2输出流
fos=new FileOutputStream(f2);
//定义一个bety数组
byte buffer[]=new byte[2048];
int len=0;
//循环读写文件
while ((len=fis.read(buffer))!=-1) {
fos.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
}
//关闭流
finally{
if (fos!=null) {
try {
fos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (fis!=null) {
try {
fis.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
2文件读写
2.1文件读取
文件输入流FileInputStream
作用是:读取磁盘文件或网络的数据
FileInputStream(File file) FileInputStream(String filepath)
主要方法:
-
int read(byte[] buffer)读取文件数据,保存到字节数组中,返回值是读取长度-1代表读取完毕
-
void close() 关闭文件流
try-with-resource IO流使用完后必须关闭,否则文件流无法得到释放,close方法调用要写在finally中。 为简化关闭流的代码,Java1.7引入了try-with-resource语法,让资源在try-catch完毕后自动关闭。 语法:
try(类 对象 = new 类()){
可能出现异常的代码
}catch(异常类型 对象){
处理异常的代码
}
文件读取过程
-
创建文件输入流
-
创建byte数组
-
循环调用read方法,存入byte数组中
-
操作byte数组
-
读取完毕关闭文件流
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileInputStreamTest {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
// 1.创建文件输入流
String filepath="D:/ddd.txt";
InputStream input=new FileInputStream(filepath);
// 2.创建byte数组
byte b[]=new byte[1024];
// 3.循环调用read方法读取数据,存入byte数组
int len=0;
while ((len=input.read(b))!=-1) {
String str=new String(b,0,len,"UTF-8");
System.out.println(str);
}
// 4.操作byte数组
// 5.读取完毕关闭文件流
input.close();
}
}
2.2 文件写入
文件输出流 FileOutputStream
作用是 :将数据写入磁盘文件或网络
构造方法:
FileOutPutStream(File flie) FileOutPutStream(String fliepath)
主要方法:
-
write(byte[] buffer,int offset,int length) 写入文件,offset开始位置,length写入长度
-
write(byte[] buffer)
-
close() 关闭流
文件写入步骤
-
创建文件输出流
-
将字符串转换问byte数组
-
调用writer方法
-
关闭文件流
package yrh;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Scanner;
public class FileOutputStreamTest {
public static void main(String[] args) {
String filepath="d:/ccc.txt";
// 创建文件输出流
try {
OutputStream fos=new FileOutputStream(filepath);
Scanner in = new Scanner(System.in);
System.out.println("输入写入内容");
String txt=in.next();
// 将字符串转换为byte数组
//调用write写入文件
fos.write(txt.getBytes());
// 关闭文件流
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2.3文件的复制
文件的复制是在读取文件的同事,将数据写到另一个文件中
思路
-
创建文件输入输出流
-
通过文件输入流读取数据到byte数组中
-
同时将byte数组中的数据写入到输出流中
-
循环 1,2,3
package yrh;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Filecopy {
//文件复制
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//读取文件位置
String filepath="d:/ccc.txt";
//写入文件位置
String fileOut="d:/eee.txt";
// 1、创建输入流和输出流
InputStream fis=new FileInputStream(filepath);
OutputStream fos=new FileOutputStream(fileOut);
// 2、创建byte数组
byte buffer[]=new byte[2048];
int len=0;
//循环从输入流中读取数据
while ((len=fis.read(buffer))!=-1) {
//向输出流中写入数据
fos.write(buffer, 0, len);
}
//关闭文件流
//先使用的后关闭
fos.close();
fis.close();
System.out.println("复制完成");
}
}
3 缓冲
什么事缓冲
前提是内存的读写速度要远高于磁盘的读写速度,缓冲就是内存中的一块空间,通过缓冲可以提高数据的读写速度
JAVA的IO体系中有些流不能独立使用,必须套在其它流的上面才能使用,称为包装流。JAVA的IO体系就是通过装饰模式来实现。需要什么流的功能就在外面套一个对应的流即可,就像一个武士,需要一把武器就装饰一把武器,需要一身铠甲就套一层铠甲,这个武士就能使用武器跟铠甲的功能了。
而缓冲流就是常用的一个包装流,也叫高效流,是对4个基本的File 流的增强,所以也是4个流,按照数据类型分类:
-
字节缓冲流:BufferedInputStream,BufferedOutputStream
-
字符缓冲流:BufferedReader,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
为什么需要缓冲如果没有缓冲,文件读写是直接从磁盘上进行的,速度比较慢;缓冲就是在内存建立一个空间,读写之前将一部分磁盘上的数据导入到
缓冲内存中,后面读写就直接从缓冲中进行,减少了直接冲磁盘读写的次数,从而提高读写效率。
缓冲流:在普通的IO流基础上,加入内存缓冲区提高IO效率
字节缓冲流BufferdInputStream缓冲输入流
创建方法
new BufferedInputStream(InputStream in);
new BufferedInputStream(InputStream in,int bufferSize);创建一个`BufferedInputStream`并保存其参数,输入流`in`供以后使用。 内部缓冲区数组创建并存储在`buf` 。
创建一个BufferedInputStream并保存其参数,输入流in供以后使用。 内部缓冲区数组创建并存储在buf 。
创建具有BufferedInputStream缓冲区大小的BufferedInputStream,并保存其参数,输入流in供以后使用。 长度为size的内部缓冲区阵列被创建并存储在buf 。
参数
in - 底层输入流。
size - 缓冲区大小。
BufferdOutputStream 缓冲输入流
BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流。
使用非缓冲流和缓冲流进行文件复制的效率对比:
package yrh;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class BufferdInputStreamTest {
//字节缓冲流
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//读取文件位置
String filepath="d:/ccc.txt";
//写入文件位置
String fileOut="d:/eee.txt";
//程序开始时间
long start = System.currentTimeMillis();
System.out.println("使用文件缓冲流");
//创建缓冲文件输入输出流对象
InputStream fis=new BufferedInputStream(new FileInputStream(filepath));
OutputStream fos=new BufferedOutputStream(new FileOutputStream(fileOut));
//创建byte数组存放文件
byte buffer[]=new byte[2048];
int len=0;
//循环读取文件
while((len=fis.read(buffer))!=-1){
//向输出流写入文件
fos.write(buffer, 0, len);
}
//关闭文件流
fos.close();
fis.close();
System.out.println("复制完成");
long end = System.currentTimeMillis();
System.out.println("程序运行时间:"+(end-start)+"ms");
// System.out.println("不使用文件缓冲数据流");
// //程序开始时间
// long start = System.currentTimeMillis();
// //创建文件输入输出流对象
// InputStream fis=new FileInputStream(filepath);
// OutputStream fos=new FileOutputStream(fileOut);
// //创建byte数组存放文件
// byte buffer[]=new byte[2048];
// int len=0;
// //循环读取文件
// while ((len=fis.read(buffer))!=-1) {
// //向输出流写入文件
// fos.write(buffer, 0, len);
// }
// //关闭文件流
// fos.close();
// fis.close();
// System.out.println("复制完成");
// long end = System.currentTimeMillis();
// System.out.println("程序运行时间:"+(end-start)+"ms");
}
}
4 字符流
4.1 FileReader 字符输入流
以字符char为单位进行的流,适合操作文本数据
-
Reader 字符输入流的父类
-
Writer 字符输出流的父类
FileReader 文件读取器
创建方法:
FileReader(File file) 创建一个新的 FileReader ,给出 File读取。 FileReader(FileDescriptor fd) 创建一个新的 FileReader ,给定 FileDescriptor读取。 FileReader(String fileName) 创建一个新的 FileReader ,给定要读取的文件的名称。
主要方法
-
public void close() :关闭此流并释放与此流相关联的任何系统资源。
-
public int read(): 从输入流读取一个字符。
-
public int read(char[] cbuf): 从输入流中读取一些字符,并将它们存储到字符数组 cbuf中 。
代码演示:
要求:将文本文件中的内容读取到控制台中显示。
package test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class RederTest {
public static void main(String[] args) throws IOException {
//要求:将文本文件中的内容读取到控制台中显示。
//1,创建字符输入流
FileReader fReader=null;
try {
File f1=new File("d:/ccc.txt");
fReader=new FileReader(f1);
int len=0;
while ((len=fReader.read())!=-1) {
System.out.print((char)len);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally {
try {
// 关闭流
if (fReader != null) {
fReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
4.2 FileWriter 字符输出流
java.io.FileWriter抽象类是表示用于写出字符流的超类。构造时使用系统默认的字符编码和默认字节缓冲区。
-
void write(int c) 写入单个字符。
-
void write(char[] cbuf)写入字符数组。
-
abstract void write(char[] cbuf, int off, int len)写入字符数组的某一部分,off数组的开始索引,len写的字符个数。
-
void write(String str)写入字符串。
-
void write(String str, int off, int len) 写入字符串的某一部分,off字符串的开始索引,len写的字符个数。
-
void flush()刷新该流的缓冲。
-
void close() 关闭此流,但要先刷新它。
代码演示:
要求:将下面的一段话输入到D盘的文本文件中。
昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否,知否?应是绿肥红瘦。
package test;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class WriterTest {
public static void main(String[] args) throws IOException {
//要求:将下面的一段话输入到D盘的文本文件中。
//昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否,知否?应是绿肥红瘦。`
//创建文件输出流
FileWriter writer=null;
File f1=new File("D:/eee.txt");
//创建文件
if (!f1.exists()) {
f1.createNewFile();
}
//构造一个FileWriter对象,给出一个带有布尔值的文件名,表示是否附加写入的数据。
writer=new FileWriter(f1, true);
writer.write("昨夜雨疏风骤,浓睡不消残酒。试问卷帘人,却道海棠依旧。知否,知否?应是绿肥红瘦。");
writer.close();
}
}
5 对象流
5.1.1概述
Java 提供了一种对象序列化的机制。用来将某个对象保存到磁盘上或者-在网络上传输。可以理解为将内存中的对象进行持久化保存下来。反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。
JAVA中是通过对象流来实现对象的序列化跟反序列化的,对象流也是一种包装流。
5.1.2 序列化java.io.ObjectOutputStream 类,将Java对象的原始数据类型写出到文件,实现对象的持久存储。
被序列化的对象需要实现java.io.Serializable 接口。Serializable 是一个标记接口,不实现此接口的类将不会使任何状态序列化或反序列化,会抛出NotSerializableException 。
如果有不需要序列化的字段使用transient关键字修饰即可。
代码演示:
package pojo;
import java.io.Serializable;
//实体类
public class Person implements Serializable{
// 序列化版本号,必须保证序列化跟反序列化的版本号一致
private static final long seriaVersionUID=-1213754818242979380L;
public String name;
//设置age字段为transient,表示此字段不需要序列化
public transient int age=1;
public String sex;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", sex=" + sex + ", getClass()=" + getClass() + ", hashCode()="
+ hashCode() + ", toString()=" + super.toString() + "]";
}
}
序列化代码演示
package test;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import pojo.Person;
public class Demo12Serializable {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
//序列化
//saveObject();
//反序列化
readObject();
}
//序列化
public static void saveObject() throws IOException{
//准备序列化的对象
Person person=new Person();
person.name = "张三";
person.age = 18 ;
person.sex = "男";
//准备数据流
FileOutputStream fos=new FileOutputStream("d:/eee.txt");
ObjectOutputStream out=new ObjectOutputStream(fos);
//序列化对象
out.writeObject(person);
// 关闭流
out.close();
fos.close();
}
//反序列化
public static void readObject() throws IOException, ClassNotFoundException{
//准备对象流
FileInputStream fis=new FileInputStream("d:/eee.txt");
ObjectInputStream in=new ObjectInputStream(fis);
Person person = (Person) in.readObject();
System.out.println(person);
//关闭流
in.close();
fis.close();
}
}
重点
序列化的重点在于序列化跟反序列化的的版本号要一致,通常可以设置成固定值或者有IDE自动生成,这个版本号定义在实体类的属性private static final long serialVersionUID。如果版本号信息不一致会抛出InvalidClassException异常。1
5.3 properties属性集5.3.1 概述
前面学习过集合,集合家族中有个成员java.util.Properties ,它继承于Hashtable 。Properties是使用键值结构存储数据的,但它最大的特点是具有持久化功能。
5.3.2 常用API
-
public Properties() :创建一个空的属性列表。
-
public Object setProperty(String key, String value) : 保存一对属性。
-
public String getProperty(String key) :使用此属性列表中指定的键搜索属性值。
-
public Set
stringPropertyNames() :所有键的名称的集合。 -
public void load(InputStream inStream): 从字节输入流中读取键值对数据。
-
public void store(OutputStream out,String comments):从字节输入流中存储键值对数据。
代码演示
要求:往Properties中存储数据,并通过流写出到本地文件中。
package test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.util.Properties;
public class TestProperties {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
//创建对应属性文件
File file=new File("D:/yhr.properties");
if (!file.exists()) {
file.createNewFile();
}
//创建properties对象,存储文件
Properties p=new Properties();
p.setProperty("name", "易荣辉");
p.setProperty("age", "12");
p.setProperty("sex", "男");
//通过OutputStreamWriter包装一层流,可以解决乱码问题
FileOutputStream fos=new FileOutputStream(file);
OutputStreamWriter osw=new OutputStreamWriter(fos,"utf-8");
p.store(osw, "");
osw.close();
fos.close();
}
}
代码演示
要求:将Properties中的数据读取到程序中,遍历所有的数据。
package test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;
import java.util.Set;
public class Demo14Properties {
public static void main(String[] args) throws IOException {
//创建对应的属性文件
File file=new File("D:/yhr.properties");
//建立到文件直接的流
FileInputStream fis=new FileInputStream(file);
InputStreamReader read=new InputStreamReader(fis);
//通过流把配置文件中的数据加载到Propertis对象中
Properties properties=new Properties();
properties.load(read);
//关闭流
read.close();
fis.close();
//遍历
Set keys = properties.stringPropertyNames();
for (String string : keys) {
System.out.println(string+" = "+properties.getProperty(string));
}
}
}
tips:
-
properties文件中键值对之间的分割可以使用= :跟空格。
-
由于properties继承Hashtable,所有还可以通过枚举器来遍历。



