Java流的总结

一、流的简介

  • 流是用来读写文件数据的,在Java程序中,对于数据的输入,输出操作以”流“的方式进行。
  • 文件是硬盘上的一块存储空间,Java里面的类File是对其的抽象,封装了文件名。
  • 类比一下水流,文件可以看成小桶。水从小桶流出,就是输出,反之就是输入。
  • 输入与输出都是站在程序角度而言,所以流具有方向性。

二、流的分类

  • 处理的数据单位不同,可分为:

    • 字节流:InputStream OutputStream
    • 字符流:Reader Writer
  • 数据流方向不同,可分为:输入流,输出流

  • 功能不同,可分为:节点流与处理流

  • 网络操作:socket

  • 对象操作:Serializable

字符流和字节流的使用范围: 字节流一般用来处理图像,视频,以及PPT,Word类型的文件。字符流一般用于处理纯文本类型的文件,如TXT文件等,字节流可以用来处理纯文本文件,但是字符流不能用于处理图像视频等非文本类型的文件

节点流: 节点流从一个特定的数据源读写数据。即节点流是直接操作文件,网络等的流,例如FileInputStream和FileOutputStream,他们直接从文件中读取或往文件中写入字节流

处理流: “连接”在已存在的流(节点流或处理流)之上通过对数据的处理为程序提供更为强大的读写功能。过滤流是使用一个已经存在的输入流或输出流连接创建的,过滤流就是对节点流进行一系列的包装。例如BufferedInputStream和BufferedOutputStream,使用已经存在的节点流来构造,提供带缓冲的读写,提高了读写的效率,以及DataInputStream和DataOutputStream,使用已经存在的节点流来构造,提供了读写Java中的基本数据类型的功能。他们都属于过滤流,就像水流里面有杂质,你要过滤它,你可以再套一层管道过滤这些杂质一样

处理流类型

缓冲流:缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写效率,同时增加了一些新的方法

三、编码与解码

编码就是把字符转换为字节,而解码是把字节重新组合成字符。如果编码与解码方式不一致,就可能会出现乱码。

  • GBK编码中,中文字符占2个字节,英文字符占1个字节
  • UTF-8编码中,中文字符占3个字节,英文字符占1个字节
  • UTF-16be编码中,中文字符占2个字节,英文字符占2个字节

注:Java中的char类型是2个字节,16位,单个中文和英文都能存储
解决乱码问题:

Byte[] bytes = str.getBytes(String encodeCharName); //字符串编码为 byte 序列
str = new String(Byte[] bytes, String decodeCharsetName);  //重新对bytes进行编码,创建新的字符串对象
//两者结合使用
str = new String(str.getBytes(String encodeName), String decodeCharsetName);  //转码时getBytes必须以原有编码格式,否则依然乱码

// 创建指定字符集的 InputStreamReader
InputStreamReader(InputStream in, String CharsetName)

// 创建使用指定字符集的 OutputStreamWriter
OutputStreamWriter(OutputStream out, String CharsetName)

四、流的使用

一个简单的使用例子:

public static void main(String[] args) {
        int count = 0;

        String line = null;

        FileInputStream in = null;
        FileOutputStream out = null;

        BufferedReader reader = null;

        //读到数组中
        byte[] buffer = new byte[1024];
        System.out.println(buffer.length + " 长度");

        try {
             in = new FileInputStream("F:\\sparkTest\\io.txt"); //空格也算字节
             out = new FileOutputStream("F:\\sparkTest\\io3.txt");
             //windows默认文件以gbk存储,读取方式是utf-8
             reader = new BufferedReader(new InputStreamReader(new FileInputStream("F:\\sparkTest\\io.txt"), "gbk"));
        } catch (Exception e1) {
            e1.printStackTrace();
        }

        try {
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            /*while ((count = in.read(buffer, 0 , buffer.length)) != -1) {
                System.out.println(count);
                out.write(buffer, 0, count);
            }*/

            /*while ((count = in.read()) != -1) {   //返回的是字母代表的ASCII码
                //中文乱码
                System.out.println(count + " " + (char)count);
                out.write(count);
            }*/

            in.close();
            out.close();
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

流的具体API略过
流的读写:
字节流:

int read() throws IOException;   //单个字节读取,返回的数字是字符的ASCII
int read(byte b[]) throws IOException //读取字节到数组,返回实际字节数
int read(byte b[], int off, int len) throws IOException //off起始位置,len可读取的长度,返回值是实际读取字节数

注:写操作方法与此对应
字符流:

void write(int c) throws IOException;
write(char cbuf[]) throws IOException;  //char数组
void write(char cbuf[], int off, int len);

处理流的类还是比较多的,有BufferReader(缓冲流),InputStreamReader(转换流),DataInputStream(数据流)等等,请仔细阅读API
类图:

五、流的关闭

流关闭的顺序:先开启的后关闭,和栈有点类似
注: 流的打开一定需要关闭,finally可以保证,但是多重判断比较麻烦,可以使用try-with-resources

//1.7之前流的关闭
finally {
    if(in != null) {
        in.close();
    }
    if(in != null) {
        in.close();
    }
    if(in != null) {
        in.close();
    }
}

使用try-with-resources:

try (FileInputStream in = new FileInputStream("F:\\sparkTest\\io.txt");
     FileOutputStream out = out = new FileOutputStream("F:\\sparkTest\\io3.txt");
     BufferedReader reader =new BufferedReader(
             new InputStreamReader(new FileInputStream("F:\\sparkTest\\io.txt"), "gbk"));) {
      逻辑代码...
     } catch(Exeception) {}

try-with-resources在try()创建流会自动按顺序关闭流,代码看起来简洁很多
try-with-resources为什么能够避免大量资源释放代码呢?答案是,由Java编译器来帮我们添加finally代码块。注意,编译器只会添加finally代码块,而资源释放的过程需要资源提供者提供。

小知识

try catch finally中都有return语句,执行顺序是怎么样的呢?

public int test() {
    try {
        int i = 1;
        i = i / 0;
        return i;
    } catch (Exception e) {
        return -1;
    } finally{
        return -2;
    }
}

本例答案是-2
在i=i/0处代码抛出异常,进入catch方法,但是在return -1前会进入finall模块return -2
也就是finally会覆盖try和catch中的return语句

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值