I/O流
概况图
一、File
概念:代表物理盘符中的一个文件或文件目录(即文件夹)
理解
- 相对路径:相较于某个路径下,指明的路径
- 绝对路径:包含盘符在内的文件或文件目录的路径
删除方法
- delete
- 删除一个文件或空目录
创建方法
- boolean createNewFile()
- 创建一个新文件
- boolean mkdir()
- 创建文件目录。如果此文件目录存在,就不创建;如果上层目录不存在也不创建
- boolean mkdirs()
- 创建目录。如果目录不存在,一并创建
获取方法
- String getAbsolutePath()
- 获取绝对路径
- String getPath()
- 获取路径
- String getName()
- 获取名称
- String getParent()
- 获取上层文件目录路径。若无,返回null
- long length()
- 获取文件长度(字节数)。不能获取目录的长度
- long lastModified()
- 获取最后一次的修改时间,毫秒值
- String [] list()
- 获取指定目录下的所有文件或者文件目录的名称数组
- File []listFiles()
- 获取指定目录下的所有文件或者文件目录的File数组
判断方法
-
boolean renameTo(File desk)
-
把文件重命名为指定的文件路径
//要保证返回true,需要file1在硬盘中存在,且file2不能在硬盘中存在 File file1 = new File("hello.txt"); File file2 = new File("D:\\hi.txt"); boolean a = file1.renameTo(file2);
-
-
boolean isDirectory()
- 判断是否文件目录
-
boolean isFile()
- 判断是否是文件
-
boolean exists()
- 判断是否存在
-
boolean canRead()
- 判断是否可读
-
boolean canWrite()
- 判断是否可写
-
boolean isHidden()
- 判断是否隐藏
FileFilter接口
当调用File类中的listFiles()方法时,支持传入FileFilter接口实现类,对获取文件进行过滤,只有满足条件的文件的才可出现在listFiles()的返回值中
语法
public interface FileFilter
boolean accept(File pathname)
综合案例
//遍历当前目录下所有文件名和文件夹名
//方式一:遍历目录文件下以.jpg结尾的文件
File dir2=new File("d:\\");
String[] list=dir2.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {// 测试指定文件是否应该包含在某一文件列表中。
//return true;//符合要求
//return false;//不符合要求
if(name.endsWith(".jpg")){
return true;
}
return false;
}
});
for (String s : list) {
System.out.println(s);
}
//方式二:
System.out.println("-----------list()---------");
//获取当前目录下的所有的文件名和文件夹名
String[] list = dir2.list();
for (String s : list) {
System.out.println(s);
}
public class FileDemo3 {
public static void main(String[] args) {
///listDir(new File("d:\\aaa"),0);
listDir(new File("D:\\H5_SQL"),0);
}
//案例1:递归遍历文件夹
public static void listDir(File dir,int level){
File[] files = dir.listFiles();
System.out.println(getSeparator(level)+dir.getName());
level++;
if(files!=null&& files.length>0){
for (File file : files) {
if(file.isDirectory()){//file是文件夹
listDir(file,level);
}else{
System.out.println(getSeparator(level)+file.getName());
}
}
}
}
public static String getSeparator(int level){
if(level<=0){
return "";
}
StringBuilder sb=new StringBuilder("|");
for (int i = 0; i < level; i++) {
sb.append("________");
}
return sb.toString();
}
//案例2:递归删除文件夹
public static void listDelete(File dir){
File[] files = dir.listFiles();
if(files!=null&&files.length>0){
for (File file : files) {
if(file.isDirectory()){
listDelete(file);
}else{
//删除文件
System.out.println(file.toString()+" 删除结果是:"+file.delete());//不进回收站
}
}
}
//删除dir
System.out.println(dir.toString()+" 删除结果是:"+dir.delete());
}
}
二、IO流原理及流的分类
1.抽象基类
- InputStream/OutputStream 字节流输入/输出
- InputStream 字节输入流
- public int read()
- public int read(byte []b)
- public int read(byte []b, int off, int len)
- OutputStream 字节输出流
- public void write(int n)
- public void write(byte []b)
- public void write(byte []b, int off, int len)
- InputStream 字节输入流
- Reader/Writer 字符流输入/输出
2.流的分类
- 单位
- 字节流:以字节为单位,可以读写所有数据
- 字符流:以字符为单位,只能读写文本数据
- 功能
- 结点流:具有实际传输数据的读写功能
- 过滤流:在结点流的基础之上增强功能
三、节点流(或文件流)
3.1 FileInputStream/FileOutputStream 字节流输入/输出
- public int read(byte[] b)
- 从流中读取多个字节,将读到内容存入b数组,返回实际读到的字节数;如果达到文件的尾部,则返回-1
- public void write(byte []b)
- 一次写多个字节,将b数组中所有字节,写入输出流
3.2 FileReader/FileWriter 字符流输入/输出
-
public int read(char[] b)
- 从流中读取多个字节,将读到内容存入b数组,返回实际读到的字节数;如果达到文件的尾部,则返回-1
-
public void write(String b)
- 一次写多个字节,将b数组中所有字节,写入输出流
-
输出流可以追加
new FileOutputStream("d:\\aaa.txt",true);
new FileWriter("d:\\aaa.txt",true);
public class FileInputStreamDemo {
public static void main(String[] args) throws Exception{
//1创建流
FileInputStream fis=new FileInputStream("d:\\aaa.txt");
System.out.println("字节个数:"+fis.available());
//2读取
//2.1 单个字节读取
int data;
while((data=fis.read())!=-1) {
System.out.print((char)data);
}
//2.2 一次读取多个字节
// byte[] buf=new byte[5];
// int len;
// while((len=fis.read(buf))!=-1){
// String s=new String(buf,0,len);
// System.out.print(s);
// }
//3关闭
fis.close();
}
}
public class FileOutputStreamDemo {
public static void main(String[] args) throws Exception{
//1创建文件字节输出流
FileOutputStream fos=new FileOutputStream("d:\\out.txt",true);
//2写入
//2.1写入一个字节
// fos.write(97);
// fos.write(98);
// fos.write(99);
//2.2写入多个字节
String s="好好学习,天天向上\r\n";
byte[] data=s.getBytes();//把字符串转成字节数组
for (int i = 0; i < 10; i++) {
fos.write(data);
}
//3关闭
fos.close();
System.out.println("执行完了");
}
}
四、缓冲流
4.1 BufferedInputStream/BufferedOutputStream 字节缓冲流输入/输出
4.2 BufferedReader/BufferedWriter 字符缓冲流输入/输出
- 支持输入换行符
- 可一次写一行,读一行
- 默认8K
public class BufferedInputStreamDemo {
public static void main(String[] args) throws Exception{
//1创建字节缓冲输入流
FileInputStream fis=new FileInputStream("d:\\aaa.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
//2读取文件
int data;
while((data=bis.read())!=-1){
System.out.print((char)data);
}
//3关闭(只关闭缓冲流,内部把底层流关闭了)
bis.close();
}
}
public class BufferedOutputStreamDemo {
public static void main(String[] args) throws Exception {
//1使用字节缓冲输出流写入文件
FileOutputStream fos=new FileOutputStream("d:\\buffer.txt");
BufferedOutputStream bos=new BufferedOutputStream(fos);
//2写入文件
String s="Java是世界上最好的语言\r\n";
byte[] bytes=s.getBytes();
for (int i = 0; i < 10; i++) {
bos.write(bytes);//8K
//bos.flush();//刷新缓冲
}
//3关闭(关闭缓冲流时会自动刷新缓冲区。相当于关闭了底层流)
bos.close();
System.out.println("结束了");
System.out.println("------------------");
补充 try的特殊用法:自动调用close方法,要求对象实现Closeable接口--------
try(Student ss=new Student()){
System.out.println(ss.toString());
}
}
}
五、转换流
5.1 InputStreamReader
将InputStream转换为Reader,字节输入流转换为字符输入流 字符流
5.2 OutputStreamWriter
将OutputStream转换为Writer,将字节输出流转换为字符输出流 字符流
作用
-
解码:字节,字节数组–>字符,字符数组
-
编码:字符,字符数组–>字节,字节数组
-
可设置字符编码
new InputStreamReader(new FileInputStream("d:\\writer.txt"),"utf-8");
public class InputStreamReaderDemo {
public static void main(String[] args) throws Exception{
//1创建的转换流
InputStreamReader isr=new InputStreamReader(new FileInputStream("d:\\writer.txt"),"utf-8");
//2读取
char[] buf=new char[1024];
int len;
while((len=isr.read(buf))!=-1){
String s=new String(buf,0,len);
System.out.println(s);
}
//3关闭
isr.close();
}
}
public class OutputStreamWriterDemo {
public static void main(String[] args) throws Exception {
//1创建转换流
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("d:\\output.txt"), "gbk");
//2写出
for (int i = 0; i < 10; i++) {
osw.write("我爱北京\r\n");
}
//3关闭
osw.close();
}
}
六、标准输入,输出流
6.1. System.in/System.out
标准的输入流,默认键盘输入/标准的输出流,默认从控制台输出
System.in -----------> InputStream
- FileInputStream类型
System.out ------------> OutputStream
- PrintStream类型
- 默认打印到控制台
- 重定向标准输出流
6.2. 重定向标准输入/出流
System.setOut();
七、打印流
7.1 PrintStream 字节输出流
7.2 PrintWriter 字符输出流
- 封装了print()/println()方法,支持写入后换行
//打印流,配合重定向输出流
public class Demo04 {
public static void main(String[] args) {
FileOutputStream fos = null;
//打印字节流
PrintStream ps = null;
try {
fos = new FileOutputStream("D:\\ceshi1.txt");
ps = new PrintStream(fos, true);
if (ps != null) {
//重定向输出流
System.setOut(ps);
}
for (int i = 0; i < 256; i++) {
System.out.print((char) i);
if (i % 50 == 0) {
System.out.println();
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
ps.close();
}
}
}
八、数据流
8.1 DataInputStream/DataOutputStream 数据输入流/输出流 字节流
方便操作Java语言的基本类型数据和String的数据,可以使用数据流。
九、对象流
9.1 ObjectOutputStream/ObjectInputStream
- 增强了缓冲区功能
- 增强了读写对象的功能
- readObject()
- 从流中读取一个对象
- writeObject(Object obj)
- 向流中写入一个对象
9.2 序列化,反序列化
- 序列化
- 把对象写入到硬盘或网络中的过程
- 反序列化
- 把硬盘或网络的二进制文件读取到内存形成对象的过程
对象序列化的细节
- 序列化类及其对象属性必须实现Serializable接口
- transient修饰为临时属性,不参与序列化
- 读取到文件尾部的标志:java.io.EOFException
- 使用serialVersionUID属性保证序列化的类和反序列化的类是同一个类
- static属性不参与序列化
手动序列化接口:Externalizable(必须有无参构造)
//手动序列化
//创建Student对象
public class Student implements Closeable, Externalizable {
private String name;
private transient int age;
private static final long serialVersionUID=100L;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public void close() throws IOException {
System.out.println("学生关闭了...");
}
//写入数据
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(age);
System.out.println("writeExternal");
}
//读取数据
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
name=in.readUTF();
age=in.readInt();
System.out.println("readExternal");
}
}
//序列化:也就是输出
public class ObjectOutputStreamDemo {
public static void main(String[] args) throws Exception{
//实现序列化功能:把对象写入到硬盘或网络中的过程。
//细节1:序列化类及其对象属性必须实现Serializable接口。
//细节2:transient修饰为瞬间(临时)属性,不参与序列化。
//细节3:读取到文件尾部的标志:java.io.EOFException。
//细节4:使用serialVersionUID属性保证序列化的类和反序列化的类是同一个类。
Student s1=new Student("AA", 20);
Student s2=new Student("AAA", 22);
Student s3=new Student("AAAA", 23);
ArrayList<Student> list=new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
//1创建对象流
FileOutputStream fos=new FileOutputStream("d:\\student.bin");
ObjectOutputStream oos=new ObjectOutputStream(fos);
//2序列化
oos.writeObject(list);
//3关闭
oos.close();
System.out.println("序列化完成...");
}
}
//反序列化:输入
public class ObjectInputStreamDemo {
public static void main(String[] args) throws Exception{
// 实现反序列化功能:把硬盘或网络的二进制文件读取到内存形成对象的过程。
//(1)创建流
FileInputStream fis=new FileInputStream("d:\\student.bin");
ObjectInputStream ois=new ObjectInputStream(fis);
//(2)反序列化
ArrayList<Student> list= (ArrayList<Student>) ois.readObject();
for (Student student : list) {
System.out.println(student.toString());
}
//(3)关闭
ois.close();
}
}
十、随机存取文件流
- RandomAccessFile既可以读取文件内容,也可以向文件中写入内容
- 但是和其他输入/输出流不同的是,程序可以直接跳到文件的任意位置来读写数据
- 读写模式
- r:只读
- rw:读写
- 作用
- 快速定位数据,并支持读写
- 方便的获取二进制文件
- 读写模式
public class RandomAccessFileDemo {
public static void main(String[] args)throws Exception {
//write();
read();
}
public static void write() throws Exception{
//1创建RandomAccessFile对象
RandomAccessFile raf=new RandomAccessFile("d:\\ran.txt", "rw");
//2写入
raf.writeUTF("灿灿");
raf.writeInt(20);
raf.writeBoolean(true);
raf.writeDouble(183.5);
raf.writeUTF("龙哥");
raf.writeInt(22);
raf.writeBoolean(false);
raf.writeDouble(183.6);
//3关闭
raf.close();
System.out.println("写入完毕");
}
public static void read() throws Exception{
//1创建RandomAccessFile对象
RandomAccessFile raf=new RandomAccessFile("d:\\ran.txt", "r");
//设置读取的指针的位置
//raf.seek(21);
//跳过指定的字节个数
raf.skipBytes(21);
//2读取
String name=raf.readUTF();
int age=raf.readInt();
boolean sex=raf.readBoolean();
double height=raf.readDouble();
System.out.println(name+"..."+age+"..."+sex+"..."+height);
//3关闭
raf.close();
}
}
public class RandomAccessFileDemo2 {
public static void main(String[] args) throws Exception{
ExecutorService es = Executors.newFixedThreadPool(4);
byte[] data=new byte[1024*1024];//1M
CountDownLatch countDownLatch=new CountDownLatch(4);
long start=System.currentTimeMillis();
for(int i=0;i<4;i++){
int n=i;
es.submit(new Runnable() {
@Override
public void run() {
RandomAccessFile raf= null;
try {
raf = new RandomAccessFile("d:\\电影.mp4", "rw");
System.out.println(Thread.currentThread().getName()+"开始下载了...");
raf.seek(n*(1024*1024));
raf.write(data);
Thread.sleep(2000);
raf.close();
System.out.println(Thread.currentThread().getName()+"下载完毕了...");
countDownLatch.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
});
};
es.shutdown();
countDownLatch.await();
long end=System.currentTimeMillis();
System.out.println("总用时:"+(end-start));
}
}
十一、Properties
- Properties:属性集合
- 特点
- 存储属性名和属性值
- 属性名和属性值都是字符串类型
- 没有泛型
- 和流有关
- 方法
- list(PrintStream/PrintWriter out)
- 将属性列表输出到指定的输出流
- load(InputStream/Reader in)
- 从输入流/输入字符中读取属性列表(键和元素对)
- store(OutputStream/Writer out,String comments)
- list(PrintStream/PrintWriter out)
public class PropertiesDemo {
public static void main(String[] args) throws Exception {
//1创建集合
Properties properties=new Properties();
//2添加数据
properties.setProperty("name", "张三");
properties.setProperty("age","20" );
properties.setProperty("address", "北京");
//3与流有关的方法
//-------1 list 使用打印流打印数据--------
properties.list(System.out);
//-------2 store 存储到硬盘---------------
FileOutputStream fos=new FileOutputStream("d:\\user.properties");
properties.store(fos,"注释");
fos.close();
//-------3 load 加载属性文件---------
System.out.println("------load-----");
Properties properties2=new Properties();
FileInputStream fis=new FileInputStream("d:\\user.properties");
properties2.load(fis);
fis.close();
properties2.list(System.out);
}
}