Java IO

一、核心类

java.io下的类

File 文件类、InputStream字节输入流、OutputStream字节输入流、Reader字符输入流、Writer字符输出流

接口

Closeable关闭流接口、Flushable刷新流接口、Serializable序列化接口

二、流分类

按方向:输入流、输出流;

按功能:节点流(直接操作数据源)、处理流也叫包装流(间接操作数据源,对 流进行封装,主要是简化操作和提高性能);

按数据:字节流、字符流(底层基于字节流)。

三、文件编码

编码(encode):字符 -> 字节

解码(decode):字节 ->字符 

UTF-8编码英文是一个字节,中文是三个字节

四、乱码产生的原因

1、乱码产生的原因-字节数不够

Demo(使用UTF-8编码)

文件中的内容

@Test
    public void flushRead(){
        File file = new File("sources/123.txt");
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            //批量读取
            byte[] flush = new byte[3];
            int len;
            while ( (len = inputStream.read(flush)) != -1){
                String s = new String(flush,0,len);
                System.out.println(s);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (null != inputStream){
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

每次读取三个字节,运行结果如下

每次读取三个字节

第一次,"q","w","e"三个英文,在UTF-8中每个英文占一个字节,可以正常打印;

第二次,读取的三个字节中 "r"占一个字节,剩下2个字节都来自汉字"中","中"占三个字节,这一次只读取到了两个字节,所以汉字"中"不能正常打印;

第三次,读取的是汉字"中"的第三个字节,和汉字"文"的前两个字节,打印出现乱码;

第四次,读取的是汉字"文"的第三个字节,打印出现乱码

2、乱码产生的原因-编码和解码使用的字符集不统一

Demo

 @Test
    public void decode() throws UnsupportedEncodingException {
        String s = "哈哈哈h";
        //编码 默认使用工程的编码方式UTF-8
        byte[] bytes = s.getBytes();
        //使用相同字符集 可以正常打印
        s = new String(bytes,0,bytes.length, StandardCharsets.UTF_8);
        System.out.println(s);
        //字符集不统一 出现乱码
        s = new String(bytes,0,bytes.length-2,"gbk");
        System.out.println(s);
    }

运行结果

五、文件分割与合并

效果

源文件

分割后的文件

合并后的文件

代码

package com.neusiri.io.stream.base.splitfile;

import lombok.Data;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

/**
 * @author zhangdj
 * @date 2019/10/8
 */
@Data
public class SplitFile {

    /**
     * 源文件路径
     */
    private File src;

    /**
     * 源文件大小
     */
    private long srcSize;

    /**
     * 目标文件夹
     */
    private String dest;

    /**
     * 每块大小
     */
    private int blockSize;

    /**
     * 块数
     */
    private int blockNum;

    /**
     * 文件扩展名
     */
    private String extName;

    /**
     * 文件分割后的存储路径
     */
    private List<String> destPaths;

    /**
     * 构造方法
     * @param srcPath 源文件路径
     * @param dest 分割文件存储的位置
     * @param blockSize 分割文件每块大小
     * @throws Exception
     */
    public SplitFile(String srcPath, String dest, int blockSize) throws Exception {
        this.src = new File(srcPath);
        this.dest = dest;
        this.blockSize = blockSize;
        init();
        split();
    }

    /**
     * 初始化源文件大小并计算块数
     */
    private void init() {
        //源文件大小
        this.srcSize = this.src.length();
        //块数
        this.blockNum = (int) Math.ceil(srcSize * 1.0 / this.blockSize);
        //扩展名
        String srcName = src.getName();
        int index = srcName.lastIndexOf(".");
        this.extName = srcName.substring(index);
        //分割文件路径
        this.destPaths = new ArrayList<>();
        for (int i = 0; i < blockNum; i++) {
            destPaths.add(dest + "/" + i + "-" + src.getName());
        }
    }

    /**
     * 分割文件
     *
     * @throws Exception
     */
    private void split() throws Exception {
        //开始位置
        long beginPos = 0;
        //每次读取的实际长度(如果文件大小比每块大小还小,取文件的大小,否则取每块大小)
        long len = (blockSize > srcSize ? srcSize : blockSize);
        for (int i = 0; i < blockNum; i++) {
            //开始位置随着分割会改变
            beginPos = i * this.blockSize;
            if (i != blockNum - 1) {
                len = blockSize;
                srcSize -= len;
            } else {
                len = srcSize;
            }
            splitFile(i, beginPos, len);
        }
    }

    /**
     * 文件分割方法(读取文件时,取较小的长度)
     *
     * @param i        块数
     * @param beginPos 起始位置
     * @param len      读取长度
     * @throws Exception 异常
     */
    private void splitFile(int i, long beginPos, long len) throws Exception {
        //获取切割后的文件名
        String splitFileName = destPaths.get(i);
        RandomAccessFile reader = new RandomAccessFile(src, "r");
        RandomAccessFile writer = new RandomAccessFile(splitFileName, "rw");
        reader.seek(beginPos);
        byte[] flush = new byte[1024];
        int actualSize;
        while ((actualSize = reader.read(flush)) != -1) {
            //想要读取的长度 比实际读取的长度大 取实际长度
            if (len >= actualSize) {
                writer.write(flush, 0, actualSize);
                //想要读取的长度减去已经读取的长度
                len -= actualSize;
            } else {
                //想要读取的长度 比实际读取长度小  取想要的长度
                writer.write(flush, 0, (int) len);
                break;
            }
        }
        reader.close();
        writer.close();
    }

    /**
     * 合并文件
     * 可以用SequenceInputStream将多个输入流进行合并 也可以分别操作输入流
     * @param mergeDest 合并文件存放的位置
     * @throws Exception
     */
    private void merge(String mergeDest) throws Exception {
        //输出流
        OutputStream outputStream = new FileOutputStream(mergeDest + "/merge" + extName, true);
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
        Vector<InputStream> vector = new Vector<>();
        SequenceInputStream sequenceInputStream = null;
        //遍历切割文件
        for (String path : destPaths) {
            InputStream inputStream = new FileInputStream(path);
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
            //将输入流放入容器
            vector.add(bufferedInputStream);
        }
        //实例化SequenceInputStream
        sequenceInputStream = new SequenceInputStream(vector.elements());
        byte[] flush = new byte[1024];
        int actualSize;
        //读取文件内容并且追加写入新的文件
        while ((actualSize = sequenceInputStream.read(flush)) != -1) {
            bufferedOutputStream.write(flush, 0, actualSize);
        }
        bufferedOutputStream.flush();
        sequenceInputStream.close();
        bufferedOutputStream.close();
    }

    /**
     * 测试
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        String srcPath = "src/main/resources/2019.09.10.jpg";
        String destPath = "src/main/resources/dest";
        int blockSize = 1024 * 10;
        SplitFile splitFile = new SplitFile(srcPath, destPath, blockSize);
        splitFile.merge("src/main/resources/mergedest");
        System.out.println(splitFile);
    }
}

 

 

 

 

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值