一、IO流架构图
字节流可以处理各种文件。包括图片、视频、音频等。
字符流专门用于处理字符文件,处理字符效率比字节流高。
二、IO操作步骤
- 建立联系 :这一步骤是为了获取流,如果此时是文件,则需要将文件抽象到内存形成对象。后期也可以是其他的数据源
- 选择流:从读写、数据单元和功能方面考虑。输入|输出,字节|字符,结点流|处理流。
- 执行操作:该读就读,该写就写。考虑是一次性完成还行需要循环。
- 释放资源:程序中打开的文件 IO 资源不属于内存中的资源,垃圾回收无法回收,需要显示关闭。
三、 基本输入流
字节流可以操作所有文件,字符流仅操作纯文本。
1.抽象类:InputStream 和 Reader
InputStream和Reader是所有输入流的基类,它们是两个抽象类,是所有输入流的模版,其中定义的方法在所有输入流中都可以使用。
在InputStream种常用如下几个方法:
在Reader中常用如下几个方法
[1]FileReader(字符输入流)的使用
//创建指定文件对象
File file=new File("F:\\iCode\\sxt\\day11\\src\\a.txt");
//通过文件对象创建一个FileReader对象
Reader r=new FileReader(file);
int i=0;
//使用Reader 对象的read()方法对字符进行读取,返回一个int类型的数据。若返回数据为-1,则说明文件中的内容已经读取完毕
while ((i=r.read())!=-1){
//将int类型的数据转换为char型并打印出来
System.out.print((char) i);
}
r.close();
使用数组进行缓存,先把文件内容读取至指定大小的数组,再将数组中的数据取出
//指定数据源
String path="F:\\iCode\\sxt\\day11\\src\\a.txt";
//选择流
FileReader reader = new FileReader(path);
char[] car=new char[5];
//读取
int len=0;
//reader.read(car)) 将读取到的数据存储到指定的数组car中,返回本次读取字符串的长度
while ((len=reader.read(car))!=-1){
//通过new String(数组,开始位置,偏移量)来获得字符串
System.out.println(new String(car,0,len));
}
//关闭数据源
reader.close();
[2]FileInputStream(字节输入流)的使用
//确定数据源
File file=new File("F:\\iCode\\sxt\\day11\\src\\a.txt");
byte[] car=new byte[3];
FileInputStream fis=null;
try {
//选择流
fis = new FileInputStream(file);
//读取
int len = fis.read(car);
System.out.println(len+"实际读取到的字节数");
String s=new String(car,0,len);
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
//关闭流
if (fis!=null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
2.抽象类OutputStream 和 Writer
用于将数据从Java内存输出到其他的防的流,称为输出流,有字符也有字节。也都类似,有两个抽象类OutputStream,Writer。OutputStream和Writer也非常相似。
在OutputStream 中常用如下方法:
在 Writer 中, 因为字符流直接以字符作为操作单位,所以 Writer 可以用字符串来代替字符数组,即以String对象来作为参数。 常用如下方法:
[1]FileWriter(字符输出流)的使用
//确定目标
String path="src\\b.txt";
//选择流
FileWriter writer=new FileWriter(path);
//写
char[] car={'n','i','c','e'};
writer.write(car);
String str=" to meet you.";
writer.write(str);
//刷新
writer.flush();
//关闭资源
writer.close();
[2]FileOutputStream(字节输出流)的使用
通过字节流完成图片的拷贝
//确定源数据
String source="C:\\Users\\asus\\Desktop\\picture\\email.png";
//确定目标文件
String target="src\\copy.png";
//选择流
InputStream is=new FileInputStream(source);
OutputStream os=new FileOutputStream(target);
byte[] car=new byte[1024];
int len=-1;
//边读
while (((len=is.read(car))!=-1)){
//边写
os.write(car,0,len);
}
os.flush();
//关闭流
is.close();
os.close();
四、缓冲处理流
BufferedInputStream和 BufferedReader
缓冲提高性能: 字节流缓冲流直接套在节点流上即可使用;字符缓冲流 +新增方法(不能使用多态):
1.BufferedReader
//确定源数据
String path="src\\c.txt";
//选择流
BufferedReader br=new BufferedReader(new FileReader(path));
//读取
String str=null;
while ((str=br.readLine())!=null) {
System.out.println(str);
}
//关闭流
br.close();
2.BufferedWriter
//确定目标文件
File file=new File("src\\d.txt");
//选择流
BufferedWriter bw=new BufferedWriter(new FileWriter(file));
//写
String str="谏逐客书\n" +
"先秦:李斯\n" +
"\n" +
" 臣闻吏议逐客,窃以为过矣。昔缪公求士,西取由余于戎,东得百里奚于宛,迎蹇叔于宋,来丕豹、公孙支于晋。此五子者,不产于秦,而缪公用之,并国二十,遂霸西戎。孝公用商鞅之法,移风易俗,民以殷盛,国以富强,百姓乐用,诸侯亲服,获楚、魏之师,举地千里,至今治强。惠王用张仪之计,拔三川之地,西并巴、蜀,北收上郡,南取汉中,包九夷,制鄢、郢,东据成皋之险,割膏腴之壤,遂散六国之从,使之西面事秦,功施到今。昭王得范雎,废穰侯,逐华阳,强公室,杜私门,蚕食诸侯,使秦成帝业。此四君者,皆以客之功。由此观之,客何负于秦哉!向使四君却客而不内,疏士而不用,是使国无富利之实而秦无强大之名也。\n" +
"\n" +
" 今陛下致昆山之玉,有随、和之宝,垂明月之珠,服太阿之剑,乘纤离之马,建翠凤之旗,树灵鼍之鼓。此数宝者,秦不生一焉,而陛下说之,何也?必秦国之所生然后可,则是夜光之璧不饰朝廷,犀象之器不为玩好,郑、卫之女不充后宫,而骏良駃騠不实外厩,江南金锡不为用,西蜀丹青不为采。所以饰后宫,充下陈,娱心意,说耳目者,必出于秦然后可,则是宛珠之簪、傅玑之珥、阿缟之衣、锦绣之饰不进于前,而随俗雅化佳冶窈窕赵女不立于侧也。夫击瓮叩缶,弹筝搏髀,而歌呼呜呜快耳目者,真秦之声也;《郑》《卫》《桑间》《昭》《虞》《武》《象》者,异国之乐也。今弃击瓮叩缶而就《郑》《卫》,退弹筝而取《昭》《虞》,若是者何也?快意当前,适观而已矣。今取人则不然,不问可否,不论曲直,非秦者去,为客者逐。然则是所重者在乎色、乐、珠玉,而所轻者在乎人民也。此非所以跨海内、制诸侯之术也。\n" +
"\n" +
" 臣闻地广者粟多,国大者人众,兵强则士勇。是以太山不让土壤,故能成其大;河海不择细流,故能就其深;王者不却众庶,故能明其德。是以地无四方,民无异国,四时充美,鬼神降福,此五帝三王之所以无敌也。今乃弃黔首以资敌国,却宾客以业诸侯,使天下之士退而不敢西向,裹足不入秦,此所谓“藉寇兵而赍盗粮”者也。\n" +
"\n" +
" 夫物不产于秦,可宝者多;士不产于秦,而愿忠者众。今逐客以资敌国,损民以益仇,内自虚而外树怨于诸侯,求国无危,不可得也。";
bw.write(str);
bw.flush();
//关闭流
bw.close();
3.BufferedInputStream
4.BufferedOutputStream
构造器 |
---|
BufferedOutputStream(OutputStream) 创建使用默认大小的输出缓冲区的缓冲字节输出流 |
BufferedOutputStream(OutputStream,int) 创建使用指定大小的输出缓冲区的缓冲字节输出流 |
方法
返回值类型 | 方法描述 |
---|---|
int | write(int b)写一个int类型的字符到文件中 |
int | write(byte[])将一个字节类型的数组写到文件中 |
int | write(byte[],int ,int ) 将字节类型的数组写到文件中,指定开始位置和结束位置 |
void | flush() 刷新输出到文件中的内容 |
void | close()关闭流并释放与之相关的系统资源 |
使用缓冲流进行文件拷贝
/**
* 使用缓冲流拷贝文件
*/
public class Demo010 {
public static void main(String[] args) throws Exception {
//确定源文件
String source="D:\\winTools\\feiGe\\repository\\第三周\\day10\\day15录像\\006ArrayList.mp4";
//确定目标文件
String target="E:\\arrayList.mp4";
//选择流
BufferedInputStream bis=new BufferedInputStream(new FileInputStream(source));
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream(target));
byte[] car=new byte[10*1024];
int len=-1;
//边读
while (((len = bis.read(car)) != -1)) {
//边写
bos.write(car,0,len);
}
bis.close();
bos.close();
}
}
5.文件夹的复制
public class Test {
public static void main(String[] args) {
//确定源文件
File source=new File("D:\\winTools\\feiGe\\repository\\第三周\\day10");
//确定目标文件
File target=new File("E:\\设计模式");
//拷贝文件
copyDirectory(source,target);
}
//拷贝文件
static void copy(File source,File target){
//缓冲流
BufferedInputStream bis=null;
BufferedOutputStream bos=null;
try {
bis=new BufferedInputStream(new FileInputStream(source));
bos=new BufferedOutputStream(new FileOutputStream(target));
//创建一个大小为10M的byte类型的缓存数组
byte[] car=new byte[10*1024];
int len=-1;
//读 一次读取大小为10M的字节,存入car数组中
while ((len= bis.read(car))!=-1){
//写
bos.write(car,0,len);
}
//刷新
bos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if (bis!=null){
bis.close();
}
if (bos!=null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
static void copyDirectory(File sourceDir,File targetDir){
//若目标文件夹不存在,则创建
if (!targetDir.exists()){
targetDir.mkdir();
}
//获得源文件目录下的所有子文件[夹]
File[] files = sourceDir.listFiles();
//遍历文件数组
for (File file:files){
//如果是文件
if (file.isFile()){
//调用复制文件的方法,文件名为当前目录+\\+文件名,拷贝至目标文件夹+\\+文件名
copy(new File(sourceDir+"\\"+file.getName()),new File(targetDir+"\\"+file.getName()));
}else {//如果是文件夹
//使用递归,参数为 当前文件夹+\\+子文件夹
copyDirectory(new File(sourceDir+"\\"+file.getName()),new File(targetDir+"\\"+file.getName()));
}
}
}
}
五、转换处理流
1.处理转换流InputStreamReader
转换流:将字节流转为字符流 处理乱码(编码集、解码集)
将文件按照指定字符编码格式读取
Reader reader = new InputStreamReader(new FileInputStream("src\\a.txt"), "gbk");
char read =(char) reader.read();
System.out.println(read);
reader.close();
2.数据处理流:DataInputStream
可以处理基本类型和String类型,保留数据的类型。前提是读取顺序与写出顺序一致,否则读取数据不正确。
将数据保存至文件,并且会保存文件的数据类型
//确定文件
File file=new File("a.txt");
//确定流
DataOutputStream dos=new DataOutputStream(new FileOutputStream(file));
//写
//dos.writeInt(123);
dos.writeBoolean(false);
dos.flush();
//关闭流
dos.close();
六、对象流
以前我们学过的流都只能读写字节,字符形式的数据,而java中非常重要并且常见的对象类型的数据,如果想要存储到文件中应该怎么操作呢?这个时候就使用到了对象流。
序列化: 是一个用于将对象状态转换为字节流的过程,可以将其保存到磁盘文件中或通过网络发送到任何其他程序
反序列化: 从字节流创建对象的相反的过程称为 反序列化
实体类
//实现了Serializable接口表名该类可以被序列化
public class Student implements Serializable {
private String name;
private int age;
//使用了transient关键字的属性不能被序列化
private transient boolean gender;
public Student(String name, int age, boolean gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public Student() {
}
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;
}
public boolean isGender() {
return gender;
}
public void setGender(boolean gender) {
this.gender = gender;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", gender=" + gender +
'}';
}
}
/**
* 对象输出流
*/
public class Demo004 {
public static void main(String[] args) throws Exception{
//目标文件
File file=new File("a.txt");
//选择流
ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(file));
//输出
Student student=new Student("张三",19,true);
oos.writeObject(student);
//关闭流
oos.close();
}
}
/**
* 对象输入流
*/
public class Demo005 {
public static void main(String[] args) throws Exception{
//确定数据源
File file=new File("a.txt");
//确定输入流
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(file));
//读
Object o = ois.readObject();
System.out.println(o);
//关闭流
ois.close();
}
}
七、Commons-io
CommonsIO 是apache的一个开源的工具包,封装了IO操作的相关类,使用Commons IO可以很方便的读写文件,url源代码等。commons-IO 需要加入classpath 的第三方jar 包内的 class 文件才能在项目中使用。
//拷贝文件
IOUtils.copy(new FileInputStream("a.txt"),new FileOutputStream("b.txt"));
//这个方法适合拷贝较大的数据流,比如2G以上
IOUtils.copyLarge(new FileReader("a.txt"),new FileWriter("c.txt"));
//去除目录和后缀后的文件名
System.out.println(FilenameUtils.getBaseName("a.txt"));
// 获取文件的后缀
System.out.println(FilenameUtils.getExtension("a.txt"));
//复制文件夹
FileUtils.copyDirectory(new File("out"),new File("E:\\"));
//复制文件
FileUtils.copyFile(new File("a.txt"),new File("d.txt"));
//把字符串写入文件
FileUtils.writeStringToFile(new File("a.txt"),"长太息以掩涕兮","utf-8");
//将文件中的内容读取至字符串
System.out.println(FileUtils.readFileToString(new File("a.txt"), "utf-8"));
//查看磁盘可用的空间 System.out.println(FileSystemUtils.freeSpaceKb()/1024/1024);