Java 流的总结

一、流的简介

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

二、流的分类

  • 字符流与字节流
    字节流:InputStream OutputStream
    字符流:Reader Writer

  • 节点流与处理流

  • 网络操作:socket

  • 对象操作:Serializable

三、编码与解码

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

  • 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语句

猜你喜欢

转载自blog.csdn.net/LJJZJ/article/details/84890372
今日推荐