FileInputStream的listFile()方法提取文件中的所有文件是按照字符串顺序查询的,字符串对比是所有字符一个个往下面对比.注意下面文件的区别;
//文件中文件保存顺序 //lsitfile()方法拿出来的顺序
java.0 Java.0
Java.1 Java.1
java.2 Java.10
java.3 Java.11
java.10 Java.2
java.11 Java.13
java.23 Java.3
//先对比前面字符的顺序,在对比后边的,跟我们往常的比大小顺序有出入
一.IO流
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3T8y7aTM-1597570256549)(E:\照片\typora\image-20200703184715958.png)]
-
java对数据的操作是通过流的方式
-
Java用于操作流的类都在IO包中
-
IO流用来处理设备之间的数据传输
-
流按流向分为两种:输入流,输出流。I/O
-
流按操作类型分为两种:
-
字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的,一次读取一个字节
-
字符流 : 字符流只能操作纯字符数据,比较方便.一次读取两个字节,
-
下图为字节流和字符流的区别
-
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tAI7t5z9-1597570256552)(E:\照片\typora\image-20200703150505928.png)]
IO流常用父类
-
字节流的抽象父类:
-
InputStream
-
OutputStream
-
字符流的抽象父类:
- Reader
- Writer
-
-
IO使用前,要导包,且一定要进行异常处理,使用后一定要释放资源
二.FileInputStream和FileOutputSteam
1.定义
- 以字节的形式来读取文件内容
- InputStream抽象类的子类, 已经重写了read()方法;OutputStream抽象类的子类, 已经重写了write()方法
- 当构建的对象不存在是,不会自动创建(FileRead和FileWrite会),必须依靠文件创建方法和文件夹创建方法来创建.
- 使用这两个流时一定要记得关闭流,如果不关闭流,写入操作时,写入的数据只会储存在缓冲区,而不会在写入文件中.
2.FileInputStream
①构造方法
- FileInputStream(String name) : 根据字符串地址来连接到一个本地文件
- FileInputStream(File file) : 根据一个File类对象连接到一个本地文件
②常用方法
- read() : 从此输入流中读取一个数据字节
- read(byte[] b) : 从此输入流中将最多b.length个字节的数据读入一个byte数组中
- read(byte[] b,int off,int len) : 从此输入流中读取最多 len个字节的数据读入到一个byte[] 数组中
- close() : 关闭此输入流并释放与此流有关的所有系统资源
read()方法读取的是一个字节,为什么返回是int,而不是byte ?
因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111,那么11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
3.FileOutputStream
①构造方法
- FileOuputStream(String name) : 根据字符串地址来连接到一个本地文件
- FileOuputStream(File file) : 根据一个File类对象连接到一个本地文件
- FileOuputStream(File file,boolean append) : 在文件末尾继续写入;append为true时,表示在文件末尾继续写入;append默认为false,表示覆盖该文件重新写入;
②常用方法
- write(int b) : 将指定字节写入此文件输出流
- write(byte[] b) : 将b.length个字节从指定byte数组写入此文件输出流中
- write(byte[] b,int off, int len) : 将指定byte数组中从偏移量off开始的len个字节写入此文件输出量
- close() : 关闭输出流并释放与此流有关的所有系统资源
利用字节流赋值文件,一个个字节赋值会导致两个字节的字符出现编码错误.
//FileInputSteam和FileOutputSteam的api用法
public class InputAndOutPut {
public static void main(String[] args) throws IOException {
File file = new File("E://桌面//PDF//abc.txt");
//创建该文件的一个输入流对象
FileInputStream fileInputStream = new FileInputStream(file);
int read = fileInputStream.read();
//利用while循环把文件里面的东西
ArrayList<Character> chars = new ArrayList<Character>();
//从输入流中读取一个字节(如果返回-1,说明已经到了文件的末尾)
while (read != -1) {
//因为ASCII码中没有负数,所以当read为负数时,就代表这个文件中没有字节了.
System.out.print((char)read);
chars.add((char)read);
read = fileInputStream.read();
}
//创建另一个文件的输出流,如果这个文件不存在就创建一个;
File file1 = new File("E://桌面//PDF//add.txt");
if (!file1.exists()) {
file1.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(file1);
//把上面的文件内容写进这个文件中
for (int i = 0; i < chars.size(); i++) {
fileOutputStream.write((int)chars.get(i));
}
}
}
三.FileReader和FileWriter
1,都是字符流,字符输出流和字节输出流创建对象时,如果写入的文件参数不存在时,会自动创建这个文件,不需要手动调用方法来创建
-
定义
- 字符流是可以直接读写字符的IO流
- 字符流读取字符,就要先读取到字节数据, 然后转为字符,如果要写出字符,需要把字符转为字节在写出
-
实用性
- 如果是我们来对读取的字节进行转换的话,非常麻烦, 因为在储存的时候, 不同的文字占用的字节数是不同的, 就好像英文用1个字节,而中文用2个字节,对读取的内容解析就是非常痛苦的一键事情
- 不会出现读取到半个中文的情况
- java在字符流中给我们提供了许多非常实用的方法, 比如一次读取文本的一行写出的时候可以将文本直接写入到本地文件,不需要转化为字节数组
-
使用
- 当程序需要跟文本进行交互的时候,推荐使用
- 当我们进行copy操作的时候, 无论是拷贝纯文本还是非文本极不推荐,非常有可以能出现乱码, 而且, 读取时字符流会有将字节转换成字符的动作,写入是会有讲字符转换成字节的动作,会降低性能
2.FileReader
-
定义
- 字符输入流, 底层使用的还是字节流
-
构造方法
- FileReader(String fileName) : 根据字符串路径和文件获取连接
- FileReader(File file) : 根据File对象和文件获取连接
-
常用方法
- int read() : 读取单个字符
- int read(char[] cbuf) : 将字符读入数组
- void close() : 关闭该流并释放资源
public class TestFileRead {
public static void main(String[] args) throws IOException {
FileReader fileReader = new FileReader("E://桌面//PDF//abc.txt");
//读取文件中的字符放入chars数组中
char[] chars = new char[500];
int num;
int i = 0;
while ((num = fileReader.read()) != -1) {
System.out.print((char)num);
chars[i++] = (char)num;
}
FileWriter fileWriter = new FileWriter("E://桌面//PDF//add5.tst");
//写入时可以直接写入一个字符串和字符数组;
fileWriter.write(chars);
//记得一定要关闭数组
fileWriter.close();
}
}
3.FileWriter
-
定义
- 字符输出流, 将字符写入到文件中,可以直接写入字符串
- 字符输出流中是有缓冲区的
-
构造方法
- FileWriter(String fileName) : 根据字符串路径和文件获取连接
- FileWriter(File file) : 根据File对象和文件获取连接
- FileWriter(File file , boolean append) : 根据File对象和文件获取连接, 让流可以从尾部写入,append=true
-
常用方法
- append(char c) : 将指定字符写入到此writer, 功能等同于write()
- write(char c) : 写入单个字符
- write(char[] cbuf, int off, int len) : 写入字符数组的某一部分
- write(String str) : 写入字符串
- write(String str, int off , int len) : 写入字符串的一部分
- flush() : 刷新流
四.BufferedInputStream和BufferedOutputStream
-
定义
- 字节输入缓冲流和字节输出缓冲流实际上是先从硬盘中把文件放在内存中缓存,然后在进行输入和输出操作
- 我们都知道单个字节的读取是效率非常低下的, 所以我们使用了小数组的方法进行流的读取和写入
- java中已经帮我们实现了, 这就是缓冲区的概念, 也是一次性读取一个数组,然后将这个数组放入内存中供我们使用
- 缓冲流只是一个壳,实际还是字节流在工作
2.BufferedInputStream字节输入缓冲流
①常用方法
-
read() : 一次读取一个字节
-
read(byte[] b, int off, int len) : 从此字节输入流中给定偏移量处开始各字节读取到指定的byte数组中
int i = 0; byte[] nums = new byte[1024]; //写入到一个1024个字节的数组中,也就是1kb while ( fileinputStream.read(nums) != -1) { if (i % 500 == 0) { filewriter = new FileOutputStream(new File("E://桌面//12//yinyue.mp" + i)); } //一次性写入一个byte数组的内容; filewriter.write(nums); filewriter.flush(); i++; }
-
close() : 关闭并释放资源,实际关闭的是内部真正工作的字节流
③注意事项
- BufferedInputStream内部建立一个缓冲区域,在读取文件的时候, 一次性读取大量的字节, 缓冲到缓冲区当中, 然后再反给我们, 看着没有变化, 区别在于一个直接操作硬盘, 一个是操作内存, 效率不可相提并论
3BufferedOutputStream字节输出缓冲流
-
定义
- 字符输出流, 将字符写入到文件中,可以直接写入字符串
- 字符输出流中是有缓冲区的
-
构造方法
- FileWriter(String fileName) : 根据字符串路径和文件获取连接
- FileWriter(File file) : 根据File对象和文件获取连接
- FileWriter(File file , boolean append) : 根据File对象和文件获取连接, 让流可以从尾部写入
-
常用方法
File.separator;
//File.separator:根据操作系统去获取文件夹分隔符;
//window返回 \字符串; linux 返回 / 字符串
E: + File.separator + a.tet;//等价于E://a.tet
public class Task2plus {
public static void main(String[] args) throws IOException {
System.out.println(File.separator);
String str = "E:" + File.separator + "桌面//12//yinyue.mp8000";
File file = new File(str);
System.out.println(file.exists());
System.out.println(file.getAbsoluteFile());
//创建一个缓冲输入字节流
FileInputStream fileInputStream = new FileInputStream(file);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
//创建一个缓冲输出字节流
FileOutputStream fileOutputStream = new FileOutputStream(new File("E://桌面//新建"));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
//利用流进行赋值操作
byte[] bytes = new byte[1024];
while (bufferedInputStream.read(bytes) != -1) {
bufferedOutputStream.write(bytes);
}
//关闭流
bufferedInputStream.close();
bufferedOutputStream.close();
}
}
拓展作业
/**
* 把文件进行拆分之后然后合并还原
*/
public class Task2 {
public static void main(String[] args) throws IOException {
//把一个文件进行拆分的操作
File file = new File("E://桌面//PDF//ALALAMO.mp3");
FileInputStream fileinputStream = new FileInputStream(file);
int num;
FileOutputStream filewriter = null;
int i = 0;
byte[] nums = new byte[1024];
while ( fileinputStream.read(nums) != -1) {
if (i % 500 == 0) {
filewriter = new FileOutputStream(new File("E://桌面//12//yinyue.mp" + i));
}
filewriter.write(nums);
filewriter.flush();
i++;
}
filewriter.close();
fileinputStream.close();
//把上面拆分的文件进行合并的操作
File file1 = new File("E://桌面//12");
File[] files = file1.listFiles();
byte[] baocun = new byte[1024];
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = new FileOutputStream("E://桌面//复制.mp3");
for (File file2 : files) {
System.out.println(file2);
fileInputStream = new FileInputStream(file2);
while (fileInputStream.read(baocun) != -1) {
fileOutputStream.write(baocun);
}
fileOutputStream.flush();
fileInputStream.close();
}
fileOutputStream.close();
}
}
五.对象操作流(序列化流)
-
定义
-
该流可以将一个对象写出, 或者读取一个对象到程序中. 也就是执行了序列化和反序列化的操作
-
//1: java里面 要对磁盘进行操作; 读取和写入内容 //2: 内容 遵循java里面的一种规范(标准) //3: 标准 : Serializable[序列化] //4: 程序写入一个对象到磁盘 ; 对象必须做序列化 ; 实现Serializable接口; //5: 从磁盘读取一个对象到程序; 对象做反序列化; 实现Serializable接口;
-
可以将集合中的对象一次性写入本地
-
写入本地的对象必须实现Serializable接口
-
-
分类
- ObjecOutputStream 将对象写入到本地
- ObjectInputStream 从本地读取文件生成对象
package com.qianfeng.www.day19;
import javax.management.ObjectInstance;
import java.io.*;
public class TestObjInput {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建一个对象输入输出流,必须传入一个字节输入输出流参数;
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:\\桌面\\abc.txt"));
ObjectOutputStream objectoutputStream = new ObjectOutputStream(new FileOutputStream("E:\\桌面\\ab\\bc.txt"));
//直接把读入的文件对象写入一个新的文件中,然后关闭流
objectoutputStream.writeObject(objectInputStream.readObject());
objectInputStream.close();
objectoutputStream.close();
}
}
package com.qianfeng.www.day19;
import javax.management.ObjectInstance;
import java.io.*;
public class TestObjOutput {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//写入一个字符串文件对象,字符串文件对象已经序列化过了(实现了Serializable接口)
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("E:\\桌面\\abc.txt"));
String str = "你好";
objectOutputStream.writeObject(str);
objectOutputStream.close();
//读刚刚写入的对象
ObjectInputStream objectinputStream = new ObjectInputStream(new FileInputStream("E:\\桌面\\abc.txt"));
System.out.println(objectinputStream.readObject());
}
}
3.自己定义一个类实现serializable接口,使用对象输出输入流.
package com.qianfeng.www.day19;
import java.io.*;
public class TestObjectSelf {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ps ps = new ps();
ps.setAge(12);
ps.setName("大仙");
//把创建的对象用对象流写入文件中,写入的对象已经序列化才行
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("E:\\桌面\\abc.txt"));
objectOutputStream.writeObject(ps);
//读刚刚写入的对象
ObjectInputStream objectinputStream = new ObjectInputStream(new FileInputStream("E:\\桌面\\abc.txt"));
System.out.println(objectinputStream.readObject());
}
}
//自定义的对象必须序列化
class ps implements Serializable {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "ps{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
列化
class ps implements Serializable {
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "ps{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}