java--IO流

IO流的概述

IO流用来处理设备之间的数据传输, 在Java中对数据的操作是通过流的方式进行的,Java用于操作流的对象都在IO包中,因此要导入IO包。

File类

File类是文件和目录路径名的抽象表现形式,它既可以用来表示目录,也可以用来表示文件。

代码演示

判断桌面是否有 .png 文件,有就输出该文件的绝对路径。

import java.io.File;

public class File1 {
    public static void main(String[] args) {
        //根据一个路径得到File对象
        File file = new File("C:\\Users\\Administrator\\Desktop");
        //调用listFiles()方法,来获取该目录下的所有文件
        File[] files = file.listFiles();
        //遍历文件数组
        for (File file1 : files) {
       //判断文件名是否以.png结尾,getName()是获得文件的名字,endsWith()是判断是否以某字符串结尾
            if(file1.getName().endsWith(".png")){
            //getAbsolutePath()方法获取绝对路径
                System.out.println(file1.getAbsolutePath());
            }
        }
    }
}

结果

C:\Users\Administrator\Desktop\File类.png
C:\Users\Administrator\Desktop\IO流.png
C:\Users\Administrator\Desktop\Map集合.png
C:\Users\Administrator\Desktop\异常.png

注:相对路径:没有带盘符的路径;绝对路径:带有盘符的路径;

字节流

FileOutputStream类

文件输出流(FileOutputStream)是用于将数据写入文件中的输出流,与FileInputStream一起使用。

FileInputStream

文件输入流(FileInputStream)是用于将文件中的数据读出来的流,它是与FileOutputStream一起使用的。

代码演示

把C:\Users\Administrator\Desktop\FileInputStream类.png的内容复制到C:\Users\Administrator\Desktop\FileInputStream类2.png中
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
//在输入输出流中可能会出现一些输入输出错误,因此要解决这些错误,你可以用到try..catch或throws
//要是不写的话IDE会报错
public class Demo {
    public static void main(String[] args) throws IOException{
        //创建一个输入流对象
        FileInputStream in = new FileInputStream("C:\Users\Administrator\Desktop\FileInputStream类.png");
        //创建一个输出流对象,如果该对象的文件不存在,就会创建这个文件
        FileOutputStream out = new FileOutputStream("C:\Users\Administrator\Desktop\FileInputStream类2.png");
        byte[] b=new byte[10];
        int len=0;
        //输入流对象用read方法把数据读入数组中,如果读到数据就返回数据的长度,如果没读到就返回-1
        while((len=in.read(b))!=-1){
        //输出流对象调用write(数组名,读这个数据从哪个位置写入,数据的长度 )方法,把数据写入文件中
            out.write(b,0,len);
        }
        //关闭流
        in.close();
        out.close();
    }
}

结果

注:用完流时,要关闭流,因为不关闭的话会占用资源(也可以说是被认为还在使用中,因此不能进行垃圾回收),长久下来就容易造成内存溢出。

BufferedOutputStream类

该类实现缓冲的输出流,通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统,一般也适合它配对的输入流一起使用(BufferedInputStream类)。

BufferedInputStream类

该类实现缓冲的输入流,可以通过此流读数据。(在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。)。

代码演示

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.FileOutputStream;

public class File11 {
    public static void main(String[] args) throws IOException {
        BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream("a.txt"));
        BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream("fox.txt"));
        byte[] bytes = new byte[100];
        int len=0;
        //把数据读到数组中,如果没有读到数据会返回-1
        while ((len=inputStream.read(bytes))!=-1){
            //调用write方法把数组中的数据写入到文件中,len为写入的个数,0为从该数据的开头位置
            outputStream.write(bytes,0,len);
            //该输出流必须刷新,不然数据不会写到文件中,其实不刷新也可以,最后关闭流时,会自动刷新,不过建议每写一次刷新一次,因为如果写入的东西太多,最后关闭流时刷新,会丢失数据
            outputStream.flush();
        }
        inputStream.close();
        outputStream.close();
    }
}

结果

 

字符流

字符流的出现是由于字节流操作中文不是特别方便,所以,java就提供了字符流。字符流:字符流 = 字节流 + 编码表

注:字符流写入时都需要刷新一下,否则数据写不到文件中。

OutputStreamWriter类

OutputStreamWriter 是字符流通向字节流的桥梁,它可使用指定的 charset(如:UTF-8,GB2312等编码) 将要写入流中的字符编码成字节。

InputStreamReader类

InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。

代码演示

键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低存入文本文件
public class Student {
    private String name;
    private int chinese;
    private int math;
    private int english;
    private int totalSocre;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getChinese() {
        return chinese;
    }

    public void setChinese(int chinese) {
        this.chinese = chinese;
    }

    public int getMath() {
        return math;
    }

    public void setMath(int math) {
        this.math = math;
    }
import java.io.*;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;

public class File9 {
    public static void main(String[] args) throws IOException {
        //创建输出流对象,FileOutputStream里的true表示可在数据后面追加数据,不会覆盖先前的数据
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("a.txt",true));
        //创建一个TreeSet对象,用来存放Student对象,并重写比较器,按总分从高到低排
        TreeSet<Student> set = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student t1, Student t2) {
                int v = t1.getTotalSocre() - t2.getTotalSocre();
                return (v==0)?(t1.getName().compareTo(t2.getName())):v;
            }
        });
        Scanner sc = new Scanner(System.in);
        for (int i = 1; i <= 5; i++) {
            Student student = new Student();
            System.out.println("请输入第"+i+"个学生的姓名:");
            student.setName(sc.next());
            System.out.println("请输入第"+i+"个学生的语文成绩:");
            student.setChinese(sc.nextInt());
            System.out.println("请输入第"+i+"个学生的数学成绩 :");
            student.setMath(sc.nextInt());
            System.out.println("请输入第"+i+"个学生的英语成绩:");
            student.setEnglish(sc.nextInt());
            set.add(student);
        }
        writer.write("姓名"+" "+"语文成绩"+" "+"数学成绩"+" "+"英语成绩"+" "+"总分");
        //写入一个回车换行,这样数据不会挤在一起,看着舒服些
        writer.write("\r\n");
        writer.flush();
        //遍历集合
        for (Student stu : set) {
            writer.write(stu.getName()+"    "+stu.getChinese()+"    "+stu.getMath()+"    "+stu.getEnglish()+"    "+stu.getTotalSocre());
            writer.write("\r\n");
            writer.flush();
        }
        writer.close();
    }
}

结果

请输入第1个学生的姓名:
jack
请输入第1个学生的语文成绩:
67
请输入第1个学生的数学成绩 :
78
请输入第1个学生的英语成绩:
89
请输入第2个学生的姓名:
sam
请输入第2个学生的语文成绩:
89
请输入第2个学生的数学成绩 :
67
请输入第2个学生的英语成绩:
56
请输入第3个学生的姓名:
jim
请输入第3个学生的语文成绩:
78
请输入第3个学生的数学成绩 :
89
请输入第3个学生的英语成绩:
34
请输入第4个学生的姓名:
lucy
请输入第4个学生的语文成绩:
67
请输入第4个学生的数学成绩 :
98
请输入第4个学生的英语成绩:
83
请输入第5个学生的姓名:
rose
请输入第5个学生的语文成绩:
78
请输入第5个学生的数学成绩 :
43
请输入第5个学生的英语成绩:
91

便捷类

OutputStreamWriter和的InputStreamReader名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,提供了对应的子类FileWriter和 FileReader,因此一样的用法。

字符缓冲流

BufferedWriter类

BufferedWriter写出数据,它是高效的字符输出流。

BufferedReader类

BufferedReader读取数据 ,它是高效的字符输入流。

代码演示

复制文件

import java.io.*;

public class File7 {
    public static void main(String[] args) throws IOException {
        //创建输入流对象,读的文件地址
        BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Administrator\\Desktop\\CopyFolderDemo.java"));
        //创建输出流对象,写的文件地址
        BufferedWriter writer = new BufferedWriter(new FileWriter("C:\\Users\\Administrator\\Desktop\\CopyFolderDemo2.java"));
        //读入一行数据(BufferedReader特有方法),如果没有的话就返回null值,并结束循环
        while (reader.readLine()!=null){
            //写入一行数据
            writer.write(reader.readLine());
            //写入回车换行(BufferedWriter特有方法)
            writer.newLine();
            //要刷新哟,不然数据写不进去
            writer.flush();
        }
        reader.close();
        writer.close();
    }
}

结果

打印流

打印流只能操作目的地,不能操作数据源(不能进行读取数据),可以操作任意类型的数据,调用print() 方法可以写任意数据类型,如果启用自动刷新,那么在调用println、printf 或 format 方法中的一个方法的时候,会完成自动刷新。

PrintWriter类

代码演示

import java.io.*;

public class File10 {
    public static void main(String[] args) throws IOException {
        //创建一个BufferedReader对象
        BufferedReader reader = new BufferedReader(new FileReader("a.txt"));
        //创建一个打印流对象
        PrintWriter print = new PrintWriter("C:\\Users\\Administrator\\Desktop\\fox.txt");
        //定义一个字符串变量
        String line=null;
        //把上面的字符串变量用来接收读到问一行数据,如果文件中没有数据就还是null,那就结束循环
        while ((line=reader.readLine())!=null){
            String s = line;
            //打印字符串到文件中
            print.println(s);
            //刷新流,不然写不进文件哟
            print.flush();
        }
        //关闭流
        reader.close();
        print.close();
    }
}

结果

随机访问流

RandomAccessFile类

RandomAccessFile最大的特点是能读能写,也可以操作任意数据类型的数据,它不属于流,是Object类的子类,但它融合了InputStream和OutputStream的功能,因此它支持对随机访问文件的读取和写入。

代码演示

import java.io.IOException;
import java.io.RandomAccessFile;

public class IODemo {
    public static void main(String[] args) throws IOException {
        //RandomAccessFile概述 最大特点 能读能写 能够获取文件指针的位置,也能够定位指针的位置
        writeData();

        redeData();

    }

    private static void redeData() throws IOException {
        RandomAccessFile rw = new RandomAccessFile("f.txt", "rw");
        //你怎么写的就怎么读取,读的格式和写的格式一样,如:先写了int类型,那就先读int类型
        int i = rw.readInt();
        long pointer = rw.getFilePointer();
        System.out.println("指针位置"+pointer);
        System.out.println(i);
        boolean b = rw.readBoolean();
        pointer = rw.getFilePointer();
        System.out.println("指针位置" + pointer);
        System.out.println(b);
        byte b1 = rw.readByte();
        pointer = rw.getFilePointer();
        System.out.println("指针位置" + pointer);
        System.out.println(b1);
        String s = rw.readUTF();
        pointer = rw.getFilePointer();
        System.out.println("指针位置" + pointer);
        System.out.println(s);
        System.out.println("-------------------");

        rw.seek(0);//定位指针的位置
        int  and= rw.readInt();
        System.out.println(and);
        rw.seek(6);
        String s1 = rw.readUTF();
        System.out.println(s1);


    }

    private static void writeData() throws IOException {

        RandomAccessFile rw = new RandomAccessFile("f.txt", "rw");
        //首先会先写入两个字节,然后才会把该数据写入,因此位置最后定位到4
        rw.writeInt(100);
        rw.writeBoolean(false);
        rw.writeByte(10);
        rw.writeUTF("你好");
        rw.close();
    }
}

结果

指针位置4
100
指针位置5
false
指针位置6
10
指针位置14
你好
-------------------
100
你好

序列化流和反序列化流

ObjectOutputStream类

序列化流(ObjectOutputStream)也就是把对象通过流存储到文件中,它也可以操作任意类型数据,还要注意的一点是必须要重写Serializable接口(这个接口中没有任何方法,只是起到了标记作用)才能被序列化,如果你不想要序列化,transient关键字可以声明不需要序列化的成员变量。

ObjectinputStream类

反序列化流(ObjectinputStream)也就是把文件中存储的对象以流的形式还原为对象,可以读任意类型数据。

代码演示

 1、通过序列化流与反序列化流完成从file.txt文件存取基本数据类型的操作 

import java.io.*;

public class MyDemo {
    public static void main(String[] args) throws IOException {
        //创建序列化流
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\file.txt"));
        //调用write方法写入数据,记得要刷新哟,不然写不进去哟
        outputStream.writeBoolean(true);
        outputStream.writeDouble(3.14);
        outputStream.writeInt(100);
        outputStream.flush();
        //创建反序列化流
        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\file.txt"));
        //怎么写就怎么读出来,按着写的顺序读出来
        System.out.println(inputStream.readBoolean());
        System.out.println(inputStream.readDouble());
        System.out.println(inputStream.readInt());
    }
}

结果

true
3.14
100

注:文件里存放的是乱码,只有读出来的时候才会还原成原来的数据。你可能会疑惑,不是要继承Serializable接口吗?为什么这里没有继承呢?,因为那是在对对象进行操作时才用到,这里是对基本数据类型进行操作。

2、通过序列化流与反序列化流完成从file.txt文件存取对象的操作

import java.io.Serializable;
//因为在主函数中要操作该对象,因此要实现这个接口,不过这个接口只是做标记作用,因此只要写上就好了
class Person implements Serializable {
        private String name;
        private transient int age;

    public Person (String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void setName (String name) {
        this.name = name;
    }

    public String getName () {
        return name;
    }

    public void setAge (int age) {
        this.age = age;
    }

    public int getAge(){
        return age;
    }
    //重写toString方法,以便于按照想要的格式输出
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}
import java.io.*;

class Test4 {
	public static void main(String[] args) throws IOException, ClassNotFoundException                {
		write();
		read();
	}

	public static void write() throws IOException {
		ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\file.txt"));
        //写入Person对象
		oos.writeObject(new Person("Tom", 20));
		oos.close();
	}
    //readObject()这个方法会抛出ClassNotFoundException这个错误,因此要加上
	public static void read() throws IOException, ClassNotFoundException {
		ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\file.txt"));
        //读出Person对象
		Object obj = ois.readObject();
        //这里会自动调用toString方法,这个方法在上面的Person类中有重写,因此会按照重写的格式输出
		System.out.println(obj);
		ois.close();
	}
}

结果

Person [name=Tom, age=0]

你可能会疑惑,明明把年龄都输入为20了怎么输出是0呢?因为transient修饰了age,transient修饰的变量不参与序列化过程(也就是写入的过程没参与),因此它没赋上值,所以为0,存到的文件夹里的数据也是乱码哟。

Properties类的概述

Properties 类表示了一个持久的属性集,它可保存在流中或从流中加载,它的列表中每个键及其对应值都是一个字符串,并且其父类是Hashtable,属于双列集合,这个集合中的键和值都是字符串 ,但是它不能指定泛型。

代码演示

 有一个file.txt文件,判断是否有"lisi"这样的键存在,如果有就改变其实为"100"

 file.txt文件内容如下:

                             zhangsan = 90

                             lisi = 80

                             wangwu = 85

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

 public class MyDemo2 {
    public static void main(String[] args) throws IOException {
        //创建一个Properties对象
        Properties properties = new Properties();
        //加载路径下的文件
        properties.load(new FileInputStream("C:\\Users\\Administrator\\Desktop\\file.txt"));
        //判断该文件是否有lisi这个键值存在,有就把对应的值改成100
        if(properties.containsKey("lisi")){
            //因为文件中存的是字符串,因此要把int类型转换成String类型,然后用put方法把值给覆盖
            properties.put("lisi", String.valueOf(100));
            //覆盖好值之后,要把值给存到文件中,这后面的null是注释,当你不知道要写什么你可以null
            properties.store(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\file.txt"),null);
            System.out.println("修改成功");
        }
    }
}

结果

修改成功

注:这上面的那一串时间就是你填写null值得结果,你可以随意些一个字符串,写进文件时会变为 #你写的字符串 这样的格式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值