一、File类
一个File类对象可以代表一个文件或目录,可以实现对文件或目录的新建、删除、重命名等操作
File file = new File("C:\\test.txt");
创建File类对象时,括号被必须设置文件路径
路径可以是相对路径或者是绝对路劲
绝对路径:以根目录开头的完整路径
FIle常用方法:
方法 | 说明 |
---|---|
boolean createNewFile() | 创建新文件 |
boolean delete() | 删除文件 |
boolean exists() | 判断文件是否存在 |
Boolean isFile() | 判断是否是文件 |
boolean isDirectory() | 判断是否是目录 |
long length() | 返回文件长度,单位为字节 若文件不存在,则返回0L |
String getPath() | 返回此对象文件名所对应的路径 |
String getAbsolutePath() | 返回此对象表示的文件的绝对路径名 |
在实际开发中,如需完成对File类的更多操作,可随时查阅API帮助文档
File file=new File("test.txt");
//判断文件是否存在
if(file.exists()){
//判断是否是文件
if(file.isFile()){
System.out.println("文件名:"+file.getName()+",文件的长度是:"+file.length()+"字节");
System.out.println("文件的路径是:"+file.getPath());
System.out.println("文件的绝对路径是:"+ file.getAbsolutePath());
}
//判断是否是目录
if(file.isDirectory()){
System.out.println("该文件是目录");
}
}else{
System.out.println("文件不存在");
二流是个抽象的概念:
是对输入输出设备的抽象,Java程序中,对于数据的输入/输出操作都是以“流”的方式进行。
设备可以是文件,网络,内存等。 流具有方向性,至于是输入流还是输出流则是一个相对的概念,一般以程序为参考,如果数据的流向是程序至设备,我们成为输出流,反之我们称为输入流
java中IO流分为几种?
1、IO流概念
流是从一端到另一端,连接了源头和目的地。
IO流可以理解为连接程序与文件/数组/网络连接/数据库。
2、IO流分类
(1)按流向分类:
输入流
输出流
(2)按处理数据不同分类:
字节流:二进制,可以处理一切文件,包括:纯文本、doc、音频、视频等。
字符流:文本文件,只能处理纯文本。
(3)按功能不同分类:
节点流:包裹源头。
处理流:增强功能,提高性能。
IO流是指一连串流动的字符,以先进先出方式发送信息的通道
I:input,指读入操作
O:output,指写出操作
Java把所有流类型都封装到java.io包中,以实现输入/输出操作
有底色的为常用示例类
如何区分字节流和字符流
看后缀:InputStream和Output Stream结尾的分别为字节输入流和字节输出流
Reader和Writer结尾的分别为字符输出流和字符输入流
二、流的体系结构
抽象基类 节点流(文件流) 缓冲流(处理流的一种)
InputStream FlieInputStream BufferedInputStream
OutputStream OutputStream BufferedOuputStream
Reader FileReder BufferedReader
Writer FileWriter BufferedWriter
输入流
只能从中读取数据,而不能写入数据的流,实现程序从数据源中读数据
输出流
只能向其写入数据,而不能从中读数据的流,实现程序向目标数据源中写数据
输入流主要由InputStream和Reader作为基类
输出流则主要由OutputStream和Writer作为基类
都是抽象类,无法直接实例化对象
四、字节流和字符流的概念
字节流:
以8位字节为操作数据单元的流,可操作二进制数据
可细分为字节输入流、字节输出流
字符流:
以16位字符为操作数据单元的流,可操作文本数据
可细分为字符输入流、字符输出流
区别:
操作的数据单元不同
使用方法几乎相同
五、按流的角色划分:节点流和处理流的概念
节点流
可以直接向一个特定的存储介质(如磁盘、文件)读写数据的流
使用节点流进行读写数据操作时,程序直接连接到数据源
处理流
对已存在的流进行连接和封装,通过封装后的流实现数据读写操作的流
使用处理流进行读写操作时,程序并不会直接连接到实际的数据源
区别:
使用处理流包装节点流,通过处理流执行输入和输出功能,让节点流与文件或磁盘等存储设置交互,可隐藏底层节点流的差异
六、字节流
主要功能:
具有输入和输出操作
主要操作byte类型数据
基类:
字节输出流类: OutputStream
字节输入流类:InputStream
6.1、字节输出流类: OutputStream(写入):
常用方法
方法 | 说明 |
---|---|
void close() | 关闭输出流 |
void flush() | 刷新缓冲区 |
void write(byte[] b) | 将每个byte数组写入数据流 |
void write(byte[] b,int off,int len) | 将每一个指定范围的byte数组写入数据流 |
void write(int b) | 将一个字节数据写入数据流 |
常见的构造方法:
方法 | 说明 |
---|---|
FileOutputStream( File file) |
创建向指定File对象写数据的文件输出流 file:指定目标文件的对象 |
FileOutputStream( String name) |
创建向指定路径的文件写数据的文件输出流 name:指定目标文件的路径字符串 |
FileOutputStream( String name, boolean append) |
创建一个向指定路径的文件写入数据的文件输出流 name:指定目标文件的路径字符串 append:表示是否在文件末尾追加数据。如果为true,则表示可以在文件末尾追加数据 |
OutputStream fos=null;
try {
//FileOutputStream参数①路径 参数②是否追加内容‘true’是追加
// 不加‘true’的话就是默认覆盖内容第二个参数可以省略
fos=new FileOutputStream("D:\\140\\test.txt",true);
String str="冲冲冲!";
byte[] words=str.getBytes();//将String类型转换为byte数组类型
//将转换为byte数组的值放入到write中 第一个参数代表数据类型
//第二参数代表截取的下标开始
//第三参数代表截取的下标结束
fos.write(words ,0,words.length);
System.out.println("写入成功");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fos!=null){
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
注意:
使用FileOutputStream类的构造方法创建对象时
如果相应的文件不存在,就会自动新建一个文件
如果参数file或name表示的文件路径是一个目录,则会抛出FileNotFoundException异常
字节输入流类:InputStream(读取)
从文件中读数据
与OutputStream一样,也是抽象类
常用方法
常用方法:
方法 | 描述 |
---|---|
int read() | 读取一个字节数据 |
int read(byte[] b) | 将数据读取到字节数组中 |
int read(byte[] b,int off,int len) | 从输入流中读取最多len长度的字节,保存到字节数组中,保存的位置从off开始 |
void close() | 关闭输入流 |
int available() | 返回输入流读取的字节数 |
使用InputStream类的FileInputStream子类实现文本文件内容的读取
常用构造方法
方法 | 描述 |
---|---|
FileInputStream(File file) | 用于创建从指定File对象读取数据的文件输入流 file:指定目标文件数据源对象 |
FileInputStream( String name) |
用于创建从指定路径的文件读取数据的文件输入流 name:指定目标文件数据源路径字符串 |
创建文件输入流对象的常用方式
注意:
按字节读取并显示数据时需进行强制类型转换
使用read()读取文件中的数据时,当返回结果为-1时,即输入流已经读到末尾
在创建输入流对象、读取数据、关闭流时必须进行异常处理
InputStream.read():
/把读取的内容输出
fis=new FileInputStream("D:\\140\\test.txt");//放入路径
byte[] words=new byte[1024];//创建字节数组
System.out.println("可读取得字节数:"+fis.available());
int data=0;//定义一个int类型的变量接收返回的内容
System.out.println("文件内容");
while((data=fis.read())!=-1){//将读取到的字节放到int变量中
System.out.print((char) data+" ");//将返回的内容转换为char类型
}
//方式一,把读取的内容存储
byte[] words=new byte[1024];
int len=0;
while ((len=fis.read(words))>30){
System.out.println(new String(words ,0,len));
}
//方式二,把读取的内容存储
byte[] words=new byte[1024];
fis.read(words);
String str=new String(words);
System.out.println(str.trim());
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭输出流
try {
if(fis!=null){
fis.close();
}
} catch (IOException e) {
e.printStackTrace();
为什么InputStream.read()读取一个byte确返回一个int呢?
java 字节读取流的read方法一次读一个byte但返回int的原因
读取二进制数据按字节读取,每次读一个字节(byte)。
read()的底层是由C++实现的,返回的是unsigned byte,取值范围为[0~255],在java中没有对应的类型,所以只能用int类型接收,由Java接收得到的就是int[0、255]。
在java中byte只能表示[0-127]的无符号数。也对应这java中int[0-127]
那么[128-255]怎么表示?
在java中byte的范围是[-128,127],所以[128-255]只能由int来接收。
字符流:
基类
字符输出流类: Writer
抽象类
常用方法
方法 | 描述 |
---|---|
void write(String str) | 将str字符串中包含的字符输出到输出流中 |
void write(String str, int off, int len) |
将字符串中从off位置开始,长度为len的字符输出到输出流中 |
void close() | 关闭输出流 |
void flush() | 刷新输出流 |
Writer类的子类:字符输出流FileWriter类
Writer fw=null;
try {
//FileWriter参数①路径 参数②是否追加内容‘true’是追加
// 不加‘true’的话就是默认覆盖内容,第二个参数可以省略
fw=new FileWriter("D:\\140\\test.txt",true);
fw.write("预测未来的最好方式就是创造未来");//写入操作
fw.flush();//*刷新缓冲区
System.out.println("文件写入成功");//写入操作
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件不存在");
} finally {
if(fw!=null){
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}以字符为数据处理单元向文本文件中写数据
BufferedReader类
Reader类的子类
带有缓冲区,提高文件读取的效率
把一批数据读到缓冲区
从缓冲区内获取数据
常用构造方法
方法 | 描述 |
---|---|
BufferedReader(Reader in) | 创建一个缓冲字符输入流 |
readLine()方法
按行读取文件中数据
相关代码:
序列化与反序列化
使用序列化和反序列化,方便数据传输和存储
序列化是将对象的状态存储到特定的存储介质中的过程,
反序列化是将特定的存储介质中数据重新构建对象的过程
对象输出流( ObjectOutputStream ):实现序列化
对象输入流( ObjectInputStream):实现反序列化
实现序例化的要素
要实现实现java.io.Serializable接口,则该类的对象是可序列化的
方法 | 描述 | 类型 |
---|---|---|
ObjectOutputStream(OutputStream out) | 创建对象输出流对象 | 构造方法 |
final void writeObject(Object obj) | 将指定对象写入流 | 实例方法 |
如何解决序列化和反序列化的版本不一致问题?
引入serialVersionUID常量(JVM在编译时自动生成serialVersionUID常量,也可显式定义)
使用ObjectInputStream类实现反序列化
方法 | 描述 | 类型 |
---|---|---|
ObjectInputStream(InputStream in) | 创建对象输入流对象 | 构造方法 |
final Object readObject() | 从指定位置读取对象 | 实例方法 |
限制序例化:
用transient关键字声明过的对象或属性不能被序例化
序例化与反序例化代码展示:
/**
*User类
*/
public class User implements Serializable {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 性别
*/
private String sex;
/**
* 注册时间
*/
private String time;
/**
* 封装属性
* @return
*/
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 String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
/**
* 输出信息的方法
*/
public void print(){
System.out.println("姓名是:"+getName()+"年龄:"+getAge()+"性别:"+getSex()+"注册时间:"+getTime());
}
/**
* 类的无参构造方法
*/
public User() {
}
/**
* 类的有参构造方法
* @param name
* @param age
* @param sex
* @param time
*/
public User(String name, int age, String sex, String time) {
this.name = name;
this.age = age;
this.sex = sex;
this.time = time;
}
package chapter_test;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class Test4 {
public static void main(String[] args) {
//声明ArrayList集合存储User的对象
ArrayList<User> list=new ArrayList<>();
ObjectInputStream obi=null;//声明一个实现序列化的对象
ObjectOutputStream obo=null;//声明一个实现反序列化的对象
try {
//实例化一个实现序列化的对象
obo=new ObjectOutputStream(new FileOutputStream("D:\\doc\\user.dat"));
//创建User类的对象作为数据
User user1=new User("张三",18,"男","2021-09-09");
User user2=new User("王五",18,"男","2021-08-08");
User user3=new User("赵六",20,"男","2021-07-07");
//添加到ArrayList集合中
list.add(user1);
list.add(user2);
list.add(user3);
//实现序例化
obo.writeObject(list);
System.out.println("序例化成功");
//实例化一个实现反序列化的对象
obi=new ObjectInputStream(new FileInputStream("D:\\doc\\user.dat"));
//实现反序例化
list=(ArrayList<User>)obi.readObject();
//循环遍历
for(User u:list){
u.print();
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
obi.close();//关闭实现序例化的流
obo.close();//关闭实现反序例化的流
} catch (IOException e) {
e.printStackTrace();
}
}
}