Io流
文件流
文件与流
文件概念
属于文件的一种,与普通文件载体不同,文件是以硬盘为载体储存在计算机上的信息集合;是指存储在外部介质上的数据集合。可管理(增删改查),储存。
流概念
是指在计算机的输入/输出操作中各部件之间的数据流动,按照数据的传输方式分为
- 输入流(InputStream)----用来读取数据的
- 输出流(OutputStream)----用来写出数据的
IO是输出输入流的简写
流分类
-
根据处理流的类型
- **字符流:**基本单位(8位byte)的流
- **字节流:**基本单位(16为Unicode)的流
-
流向分类(以代码为中心)
- 输入流(Input):从硬盘将数据读取到代码中,只读不写
- 输出流(Output):从代码中将数据写入硬盘中,只写不读
-
根据流的角色来分类
- **节点流:**特定设备需要使用节点流来进行输出操作
- **过虑流:**对一个已经存在的输入输出流功能进行强化,注意:一般不能单独使用,必须配合节点流来进行使用
常用Io流体系表
分类 | 字节输入流 | 字节输出入 | 字符输入流 | 字符输出流 |
---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer |
访问文件 | FileInputStream | FileOutputStream | FileReader | FileWriter |
缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 | InputStreamReader | OutputStreamWriter | ||
对象流 | ObjectInputStream | ObjectOutputStream |
file类
- file类是Java.io包中唯一代表磁盘文件本身的对象,也就是说,如果希望在程序中操作文件和目录,则都可以通过file类完成
- file类定义了一些方法操作文件,可进行新建,删除,重命名文件和目录等。但file不能访问文件内容本身,如需访问则需要使用输出/输入流
Java
package 流;
import java.io.File;
public class 检查文件 {
public static void main(String[] args) {
File file = new File("src/main/java/流/文件测试包/文件.txt");
//获取名字
String name = file.getName();
System.out.println(name);
//获取文件大小(单位是字节)
long len = file.length();
System.out.println(len+"字节");
//是否可读可写
boolean cr = file.canRead();
boolean cw = file.canWrite();
System.out.println("是否可读:"+cr);
System.out.println("是否可写:"+cw);
//是否隐藏
boolean ih = file.isHidden();
System.out.println("是否隐藏:"+ih);
}
}
语法格式
Java
File 文件名=new File("文件路径");
创建新文档
使用createNewFile()方法
Java
package 流;
import java.io.File;
import java.io.IOException;
public class 创建文档 {
public static void main(String[] args)throws IOException {
File path=new File("src/main/java/流/文件测试包/文件1.txt");
if(path.exists()){
//exists:判断文件夹当中是否存在某个文档,返回值只能是booleane类型
System.out.println("文档已经存在,重新命名");
}
else {
path.createNewFile();//创建文档
System.out.println("创建成功");
}
}
}
删除和判断文件/夹
Java
package 流;
import java.io.File;
public class 判断_删除文件_夹 {
public static void main(String[] args) throws Exception {
File path=new File("src/main/java/流/文件测试包/文件2.txt");
if(path.exists()){
//exists:判断文件夹当中是否存在某个文档
System.out.println("文档已经存在,重新命名");
}
else {
path.createNewFile();//createNewFile:创建文档
System.out.println("创建成功");
}
//判断是否是文件:isFile 判断是否是文件夹:isDirectory
System.out.println("判断是否是文件:"+path.isFile());
System.out.println("判断是否是文件夹:"+path.isDirectory());
//删除文件夹
File a=new File("src/main/java/流/文件测试包/文件2.txt");
System.out.println(a.delete());
/*a.delete()
* 返回teur表示删除成功
* 返回false表示删除失败
* */
}
}
获取当前文件夹中所有文件
使用list()方法
Java
package 流;
import java.io.File;
public class k {
public static void main(String[] args) {
//获取当前目录中的所有子项
File dir = new File("src/main/java/流/文件测试包");
/*
boolean isFile()
判断当前File表示的是否为一个文件
boolean isDirectory()
判断当前File表示的是否为一个目录
*/
if(dir.isDirectory()){
/*
File[] listFiles()
将当前目录中的所有子项返回。返回的数组中每个File实例表示其中的一个子项
*/
File[] subs = dir.listFiles();
System.out.println("当前目录包含"+subs.length+"个子项");
for(int i=0;i<subs.length;i++){
File sub = subs[i];
System.out.println(sub.getName());
}
}
}
}
获取符号特点条件子项目
重载的listFiles方法:File[] listFiles(FileFilter)
该方法要求传入一个文件过滤器,并仅将满足该过滤器要求的子项返回。
java
package file;
import java.io.File;
import java.io.FileFilter;
/**
* 有条件的获取一个目录中的子项
*/
public class ListFilesDemo2 {
public static void main(String[] args) {
//获取当前目录下的所有文本文件(文件名是以".txt"结尾的)
File dir = new File(".");
if(dir.isDirectory()){
// FileFilter fileFilter = new FileFilter() {
// public boolean accept(File f) {
// return f.getName().endsWith(".txt");
// }
// };
// /*
// 重载的listFiles方法要求传入一个文件过滤器
// 该方法会将File对象表示的目录中所有满足过滤器条件的子项返回
// */
// File[] subs = dir.listFiles(fileFilter);
File[] subs = dir.listFiles(f->f.getName().endsWith(".txt"));
for(File sub : subs){
System.out.println(sub.getName());
}
}
}
}
创建目录mkdirs()
Java
package 流;
import java.io.File;
import java.io.IOException;
public class 创建多级目录 {
public static void main(String[] args) throws IOException {
// 定义需要创建的文件夹路径
String dirPath = "src/main/java/流/文件测试包/创建目录";
// 创建文件对象
File file = new File(dirPath);
// 判断文件是否存在,不存在则创建
if (!file.exists()) {
// 创建文件
file.mkdirs();
System.out.println("创建目录成功!");
} else {
System.out.println("目录已存在!");
}
}
}
mkdirs()和mkdir()区别
- mkdirs()
- 它可以创建多级目录结构,如果父目录不存在,它会自动创建所有必要的父目录
- mkdir()
- 它只能创建单个目录,并且只有当父目录已经存在时才能成功创建目录。如果父目录不存在,它将抛出异常
常用方法
- getParent():获取上级目录
- getPath():获取相对路径
- getAbsolutePath:获取绝对路径
- getName():获取名字
- lastModified():最近一次修改时间
Java
package 流;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class 常用方法 {
public static void main(String[] args) throws IOException {
File path=new File("src/main/java/流/文件测试包/文件2.txt");
path.createNewFile();
System.out.println("上级目录:"+path.getParent());
System.out.println("该文件的名字为;"+path.getName());
long longdate=path.lastModified();//最近修改时间
Date date=new Date(longdate);//new Date:获取的是柏林时间
SimpleDateFormat pp=new SimpleDateFormat("yyy-mm-dd hh:mm:ss:ss");//时间格式转换 SimpleDateFormat()
System.out.println(pp.format(date));//如果文件不存在则输出初始时间
File yd=new File("文件测试包/lly.doc");
System.out.println("相对路径:"+yd.getPath());
System.out.println("绝对路径:"+yd.getAbsolutePath());
}
}
/*
输出:
上级目录:src\main\java\流\文件测试包
该文件的名字为;文件2.txt
2024-24-21 12:24:34:34
相对路径:文件测试包\lly.doc
绝对路径:F:\Java_project\java_maven\文件测试包\lly.doc*/
文件字节流
InputStream是Java所有字节输入流类的父类,OutputStream是Java所有字节输出流类的父类,因此继承它们的子类要重新定义父类中的抽象方法。
OutputStream
是字节输出流,也是一个抽象类,new子类来定义其方法
常用方法
write():向输出流中写入一个字节
close:关闭输出流
flush:可以强制将缓冲区中的数据写入输出流,并清空缓冲区
实现代码
java
package com.ch012.h003;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
public class shuchuruliu {
public static void out(){
//地址
File lyy=new File("src/com/ch012/h003/ceshi/测试.txt");
try{
FileOutputStream ldy=new FileOutputStream(lyy,true);//true为追加操作内容
String zb="风声鹤起,问我要有多大,梦里把你吓";//原本准备内容
ldy.write(zb.getBytes());//x写入内容
ldy.close();//关闭资源
System.out.println("成功输入!");
}
catch (FileNotFoundException e){
System.out.println("找不到指定文件");
}catch (IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
out();//调用方法
}
}
//输出:
风声鹤起,问我要有多大,梦里把你吓
Java
package 流;
import java.io.FileOutputStream;
import java.io.IOException;
public class 文件字节流1 {
public static void main(String[] args) {
try {
FileOutputStream a=new FileOutputStream("src/main/java/流/文件测试包/文件3");
String a1="1234567890";
a.write(a1.getBytes());//把数据写到内存
a.flush();//把内存中的数据刷新写到硬盘上
a.close();//关闭
} catch (IOException e) {
e.printStackTrace();
}
}
}
InputStream
是输入流,也是一个抽象类,主要负责将数据进行读取操作,在进行实列化的时候一定要是实列化其子类,new子类来使用方法
Java
package 流;
import java.io.FileInputStream;
public class 文件字节流 {
public static void main(String[] args) {
try {
FileInputStream a=new FileInputStream("src/main/java/流/文件测试包/文件3");
byte[]b=new byte[10];//设置一个数组接收读取文件的内容
a.read(b);
System.out.println(new String(b));//打印出读取的内容
a.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
常用方法
read():读取数据
close:关闭资源
代码实现
java
package 流;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class 读取文件内容 {
public static void main(String[] args) throws IOException {
File ye=new File("src/main/java/流/文件测试包/文件2.txt");
FileInputStream le = new FileInputStream(ye);
byte[]bytes=new byte[1024];
/*读取数据*/
int len=le.read(bytes);
while (len!=-1){
System.out.println(new String(bytes,0,len));
len=le.read(bytes);
}
}
}
字节流拷贝文件
java
package 流;
import java.io.*;
public class 字节流复制 {
//将文件复制到另一个文件
public static void main(String[] args) throws IOException {
FileInputStream in=new FileInputStream("src/main/java/流/文件测试包/文件.txt");
FileOutputStream out=new FileOutputStream("src/main/java/流/文件测试包/文件2.txt");
byte[] b=new byte[100];
int len;
while((len=in.read(b))!=-1){
out.write(b,0,len);
}
in.close();
out.close();
}
}
/*注意:
使用write方法帮我们去进行写入工作的时候,为了解决部分编码问题(乱码),于是传入三个参数
第一个:byte[]存放读取出来的内容
第二个:起始位置,因为是进行拷贝工作,所以一般起始位置都是从0开始
第三个:编号*/
文件字符流
FileReader
主要负责读取工作
java
package 流.文件字符流;
import java.io.FileReader;
import java.io.IOException;
public class 文件字符流 {
public static void main(String[] args) throws IOException {
//读取文件数据
FileReader fr = new FileReader("src/main/java/流/文件测试包/文件.txt");
char[]c=new char[10];
int len=0;
while ((len=fr.read(c))!=-1){
System.out.println(new String(c,0,len));
}
fr.close();
}
}
writer
java
package 流.文件字符流;
import java.io.FileWriter;
import java.io.IOException;
public class 文件字符流2 {
public static void main(String[] args) throws IOException {
FileWriter a=new FileWriter("src/main/java/流/文件测试包/文件.txt");
a.write("一滴水的感恩!");
a.flush();
a.close();
}
}
字符流拷贝
java
package 流.文件字符流;
import java.io.*;
public class 拷贝 {
public static void main(String[] args) throws IOException {
FileReader a = new FileReader("src/main/java/流/文件测试包/文件.txt");
FileWriter b = new FileWriter("src/main/java/流/文件测试包/文件2.txt");
char[]c=new char[100];
int len;
while ((!((len=a.read(c))!=-1))){//读取数据
b.write(c,0,len);//写入数据
}
a.close();
b.close();
}
}
缓冲流
缓冲字节流
功能
在流链接中的作用:加快读写效率
通常缓冲是最终链接在低级流上的流
flush的传递
flush()方法是被定义在java.io.Flushable中。而字节输出流的超类java.io.OutputStream实现了该接口,这意味着所有的字节输出流都有flush方法。而除了缓冲流之外的高级流的flush方法作用就是调用它链接的流的flush方法将该动作传递下去。最终传递给缓冲流来清空缓冲区。
BufferedInputStream
Java
package 流.缓冲流;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
//缓冲字节流读取文件内容
public class 缓冲字节流 {
public static void main(String[] args) throws IOException {
FileInputStream a=new FileInputStream("src/main/java/流/文件测试包/文件2");
BufferedInputStream b=new BufferedInputStream(a);
byte[]c=new byte[100];
int len;
while ((len=b.read(c))!=-1){
System.out.println(new String(c,0,len));
}
a.close();
b.close();
}
}
BufferedOutputStream
Java
package io;
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* 缓冲输出流的写缓冲问题
*/
public class BosFlushDemo {
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("bos.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
String line = "super idol的笑容都没你的甜~";
byte[] data = line.getBytes(StandardCharsets.UTF_8);
bos.write(data);
/*
void flush()
强制将缓冲流的缓冲取(内部维护的字节数组)中已经缓存的字节一次性写出
*/
// bos.flush();
System.out.println("写出完毕!");
bos.close();//缓冲输出流的close()方法内部会自动调用一次flush()方法确保数据写出
}
}
写缓冲问题
由于缓冲输出流会将写出的数据装满内部缓冲区(默认8kb的字节数组)后才会进行一次真实的写出操作。当我们的数据不足时,如果想要及时写出数据,可以调用缓冲流的flush()方法,强制将缓冲区中已经缓存的数据写出一次。
缓冲字节流拷贝
Java
package 流.缓冲流;
import java.io.*;
public class 缓冲字节流文件复制 {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("src/main/java/流/文件测试包/b51866052244a2414c0d2cc75f3c3752.png");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("src/main/java/流/文件测试包/创建目录/复制的图片.png");
BufferedOutputStream bos = new BufferedOutputStream(fos);
int len;
long start = System.currentTimeMillis();
while((len=bis.read())!= -1){
bos.write(d);
}
long end = System.currentTimeMillis();//格林尼治标准时间
System.out.println("复制完毕!耗时:"+(end-start)+"ms");
bis.close();
bos.close();
}
}
缓冲字符流
BufferedReader
Java
package 流.缓冲流;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class 缓冲字符输入流 {
public static void main(String[] args) throws IOException {
FileReader r=new FileReader("src/main/java/流/文件测试包/文件3");
BufferedReader br=new BufferedReader(r);
char[]b=new char[100];
int len;
while ((len=br.read(b))!=-1){
System.out.println(new String(b,0,len));
}
r.close();
}
}
BufferedWriter
Java
package 流.缓冲流;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class 缓冲字符输出流 {
public static void main(String[] args) throws IOException {
FileWriter a=new FileWriter("src/main/java/流/文件测试包/文件2.txt");
BufferedWriter b=new BufferedWriter(a);
String c="hello world";
System.out.println("成功");
b.write(c);
b.flush();
b.close();
a.close();
}
}
缓冲字符流拷贝
Java
package 流.缓冲流;
import java.io.*;
public class 缓冲字符流拷贝 {
public static void main(String[] args) throws IOException {
BufferedReader a=new BufferedReader(new FileReader("src/main/java/流/文件测试包/文件3"));
BufferedWriter b=new BufferedWriter(new FileWriter("src/main/java/流/文件测试包/文件2.txt"));
char[] c=new char[1024];
int len=0;
while((len=a.read(c))!=-1) {
b.write(c, 0, len);
}
System.out.println("成功");
b.flush();
b.close();
a.close();
}
}
字符转换流
字符流与字节流之间的转换
好处
1,可以进行编码格式的设置
2,可以加快读写速度
3,读写的数据类型为字节类型
InputStreamReader
将字符输入流和字节输入流之间进行转换
Java
package 流.转换流;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
public class 转换输入流 {
public static void main(String[] args) throws IOException {
FileInputStream a=new FileInputStream("src/main/java/流/文件测试包/文件4");
InputStreamReader b=new InputStreamReader(a,"UTF-8");
char[]c=new char[10];
int len;
while((len=b.read(c))!=-1){
System.out.println(new String(c,0,len));
}
b.close();
a.close();
}
}
OutputStreamWrier
将字符流输出流和字节输出流之间进行转换
Java
package 流.转换流;
import java.io.*;
public class 转换输出流 {
public static void main(String[] args) throws IOException {
FileOutputStream out = new FileOutputStream("src/main/java/流/文件测试包/文件5");
OutputStreamWriter outWriter = new OutputStreamWriter(out,"utf-8");
outWriter.write("转换输出流");
System.out.println("成功");
outWriter.close();
out.close();
}
}
字节对象流
直接把某个对象写入到某个文件中,直接读取某个文件中的对象属性
为什么使用序列化操作
1,可以将对象永久的保存到磁盘中
2,可以把对象通过网络上进行传输到另一台机器上
**注:**无论是保存在磁盘中还是传输,都需要将对象转换为字节后才可以进行
使用序列化的前提
- 必须实现Serilizable接口
创建被序/反序列化的对象
Java
package 流.对象流;
import java.io.Serializable;
public class chuangjian implements Serializable {
String name;
int age;
private transient String id;
public chuangjian(String name, int age, String id){
this.name=name;
this.age=age;
this.id=id;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age;
}
}
实现了序列化接口的类建议显示的定义常量:static final long serialVersionUID = 1L;
序列化操作
将对象的某些属性或方法写入到某个文件中(将对象写入文档)
ObjectOutputStream
主要负责写入工作,实现序列化操作(将某个对象写入到某个文件中)
Java
package 流.对象流;
import java.io.*;
public class 对象流反序列化 {
public static void main(String[] args) throws IOException {
chuangjian a=new chuangjian("zhangsan",21,"jd218429");
FileOutputStream b=new FileOutputStream("src/main/java/流/文件测试包/文件.txt");
ObjectOutputStream b1=new ObjectOutputStream(b);
b1.writeObject(a);
System.out.println("成功");
b1.close();
}
}
transient关键字
当一个属性被transient关键字修饰后,该对象在进行序列化时,转换出来的字节中是不包含该属性的。忽略不必要的属性可以达到对象"瘦身"的操作。
对象瘦身可以在对象持久化时减少磁盘开销。在进行传输时可以缩短传输速度。
如果该对象不需要序列化,那么该关键字不发挥其他任何效果
Java
public class chuangjian implements Serializable {
String name;
int age;
private transient String id;
序列化时不包含otherInfo属性,并且反序列化时该属性值为null
Java
Person{name='zhangsan', age=21,id=null}
反序列化操作
将某个文件中的对象读取出来(在文件中读取对象)
ObjectInputStream
主要负责读取工作,实现反系列化操作(将某个文件中的对象读取出来)
Java
package 流.对象流;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class 序列化 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileInputStream a=new FileInputStream("src/main/java/流/文件测试包/文件.txt");
ObjectInputStream b=new ObjectInputStream(a);
chuangjian c= (chuangjian) b.readObject();
System.out.println(c);
b.close();
}
}