转换流、文件拷贝案例和字符编码

一、字节流vs字符流

在实际开发中,字节流一定是优先考虑的,只有在处理中文时才会考虑字符流。因为所有的字符都需要通过内存缓冲来进行处理。所有字符流的操作,无论是输入还是输出,数据都先保存在缓存中。

1.字节流输出和字符流输出的区别

如果字符流不关闭,数据就有可能保存在缓存中并没有输出到目标源。这种情况下,必须强制刷新才能得到完整数据。

package com.xunpu.myio;

import java.io.*;

/**
 * 字符流的强制刷新操作
 */
public class TestFlush {
    public static void main(String[] args) {
        File file=new File(File.separator+"E:"+File.separator+"JavaFile"+File.separator+
        "Directory"+File.separator+"bbb"+File.separator+"hello.txt");
        if(!file.getParentFile().exists()){
            file.mkdirs();//如果父文件对象不存在,就递归创建父目录。
        }
        try(Writer writer=new FileWriter(file);
        Reader reader=new FileReader(file)) {
            //写数据
            writer.write("hello world");
            //读数据
            char[] chars=new char[1024];
            int len=reader.read(chars);
            String res=new String(chars);
            System.out.println("文件内容为:"+res);//此时没有内容输出,这是因为writer没有刷新到缓冲区
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

此时结果为:

这是因为数据保存在缓冲区。解决办法:强制刷新缓冲区中的数据

package com.xunpu.myio;

import java.io.*;

/**
 * 字符流的强制刷新操作
 */
public class TestFlush {
    public static void main(String[] args) {
        File file=new File(File.separator+"E:"+File.separator+"JavaFile"+File.separator+
        "Directory"+File.separator+"bbb"+File.separator+"hello.txt");
        if(!file.getParentFile().exists()){
            file.mkdirs();//如果父文件对象不存在,就递归创建父目录。
        }
        try(Writer writer=new FileWriter(file);
        Reader reader=new FileReader(file)) {
            //写数据
            writer.write("hello world");
            writer.flush();//强制刷新
            //读数据
            char[] chars=new char[1024];
            int len=reader.read(chars);
            String res=new String(chars);
            System.out.println("文件内容为:"+res);//此时没有内容输出,这是因为writer没有刷新到缓冲区
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

二、转换流

转换流就是将字节流转换为字符流的流。字符流类中提供了把字节流转换为相应字符流的类:

public class OutputStreamWriter extends Writer;
实现方法:OutputStreamWriter类的构造方法:
public OutputStreamWriter(OutputStream out);

public class InputStreamReader extends Reader;
实现方法:InputStreamReader类的构造方法:
public InputStreamReader(InputStream in)

使用方法:

package com.xunpu.myio;

import java.io.*;

/**
 * 测试将字节流转换为字符流
 */
public class TestChange {
    public static void main(String[] args) throws IOException {
        File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
                +File.separator+"aaa.txt");
        OutputStream out=new FileOutputStream(file);
        OutputStreamWriter writer=new OutputStreamWriter(out);//将输出字节流转换为字符流
        writer.write("The weather is fine");
        writer.close();
        InputStream in=new FileInputStream(file);
        InputStreamReader reader=new InputStreamReader(in);//将输入字节流转为输入字符流
        char[] chars=new char[1024];
        int len = reader.read(chars);
        String res=new String(chars);
        System.out.println("文件内容为:"+res);
    }
}

三、文件拷贝案例

思路:

/**
 * 实现文件拷贝(通过传参数的方式)
 * 1.判断拷贝的源文件(args[0])是否存在。
 *   1.1 如果不存在,则抛出异常(FileNotFoundException)
 *   1.2 如果存在,进行下一步操作
 * 2.判断目的文件(args[1])的父路径是否存在。
 *   2.1 如果不存在,则递归创建父路径,继续下一步。
 *   2.2 如果存在,什么也不做。
 * 3.进行文件的拷贝工作。
 *   从源文件中读取数据,同时向目的文件中写入数据。直到读源文件到末尾。
 */
package com.xunpu.myio;

import java.io.*;

/**
 * 实现文件拷贝
 * 1.判断拷贝的源文件(args[0])是否存在。
 *   1.1 如果不存在,则抛出异常(FileNotFoundException)
 *   1.2 如果存在,进行下一步操作
 * 2.判断目的文件(args[1])的父路径是否存在。
 *   2.1 如果不存在,则递归创建父路径,继续下一步。
 *   2.2 如果存在,什么也不做。
 * 3.进行文件的拷贝工作。
 *   从源文件中读取数据,同时向目的文件中写入数据。直到读源文件到末尾。
 */
public class CopyFile {
    public static void main(String[] args) throws IOException {
        if(args.length!=2){
            System.out.println("不符合拷贝文件要求,请给出源文件路径和目的文件路径,重新尝试");
            return;
        }
        //1.判断源文件是否存在
        boolean isSourceexist=sourceFileIsExisted(args[0]);
        if(!isSourceexist){
            System.out.println("源文件不存在,拷贝失败!");
            throw new FileNotFoundException();
        }
        //2.判断目的文件的父目录对象是否存在,不存在则创建。
       isParentDirectory(args[1]);
        //3.进行文件拷贝
        File res=copyFile(args[0],args[1]);
        //打印出文件的内容
        Reader reader=new FileReader(res);
        char[] data=new char[1024];
        int len=reader.read(data);
        String str=new String(data,0,len);
        System.out.println("文件内容为:"+str);
    }

    //文件拷贝具体实现
    private static File copyFile(String srcPath, String desPath) throws IOException {
        File src=new File(srcPath);
        File des=new File(desPath);
        //定义输出流
        InputStream in=new FileInputStream(src);
        InputStreamReader reader=new InputStreamReader(in);
        //定义输入流
        OutputStream out=new FileOutputStream(des);
        OutputStreamWriter writer=new OutputStreamWriter(out);

        //进行文件的拷贝
        int len=0;
        char[] data=new char[1024];
        while((len=reader.read(data))!=-1){
            writer.write(data,0,len);
        }
        writer.flush();//强制刷新缓冲区的字符
        return des;
    }

    //判断目的文件的父目录对象是否存在
    private static void isParentDirectory(String desPath) {
        File file=new File(desPath);
        if(!file.getParentFile().exists()) {//取得父File对象,并判断是否存在。
            file.mkdirs();//如果不存在,则递归创建。
        }
    }

    //判断源文件是否存在
    private static boolean sourceFileIsExisted(String sourcePath) {
        File file=new File(sourcePath);
        return file.exists();
    }
}

将配置环境变量设置为:

注意:在使用字符流写文件时,一定要使用writer.flush()将缓冲区的数据刷新!!!

四、字符编码

在计算机的世界里,所有的文件都是通过编码来描述的。

1.常见的编码

1)描述中文的编码:GBK、GB2312:国标编码,GBK支持简体中文和繁体中文,而GB2312只包含简体中文。

2)支持所有的文字信息:UNICODE编码,Java提供的16进制编码,可以描述世界上任意的文字信息。缺点是:编码较庞大,会造成网络传输上的负担。

3)国际通用编码:ISO8859-1,单字节编码,向下兼容ASCII码,其编码范围是0X00~0XFF.缺点:所有的编码都需要进行转换。

4)UTF编码:结合了UNICODE编码和ISO8859-1编码。如果使用16进制文字就使用UNICODE;如果是字母就使用ISO8859-1。常用的是UTF-8编码。

2.查看操作系统中Java默认支持的编码

package com.xunpu.myio;

/**
 * 测试字符编码
 */
public class TestCode {
    public static void main(String[] args) {
        System.getProperties().list(System.out);//获取Java运行属性
    }
}

结果截取一部分:

sun.jnu.encoding=GBK是操作系统中的默认编码,而file.encoding=UTF-8是我们自己设置的。

3.观察乱码

如果本地系统所用的编码和程序所用编码不同,那么强制转换就会出现乱码。

package com.xunpu.myio;

import java.io.*;

/**
 * 测试字符编码
 */
public class TestCode {
    public static void main(String[] args) throws IOException {
        File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
                +File.separator+"aaa.txt");
        OutputStream out=new FileOutputStream(file);
        out.write("你好,我是xxx".getBytes("ISO8859-1"));//设置编码格式为ISO8859-1
        out.close();
    }
}

结果:

改正方法为:

package com.xunpu.myio;

import java.io.*;

/**
 * 测试字符编码
 */
public class TestCode {
    public static void main(String[] args) throws IOException {
        File file=new File("E:"+File.separator+"JavaFile"+File.separator+"Directory"+File.separator+"bbb"
                +File.separator+"aaa.txt");
        OutputStream out=new FileOutputStream(file);
        out.write("你好,我是xxx".getBytes("GBK"));//或者设置为UTF-8
        out.close();
    }
}

结果:

乱码产生的本质:编码和解码不统一。

建议:以后使用UTF-8编码!!!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值