目录
1.字节流 FileInputStream FileOutputStream
2.BufferedInputStream BufferedoutputStream
3.BufferedReader BufferedWriter
2.objectInputStream objectOutputStream
六,InputStreamReader OutputStreamWrite
一,文件 File
1.创建文件的三种方式
(1)根据路径创建文件:创建File对象,传入文件路径,调用createNewFile方法(会抛出IOException异常),注意:file对象被创建出后首先被保存在内存中,调用方法createNewFile后才会被写到硬盘中。
public static void create01() throws IOException {
String filePath = "E:\\FileTest\\news1.txt";
File file = new File(filePath); //根据路径创建文件
file.createNewFile(); //createNewFlie()创建新文件,抛出IOException异常
}
(2)根据父目录文件加子路径创建文件: 创建File对象,传入父目录文件和子路径,调用createNewFile方法。
public static void create02() throws IOException{
File parent = new File("E:\\FileTest\\");
String child = "news2.txt";
File file = new File(parent, child); //根据父目录文件加子路径创建
file.createNewFile();
}
(3)根据父路径加子路径创建文件:创建File对象,传入父路径和子路径,调用createNewFile方法。
public static void create03() throws IOException{
String parent = "E:\\FileTest\\";
String child = "news3.txt";
File file = new File(parent, child); //根据父目录和子路径创建文件
file.createNewFile();
}
2.获取文件信息的操作
getName | 获取文件名称 |
getAbsolutePath | 获取文件绝对路径 |
getparent | 获取文件父路径 |
length | 获取文件大小,按字节算 |
exists | 文件是否存在 |
isFile | 是否是一个文件 |
isDirectory | 是否是一个目录 |
delete | 删除文件 |
3.目录操作
创建目录有两种方式:mkdirs()创建多级目录,mkdir()创建单级目录。 创建成功会返回True。
package Text_Streams.File;
import java.io.File;
public class Directory {
public static void main(String[] args) {
String directoryPath = "E:\\FileTest\\Demo\\a";
File file = new File(directoryPath);
if(file.mkdirs()){ //mkdirs创建多级目录,mkdir创建单级目录
System.out.println(file.getName() + "创建成功!");
}
else System.out.println(file.getName() + "创建失败!");
}
}
二,io流原理
io流即 input 流(输入流)和 output 流(输出流)。输入流指读取外部数据(外部存储设备中的数据)到程序(内存)当中,输出流指将程序(内存)中的数据输出到外部存储设备中。
1.流的分类
- 按操作数据单位不同分为:字节流和字符流;
- 按数据流的流向不同分为:输入流和输出流;
- 按流的角色不同分为:节点流和处理流(包装流);
Java IO流的四个抽象基类如下,Java IO流都是从这四个基类派生出的,由这四个类派生出的子类名称都是以其父类名称作为子类名后缀,例如:FileInputStream就是字节输入流,FileWrite就是字符输出流。
(抽象基类) | 字节流 | 字符流 |
输入流 | InputStream | Reader |
输出流 | OutputStream | Writer |
三,节点流
1.字节流 FileInputStream FileOutputStream
字节流读取文件时按字节单位读取,适合用于读取二进制文件如:图片,音乐,视频等。
(1)FileInputStream用read()方法读取文件,以int形式返回读取内容,读取结束时返回-1,具体操作步骤如下:
- 创建FileInputStream对象,传入文件路径或文件对象;
- 调用read方法读取文件,read方法抛出IO异常;
- 读取结束后关闭输入流,避免资源浪费;
public static void readFile() throws IOException {
int fileRead = 0;
String filePath = "E:\\FileTest\\news1.txt";
File file = new File(filePath);
FileInputStream fileInputStream = new FileInputStream(file); //创建FileInoutStream对象,读取文件(从硬盘到内存)
while((fileRead = fileInputStream.read()) != -1){ //read方法按字节读取,读取结束时返回-1
System.out.print((char)fileRead); //read返回ascall码,需强转为char
}
fileInputStream.close(); //读取结束后要关掉输入流,以防资源浪费
}
read方法默认一个字节一个字节读取,在调用read方法时,可以在read中传入一个字节数组,这样输入流每次读取时可以最多读取数组长度个字节到数组中,并返回实际读取到的字节数。
public static void readFile1() throws IOException {
byte by[] = new byte[8];
int fileLength = 0;
String filePath = "E:\\FileTest\\news1.txt";
FileInputStream fileInputStream = new FileInputStream(filePath); //创建FileInoutStream对象,读取文件(从硬盘到内存)
while((fileLength = fileInputStream.read(by)) != -1){ //从该输入流读取最多by.length个字节到by中,返回实际读取到的字节数
System.out.print(new String(by, 0, fileLength)); //字符串方法,将数组中指定范围的字节内容转化为字符串
}
fileInputStream.close(); //读取结束后要关掉输入流,以防资源浪费
}
(2)FileOutputStram用write()方法输出数据,操作步骤如下:
- 创建FileOutputStram对象,传入文件路径或文件对象;
- 调用write方法,有三种写入方式:写入一个字节,写入字节数组中全部内容,写入字节数组中指定范围的内容;
- 关闭输出流;
public static void writeFile() throws IOException {
String filePath = "E:\\FileTest\\news4.txt";
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
String str = "ysqdysqd";
fileOutputStream.write('y'); //1.写入一个字节
fileOutputStream.write(str.getBytes()); //2.写入字符串,getBytes将字符串转换为字节数组
fileOutputStream.write(str.getBytes(), 0, 4); //3.从off开始,将字节数组中长度为len的字节输出
fileOutputStream.close();
}
FileOutputStream默认将文件原有内容全部覆盖,在创建对象时,可以将append值设为true,这样写入内容会追加到原有内容之后。
new FileOutputStream(filePath); 直接覆盖原来的内容
new FileOutputStream(filePath,true); 将append置为true,写入的内容会追加到原有内容之后
(3)实现文件拷贝:复制硬盘中的内容,可以开启输入流将指定文件读取到内存中,然后再开启输出流将数据重新输出到硬盘中,具体操作如下:
public static void copy() throws IOException{
String filePath = "E:\\FileTest\\learn.jpg";
String filePath2 = "E:\\FileTest\\learn1.jpg";
FileInputStream fileInputStream = new FileInputStream(filePath);
FileOutputStream fileOutputStream = new FileOutputStream(filePath2);
int len;
byte by[] = new byte[1024];
while((len = fileInputStream.read(by)) != -1){
fileOutputStream.write(by, 0, len);
}
if(fileOutputStream != null)fileOutputStream.close();
if(fileInputStream != null)fileInputStream.close();
}
运行成功,没有问题。
2.字符流 FileReader FileWriter
在操作文本文件时,适合用字符流,字符流FileReader和FileWriter的操作方法与字节流FileInputStream和FileOutputStream基本一致,这里直接用文件拷贝代码来举例它们的用法。
public static void fileRead() throws IOException {
String filePath = "E:\\FileTest\\news1.txt";
String filePath1 = "E:\\FileTest\\news5.txt";
File file = new File(filePath);
FileReader fileReader = new FileReader(file);
FileWriter fileWriter = new FileWriter(filePath1, true);
int reader;
char ch[] = new char[8];
while((reader = fileReader.read(ch)) != -1)
{
fileWriter.write(ch, 0, reader);
}
if(fileReader != null)fileReader.close();
fileWriter.flush(); //字符输出流结束时需要刷新,否则可能会输出失败
if(fileWriter != null)fileWriter.close();
}
四,处理流
1.节点流和处理流的区别
- 节点流从一个特定的数据源读取数据,如FileReader,FileWrite等;
- 处理流(也叫包装流),“连接”在已有的流(节点流或处理流)之上,提供更为强大的读写功能。
总的来说,节点流是一种低级流,直接与数据源接触。处理流包装了节点流,即消除了不同节点流之间的实现差异,也可以提供更方便的方法来完成输入输出,此外,处理流不会与数据源直接接触。举例说明:
public BufferedInputStream(InputStream in, int size) {
super(in); //封装了一个InputStream对象
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];
}
从处理流BufferedInputStream的构造方法可以看出,其中封装了一个InputStream的对象,使用时可以根据传入的InputStream向下转型,也就是“消除了不同节点流之间的实现差异”,此外也可以重新包装原有的方法,也就是”提供更为强大的读写功能“。
2.BufferedInputStream BufferedoutputStream
BufferedInputStream和BufferedoutputStream是包装字节流的处理流,使用步骤如下:
- 实例化一个字节流对象;
- 将字节流对象包装到处理流当中;
- 进行读写操作;
- 关闭外部流;
处理流的读写方式与包装的流读写方法一致,需要注意的是,关闭IO流时关闭外部流,也就是处理流即可,因为底层会自动关闭节点流,代码示例如下:
public static void copy() throws IOException {
String filePath = "E:\\FileTest\\learn2.jpg";
String filePath1 = "E:\\FileTest\\learn3.jpg";
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath1));
byte by[] = new byte[8];
int len;
while((len = bufferedInputStream.read(by)) != -1){
bufferedOutputStream.write(by, 0, len);
}
bufferedInputStream.close(); //关闭外部流即可
bufferedOutputStream.flush(); //输出流记得刷新
bufferedOutputStream.close();
}
3.BufferedReader BufferedWriter
包装字符流的处理流,使用步骤与上述两个处理流一致:
- 实例化一个字符流对象;
- 将字符流对象包装到处理流当中;
- 进行读写操作;
- 关闭外部流;
public static void read1() throws IOException {
String filePath = "E:\\FileTest\\news5.txt";
BufferedReader bufferedReader = new BufferedReader(new FileReader(filePath));
String len;
while((len = bufferedReader.readLine()) != null){ //readLine读取结束返回null
System.out.println(len);
}
bufferedReader.close();
}
public static void write1() throws IOException{
String filePath = "E:\\FileTest\\news5.txt";
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filePath, true));
String str = "原神启动!";
bufferedWriter.write(str);
bufferedWriter.newLine(); //插入换行符
bufferedWriter.close();
}
五,对象处理流
在上面的操作中,我们保存的只是单纯的文字,图片之类的数据,假如我保存了一个数据100,我怎么知道这个数据是字符串还是整型数字呢?这时,我们就需要同时保存数据和数据的类型。对于这样的需求,我们就需要用到序列化和反序列技术。
1.序列化和反序列化
- 序列化就是在保存数据时,同时保存数据的值和数据类型;
- 反序列化就是在恢复数据时,同时恢复数据的值和数据类型;
- 需要让某个对象支持序列化机制,必须实现这连个接口之一:Serializable,Externalizable;
2.objectInputStream objectOutputStream
对象流objectInputStream和objectOutputStream可以用来实现序列化和反序列化,操作如下:
//序列化
public static void write() throws IOException {
String filePath = "E:\\FileTest\\news6.txt";
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(filePath));
objectOutputStream.writeInt(100); //自动装箱 int -> Integer Integer实现了Serializable
objectOutputStream.writeBoolean(true);
objectOutputStream.writeChar('s');
objectOutputStream.writeObject(new Dog("神里凌华的狗", 250)); //对象序列化
objectOutputStream.writeUTF("原神启动!");
objectOutputStream.close();
}
//反序列化
public static void read1() throws IOException, ClassNotFoundException {
String filePath = "E:\\FileTest\\news6.txt";
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filePath));
//读取(反序列化)的时候要与保存数据(序列化)的顺序一样
System.out.println(objectInputStream.readInt());
System.out.println(objectInputStream.readBoolean());
System.out.println(objectInputStream.readChar());
Object dog = objectInputStream.readObject();
System.out.println(dog.toString());
System.out.println(objectInputStream.readUTF());
objectInputStream.close();
}
注意:
- 读取(反序列化)时要与保存数据(序列化)的顺序一致;
- 序列化对象时,对象里面属性的类型也要实现序列化接口,基本数据类型如int型数据会被自动装箱成Integer,Integer实现了序列化接口;
- 序列化具有可继承性,若某类实现了序列化,那他的子类默认实现序列化;
- 被transient修饰的字段不会被序列化;
3. serialVersionUID
serialVersionUID是在序列化与反序列化过程中用于检验的版本号,在序列化时,会将对象的serialVersionUID写入到字节序列中,反序列化时会检查接收方对象的serialVersionUID是否与序列化时写入的一致,如果一致则反序列化成功,不一致则报错InvalidCastException。
serialVersionUID可以显式声明或隐式声明,若隐式声明,则每次修改Class时,自动生成的serialVersionUID会改变,导致反序列化失败。所以serialVersionUID最好显式声明:
private static final long serialVersionUID = 1l;
六,InputStreamReader OutputStreamWrite
字符流默认的编码方式是UTF-8,但是遇到不是该种编码方式的文件时,字符流就会读取失败,这时就需要用到InputStreamReader和OutputStreamWrite类,帮助实现字节流和字符流之间的转化。
1.InputStreamReader
InputStreamReader将字节流转化为字符流,可以指定编码方式,使用步骤:
- 将字节流装入InputStreamReader,并指定编码方式;
- 将InputStreamReader装入字符流;
- 读写;
- 关闭外层流;
public static void input() throws IOException{
String filePath = "E:\\FileTest\\news51.txt";
//字节流转化为字符流 两步包装:
//1.将 FileInputStream 转化为 InputStreamReader,并指定编码 gbk
InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream(filePath), "gbk");
//2.把 InputStreamReader 装入包装流 BufferedReader
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
//3.读取
String len;
while((len = bufferedReader.readLine()) != null)
{
System.out.println(len);
}
bufferedReader.close();//关外层流即可
}
2.OutputStreamWrite
OutputStreamWrite将字符流转化为字节流,使用方式与InputStreamReader一致。
public static void output() throws IOException{
String filePath = "E:\\FileTest\\news51.txt";
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(filePath), "gbk");
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
bufferedWriter.write("hello world!");
bufferedWriter.close();
}