java io流 字节流(节点流、处理流)字符流(节点流、处理流)对象流 ,对象流序列化,打印流 PrintStream、PrintWriter,以及Properties 类集合对文件的处理

首先来看一个字节流和字符流与处理流的应用:

package javaIO.com;
import java.io.IOException;
import java.io.*;


//文件字节流转字符流复制

public class TestIO {
    public static void main(String[] args) {
        BufferedInputStream in=null;
        PrintStream out=null;
        try{
             in = new BufferedInputStream(new FileInputStream( "D:\\student_file.txt"));
            out = new PrintStream( new
                    BufferedOutputStream( new FileOutputStream("D:\\student_score.txt")));
            System.setIn(in); System.setOut(out); System.setErr(out);
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String s;
            while((s = br.readLine()) != null) System.out.println(s);
            System.out.println("复制成功!!!!");
        }
        catch(IOException iox){
            System.out.println("复制失败!!!!!");
        }finally {
            try {
                in.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

那为什麽需要将字节流转换成字符流呢?因为我们一般的文档都是UTF-8格式编码的;不管用字节流还是字符流进行复制都是可以的,不会出现乱码,但如果是其他格式的编码呢?比如gbk或者是其他的编码,在读取过程中就可能出现乱码;当然处理流呢只是多了一个缓冲区,更能够实现更多类的对象的处理,比如说字符串,数组等其流的统一处理

那为了解决不同编码文件所带来的问题;我们来看看下面这个例子:

首先看从指定编码的文件内容读出的例子:

package javaIO.com;

import java.io.*;

@SuppressWarnings({"all"})
public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        Test1();
    }

    //演示使用 InputStreamReader 将字节流转换为字符流
//将字节流 FileInputStream 转成字符流 InputStreamReader,指定编码 gbk/utf-8/utf8
    public static void Test1() throws IOException{
        String sc="D:\\student_file.txt";
        BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(sc),"utf-8"));
        String s;
        System.out.println("读取内容:");
        while((s= br.readLine())!=null){
            System.out.println(s);
        }
        br.close();//关闭外层流
    }
}

接下来我们看对一些内容进行复制并改变编码的例子:

package javaIO.com;

import java.io.*;

@SuppressWarnings({"all"})
public class InputStreamReader_ {
    public static void main(String[] args) throws IOException {
        Test2();
    }

   
    //演示使用 OutputStreamWriter 将字节流转换为字符流
//将字节流 FileOutputStream 转成字符流 OutputStreamWriter,指定编码 gbk/utf-8/utf8
    public static void Test2() throws IOException{
        String sc="D:\\majunyi.txt";//输出文件
        BufferedWriter bs=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(sc),"utf-8"));
        bs.write("风煞 JAVA");
        bs.newLine();//换行
        String scr="D:\\student_file.txt";//输入文件
        BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream(scr),"gbk"));
        String s;
        while((s= br.readLine())!=null){
            bs.write(s);
            bs.newLine();
        }
        bs.close();
        br.close();//必须关闭,否则副本中无内容
        System.out.println("复制成功!!!");
    }
}

注意:在进行文件复制时结束后必须要关流(bs.close();)或者刷新(bs.flush();),否则看不到任何内容,因为只有在关流或者刷新后文件才会开始在硬盘中开始复制。

下面我们来看一下用字符流与处理流相结合实现文本本文档的复制:

package javaIO.com;

import java.io.IOException;
import java.io.*;


//文件字符流复制

@SuppressWarnings({"all"})//镇压警告
public class TestIO {
    public static void main(String[] args) {
        String line;
        BufferedWriter dest=null;
        BufferedReader source=null;
        try{
            dest=new BufferedWriter(new FileWriter("D:\\student_file.txt",true));//以追加的方式复制
            source=new BufferedReader(new FileReader("D:\\studentscore.txt"));
            line=source.readLine();//按行读取
            while(line!=null){
                dest.write(line);
                dest.newLine();//换行
                line=source.readLine();
            }
            System.out.println("复制成功........");
        }catch (IOException e){
            e.fillInStackTrace();
        }finally {
            try{
                dest.close();
                source.close();
            }catch (IOException e){
                e.fillInStackTrace();
            }
        }
    }
}
    

注意:在这里我们直接用字节流对文本文件进行复制也是没有问题的,我就不演示了

另外我们来看一下图片或者视频的复制;当然这里就应该用字节流处理了:

package javaIO.com;

import java.io.IOException;
import java.io.*;

public class TestIO {
    public static void main(String[] args) {
        JpgTest();
    }

//图片复制
    public static void JpgTest(){
        String srcFilePath="D:\\majunyi.jpg";
        String dastFilePath="D:\\zhangyi.jpg";
        BufferedInputStream bis=null;
        BufferedOutputStream bos=null;
        try {
            bis=new BufferedInputStream(new FileInputStream(srcFilePath));
            bos=new BufferedOutputStream(new FileOutputStream(dastFilePath));
            byte[] buff=new byte[1024];
            int readLen=0;
            while((readLen= bis.read(buff))!=-1){
                bos.write(buff,0,readLen);
            }
            System.out.println("文件拷贝完毕!!!");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {//关闭文件!
           try {
               if(bis!=null){
                   bis.close();
               }
               if (bos!=null){
                   bos.close();
               }
           }catch (IOException e){
               e.printStackTrace();
           }
        }
    }
}

注意:这里

byte[] buff=new byte[1024];
int readLen=0;
while((readLen= bis.read(buff))!=-1){
    bos.write(buff,0,readLen);
}

不管对图片复制还是对视频复制;如果用字节数组时必须用readLen记录bis.read(buff)读到的字节数,用 bos.write(buff,0,readLen);写入指定长度的字符数组;否则将出错,因为在结束时不一定读到整个字节数组的字节,图片和视频的复制要求是比较严格的,大家要注意。

最后我为大家介绍对象流实现数据的序列化;

那什么是数据的序列化呢?比如我们平时要保存一个 int类型的100;我们可以直接写入100;但他是以一个int类型的100保存还是一个字符串或者是其他的东西呢?

所以简单来说数据的序列化就是不仅要存数据还要保存数据的类型;但是如果要实现对象的序列化,那么这个类一定要实现Serializable接口,(还可以实现另外一个接口,但由于Serializable是一个空接口里面没有方法,不需要进行覆写,所以一般实现Serializable接口更方便)而且基本数据类型都是直接或间接实现Serializable接口的,所以可以对任意基本数据类型的对象序列化,其他对象的序列化必须实现Serializable接口。

我们先来看对一些基本数据和某各类的对象进行序列化的例子:

package javaIO.com;


import java.io.IOException;
import java.io.*;



@SuppressWarnings({"all"})
class Dog implements Serializable{//如果要序列化某个对象,必须实现 Serializable 接口
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}



@SuppressWarnings({"all"})//镇压警告
public class TestIO {
    public static void main(String[] args) throws Exception{
         ObjectOutputStreamTest();
    }


//演示ObjectOutputStream的数据序列化
    public static void ObjectOutputStreamTest() throws Exception{
        //序列化后,文件保存格式不是文本,而是按照他自己的格式来保存
        String filepath="D:\\date.dat";
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(filepath));


        //Java 的序列化不能对 static 和 transient(短暂的)修饰的属性进行保存
        // 也就是说Java 不能序列化tatic 和 transient(短暂的)修饰的属性
        //序列化数据到D:\\date.dat
        oos.writeInt(129);//int -> Integer (实现了 Serializable)
        oos.writeBoolean(true);//boolean -> Boolean (实现了 Serializable)
        oos.writeChar('K');//char ->Character (实现了 Serializable)
        oos.writeUTF("风煞.JAVA");//String

        //保存一个Dog 对象  构造Dog类
        oos.writeObject(new Dog("旺财",4));

        oos.close();//关流
        System.out.println("数据保存完毕!!!");
    }
}


接下来我们试着将刚才序列化的数据反序列化读出:

package javaIO.com;


import java.io.IOException;
import java.io.*;



@SuppressWarnings({"all"})
class Dog implements Serializable{//如果要序列化某个对象,必须实现 Serializable 接口
    private String name;
    private int age;

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

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

@SuppressWarnings({"all"})//镇压警告
public class TestIO {
    public static void main(String[] args) throws Exception{

    }

//演示ObjectInputStream的数据反序列化
    public static void ObjectInputStreamTest() throws Exception{
       //数据反序列化文件
        String filepath="D:\\date.dat";
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(filepath));


        //反序列化数据读取顺序必须与序列化保存时顺序相同!!!!  否则会出现异常
        System.out.println(objectInputStream.readInt());
        System.out.println(objectInputStream.readBoolean());
        System.out.println(objectInputStream.readChar());
        System.out.println(objectInputStream.readUTF());
       // System.out.println(objectInputStream.readObject());  将会抛出异常!!!
        Object dog =objectInputStream.readObject();
        System.out.println("Object o 运行类型"+dog.getClass());
        System.out.println("dog 信息:"+dog);
        objectInputStream.close();//记得关流
        System.out.println("数据读出成功!!!");
        //试着调用dog的get方法
        //由于此时的dog时Object类的,调用get方法需要进行向下转型
        Dog dog1=(Dog) dog;
        System.out.println("名字:"+dog1.getName());
        System.out.println("年龄:"+dog1.getAge());
    }
}

注意:反序列化数据读取顺序必须与序列化保存时顺序相同!!!!  否则会出现异常

下面来看看打印流吧:

package javaIO.com;

import org.junit.jupiter.api.Test;

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;

// java io流 打印流 PrintStream(字节流) 和PrintWriter(字符流)
public class PriintFile_ {
    public static void main(String[] args) {
        
    }

    @Test
    public void PrintWriter_() throws IOException{
        PrintWriter printWriter=new PrintWriter(new FileWriter("D:\\PrintStream_.txt"));
        printWriter.println("manuidshybgfheswd");
        printWriter.close();
    }

    @Test
    public void PrintStream_() throws IOException{
        PrintStream out= System.out;
        // 在默认情况下, PrintStream 输出数据的位置是 标准输出,即显示器
        out.print("jhon,hello");
        // 因为print的底层是调用write 实现的,因此也可以这样操作
        out.write("majunyi".getBytes(StandardCharsets.UTF_8));


        // 打印流 PrintStream(字节流) 可以更改输出位置
        System.setOut(new PrintStream("D:\\PrintStream_.txt"));
        System.out.println("majnuyi");
        out.print("majunyi_txt");
        out.close();
    }
}

看到这里是不是觉得眼熟呢,在文章开头就有介绍啦,它可以用来确定流的打印位置。

另外在上面一段代码中我使用了java 的JUnit 测试框架( @Test ),如果有不懂的朋友呢,我在我的另一篇文章(java 泛型 及 java JUnit 测试框架) 中配有截图和详细讲解,大家可以去进行参考。

那么现在就是我们的 Properties 类对文件的操作啦:

首先来看一下如果没有Properties 类我们如何对文件进行操作:

先看看我们mysql.properties 文件中的内容:

 接下来我们需要将指定的内容读出:

public class propertiesFile {
    public static void main(String[] args)  throws IOException{
        Test01();
    }

    // 普通方法读取文件想要的内容:
    public static void Test01() throws IOException {
        // 读取mysql.properties 文件,并得到ip,User,和 pwd
        BufferedReader reader = new BufferedReader(new FileReader("src\\mysql.properties"));
        String s=null;
        while ((s=reader.readLine())!=null){
            // s只要后面部分需要对字符串进行拆分
            String[] split = s.split("=");
            System.out.println(split[0]+"是"+split[1]);
        }
    }
}

运行示例:

那这样如果需要创建文件和实现对文件进行更改都是比较麻烦的,那让我们来看看 Properties 类所能实现的功能吧:

package javaIO.com;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

// 演示 properties 类对文件的操作
public class propertiesFile {
    public static void main(String[] args)  throws IOException{
        Test02();
        Test03();
    }

    

    /**
     *  properties 使用示例
     *  常用方法:
     *  1. load:加载配置文件的键值对到 Properties 对象
     * 2. list: 将数据显示到指定设备 流对象
     * 3. getProperty(key): 根据键获取值
     * 4.setProperty(key,value): 设置键值对到Properties 对象
     * 5. store: 将Properties中的键值对储存到配置文件,在IDEA 中,保存信息到配置文件,如果含有中文,会存储为Unicode码
     */
    public static void Test02() throws IOException{
        // 1. 创建 Properties 对象
        Properties properties = new Properties();
        // 2. 加载 src\mysql.properties 文件
        properties.load(new FileReader("src\\mysql.properties"));
        // 3. 把 K-V 显示出来
        properties.list(System.out);
        // 4. 根据 Key 获取
        System.out.println(properties.getProperty("User")+"\n"+
                properties.getProperty("ip")+"\n"+properties.getProperty("pwd")+"\n\n\n\n");


    }



    /**
     * 1. 使用Properties 类对mysql.properties 的读取
     * 2. 使用Properties 类添加Key-Value 到新文件 mysql2.properties 中
     * 3. 使用Properties 类完成对mysql.properties 的读取,并修改某个值
     * 注意: Properties 的底层为Hashtable, 则其底层核心代码为 Hashtable
     */
    public static void Test03() throws IOException{
        // 使用Properties 类来对文件内容进行配置
        Properties properties = new Properties();
       // 创建
        properties.setProperty("charset","UTF-8");
        properties.setProperty("User","汤姆");// 中文保存为 Unicode 码
        properties.setProperty("pwd","abc1234");

        // 将K-V 存储到文件中即可
        properties.store(new FileOutputStream("src\\mysql2.properties"),"majnuyi");
        // 第二个参数代表文件的注释 null 代表没有注释

        // 修改 setProperty,如果存在Key,则为修改,若key 存在,则为创建
        properties.setProperty("User","tom-jact");
        properties.store(new FileOutputStream("src\\mysql2.properties"),"majnuyi");
    }
}

 来看看运行效果吧:

现在 mysql2.properties 文件中的内容:

 

 我的演示及讲解就到这里啦,还有很对方法希望大家下来自己研究呢,我展示的只是平时较为常用的方法,谢谢大家,有问题评论区留言哦!!!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风煞

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值