本文主要介绍了java中流的相关知识,首先介绍IO流的分类(从不同角度对IO流进行分类),其次详细的介绍了字节流与字符流(按数据传输最小单位对流进行划分)的知识,其中包含了常见的字节流与字符流,之后介绍了文件的相关知识,最后介绍了常用配置文件properties与流的结合使用相关知识!
一、IO流作用及分类
1.流的概念
- 概念: 传输数据的管道
2.IO流的作用
- 作用: 当前程序与其他文件(内存,文件)数据的传输管道
3.IO流的分类
按照流向分类
- 输入流: 将数据从其他地方(内存、磁盘文件)传输到程序中
- 输出流: 将程序中的数据输出到其他地方(内存、磁盘文件)
按照传输的最小数据单位分类
- 字节流: 传输的最小数据单位是byte(
可以传输任何一种数据
)- 字符流: 传输的最小单位是char(只能输出文本内容,不能传输音频,视频,图片等数据)
按照功能分类
- 节点流: 不会对数据进行加工
- 过滤流: 会对数据进行加工
二、字节流
体系:
- InputStream: 所有
字节输入流
的父类,是一个抽象类
- OutputStream: 所有
字节输出流
的父类,是一个抽象类
1.文件字节流
- FileInputStream: 从文件到程序
- FileOutputStream: 从程序到文件
eg:文件的复制
public static void main(String[] args) throws IOException {
//从哪里读文件到程序中
FileInputStream fis=new FileInputStream("E:\\text01.txt");
//从程序读出到哪个文件,true表示是否追加
FileOutputStream fos=new FileOutputStream("E:\\text02.txt",true);
byte[] bytes=new byte[1024];
int len=0;
//复制
while((len=fis.read(bytes))!=-1) {
fos.write(bytes, 0, len); //逐个数组复制文件
fos.flush();
}
//关流
fis.close();
fos.close();
System.out.println("OVER!");
}
2.内存字节流
- ByteArrayInputStream: 从内存到程序
- ByteArrayOutputStream: 从程序到内存(
toByteArray():获取内存流连接的内存中的数据
)
注意:
- 使用内存字节流可以解决文件流读取数据部分乱码问题(若使用字节数据读取读取的最后一个位置刚好是某个汉字的一半)
- 通常不会使用内存字节流操作文件,因为若文件过大时,将其全部读取到内存中可能会导致运行内存溢出
eg:内存流示例
//1.读取内存中的数据
public static void readMemory() throws IOException {
//字符串常量在运行时存储在运行内存的常量池中
byte[] bytes="这是运行内存中的数据".getBytes();
ByteArrayInputStream bis=new ByteArrayInputStream(bytes);
//读取到b中
byte[] b=new byte[1024];
int len = bis.read(b);
bis.close();
String str=new String(b, 0, len);
System.out.println(str);
}
//2.防止文件流出现部分乱码
public static void writeMemory() throws IOException {
FileInputStream fis=new FileInputStream("E:\\text01.txt");
//不需要给参数(数据可以直接存储到内存中)
ByteArrayOutputStream bos=new ByteArrayOutputStream();
byte[] b=new byte[1024];
int len=0;
while((len=fis.read(b))!=-1) {
//将值存储到bos负责的运行内存中
bos.write(b, 0, len);
bos.flush();
}
//将bos负责的内存区域的值以数组的形式读取出来
byte[] bytes = bos.toByteArray();
bos.close();
fis.close();
System.out.println(new String(bytes));
}
public static void main(String[] args) throws IOException {
readMemory();
writeMemory();
}
3.缓冲字节流(
过滤流
)
- BufferedInputStream
- BufferedOutputStream
作用:提供读写效率:
减少数据的搬运次数,在数据搬运中加入缓冲区,将数据临时保存到缓冲区中,待缓冲区中数据累积到一定值时将一次性将缓冲区中的数据搬运到另一端构造函数:
以BufferedInputStream为例
- 方式一:可以提供一个
InputStream
类型的对象,其默认缓冲区大小为8k(可以看源码)- 方式二: 可以提供一个
InputStream
类型的对象与缓冲区大小size
(单位为字节)
4.对象字节流
ObjectInputStream
ObjectOutputStream
作用:
- 将对象存入文件中,或将文件中存储的对象读取到程序中
注意:
类实现Serializable接口,表示此类进行了序列化,jdk封装的类几乎都实现了序列化(eg:String)
- static修饰的属性不能被序列化
- 版本号除了让程序员与程序员沟通外,没有任何作用(序列化版本号除了可以让程序不飘黄线,其他没什么用)
存储的对象中的所有属性所属的数据类型都必须实现Serializable接口(聚合:一个类中含有以另一个类为数据类型的属性)
- transient修饰的属性称为瞬时属性,不参与序列化
对象流可以关闭其内层流(底层源代码可以观察到)
- 与文件流结合使用(将对象信息保存或读取与本地文件进行交互-类似于数据库)
因为jdk封装的类基本上都实现了Serializable接口,故也可以将若干个对象存储到集合中,然后再将集合对象通过对象流存储到文件中
eg:对象流示例
public static void main(String[] args) throws IOException, ClassNotFoundException {
//保存对象到文件中
FileOutputStream fos=new FileOutputStream("E:\\person.txt");
ObjectOutputStream oos=new ObjectOutputStream(fos);
Person person=new Person("张三", 15);
oos.writeObject(person);
oos.close();//对象流会关闭内层流
//从文件中读取对象信息
FileInputStream fis=new FileInputStream("E:\\person.txt");
ObjectInputStream ois=new ObjectInputStream(fis);
Person p = (Person) ois.readObject();
ois.close();//对象流会关闭内层流
System.out.println(p);
}
三、字符流
特点: 传输的最小单位是char(字符)
1.体系:
与字节流父类提供的方法的用法相似
Reader(抽象类): 所有
字符输入流
的父类
- read()
- read(char[] c)
- read(char[] c,int off, int len)
- close()
Writer(抽象类): 所有
字符输出流
的父类
- write(int b)
- write(char[] c)
- write(char[] c, int off , int len)
- flush()
- close()
2.子类
- 转换流可以将字节流转换为字符流
四、文件(File)
1.File创建对象
new File(“路径”): 此操作不会帮助我们创建文价夹,其指的是后续需要操作的文件对象
- 表示可以操作的文件和文件夹(已存在: 删除文件,获取路径等操作)
- 表示将要操作的文件或文件夹(未存在,将要创建: 创建文件夹)
----对文件的操作均是通过此步骤实现
2.常用属性及方法
常用属性:
- separator:获取当前系统的文件分割符
- pathSeparator:获取当前系统的路径分割符
常用方法:
- file对象.getAbsolutePath():获取文件的绝对路径
- file对象.getPath()获取文件路径
- file对象.getParent():获取父文件夹路径
- file对象.getParentFile():获取父文件夹对应的file对象
- file对象.createNewFile();:创建文件(只能在当前程序项目下创建文件,与src同级别)
- file对象.mkdir():创建1级文件夹
- file对象.mkdirs();:创建多级文件夹
- file对象.isDirectory():判断是否是文件夹
- file对象.isFile():判断是否是文件
- file对象.exists():判断是否是可执行程序
- delete():删除文件或一级空文件夹
- length():获取文件中内容的字节数
- listFiles():获取当前文件夹下得所有直系子文件或文件夹
eg:常用属性及方法示例
// new File("文件名"),不会帮助我们创建文价夹,
//需要调用方法,其指的是后续需要操作的当前文件对象
File file = new File("E:\\text\\text01");
//1.分隔符
String pathseparator = file.pathSeparator;
System.out.println(pathseparator);
System.out.println(file.separator);
//2.获取文件的绝对路径
String absolutePath = file.getAbsolutePath();
System.out.println(absolutePath);
//3.获取文件路径
String path = file.getPath();
System.out.println(path);
//4.获取父文件夹路径
String parentPath = file.getParent();
System.out.println(parentPath);
//5.获取文件夹对象对应的File对象
File parentFile = file.getParentFile();
System.out.println(parentFile.getAbsolutePath());
//6.创建文件(只能在当前程序项目下创建文件,与src同级别)
File file2=new File("tx.txt");
file2.createNewFile();
//7.相对于当前程序的路径
File file3=new File("./b/c");
file3.mkdirs();
//获取路径会进行傻瓜式拼接:
//E:\Eclipse_Project\JavaBasic\.\b\c
System.out.println(file3.getAbsolutePath());
//8.绝对路径创建多级文件夹
File file4=new File("E:\\text\\test01\\b\\c\\t1.docx");
file4.mkdirs();
//9.创建一级文件夹
File file5=new File("E:\\txt");
file5.mkdir();
//10.判断当前file对象是否为文件或文件夹
System.out.println(file5.isDirectory());
System.out.println(file5.isFile());
//11.判断当前对象是否为可执行程序
File file6=new File("E:\\Eclipse_Project\\HelloWord.java");
System.out.println(file6.exists());
//12.删除文件或空一级文件夹
file4.delete();
//13.获取当前文件中内容的字节数
System.out.println(file6.length());
//14.获取当前文件夹下的所用执行子文件或文件夹
File file7=new File("E:\\Eclipse_Project");
File[] listFiles = file7.listFiles();
for (File file8 : listFiles) {
System.out.println(file8.getName());
}
3.文件过滤器
在File类中有两个listFiles重载的方法,方法传递的参数可以是过滤器
FileFilter:
- File[] listFiles(FileFilter filter)
- 作用:用来过滤文件(File对象)
- 重写方法:accept(File dir, String name)
参数:File pathname:使用listFile方法遍历目录,得到的每一个文件对象
FilenameFilter:
- File[] listFiles(FilenameFilter filter)
- 作用:用于过滤文件名称
- 重写方法:accept(File dir, String name)
参数:dir:父文件夹对应的File对象 name:当前遍历文件的名称
注意: 两个过滤器接口是没有实现类的,需要我们自行写实现类,然后accept()方法重写过滤规则。当accept返回值为true时表明该文件为所需获取的文件,否则将文件进行过滤掉
eg:过滤器示例
public static void main(String[] args) {
// TODO Auto-generated method stub
File file =new File("E:\\Eclipse_Project");
File[] files01=file.listFiles(new FileFilter() {
@Override
//参数为当前遍历的文件对象
public boolean accept(File pathname) {
String name = pathname.getName();
if (name.endsWith(".jpeg")) {
return true;
}
return false;
}
});
//遍历
for (File file2 : files01) {
System.out.println(file2.getName());
}
/**
* 1参:父文件夹对应的File对象
* 2参:当前遍历文件的名称
*/
File[] files02=file.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
// TODO Auto-generated method stub
if (name.endsWith(".java")) {
System.out.println(dir.getName());
return true;
}
return false;
}
});
for (File file2 : files02) {
System.out.println(file2.getName());
}
}
五、Properties(类)
- 概念: Properties类表示一组持久的属性。 Properties可以保存到流中或从流中加载。 属性列表中的每个
键及其对应的值都是一个字符串
。- 继承于集合: HashTable(类)
- 方法:
1,可以用作配置文件,比如与流配合使用,用于类对象的加载;(key=Value)
2,可以将properties文件通过流读取到程序Properties对象集合中(list方法),相反,也可以将Properties集合对象通过流保存到本地文件中(store)