Java基础教程——字节流

Posted tigerlion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java基础教程——字节流相关的知识,希望对你有一定的参考价值。

IO流

技术图片

水流 特点
连续性 逝者如斯夫,不舍昼夜;
方向性 一江春水向东流。水往低处流。百川东到海,何时复西归?少壮不努力,老大徒伤悲!
源头尽头 唯有源头活水来;覆水难收

Java里的IO也有这样的特点。

IO:数据从硬盘流向内存(Input),或者从内存流向硬盘(Output)。

技术图片

IO流分类:

按照流的流向来分:输入流、输出流。
|-输入流:读入内存。
|-输出流:写出到硬盘等设备。

按操作数据单元分:字节流、字符流
|-字节流:8位
|-字符流:16位

按流的角色分:节点流、处理流。
|-节点流:特定的IO设备(如硬盘),也叫低级流
|-处理流:经过封装的流,也叫高级流、包装流,可以消除不同节点流的差异(典型的装饰器模式)

Java的IO流有40多个类,高抽象层的基类有四个:

字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

字节流

字节流:100100011010100010

可以操作所有文件,包括文本文件、视频、音频、压缩文件等等都可以用字节流读写。

两个重要的抽象类:

(1)抽象类 java.io.OutputStream,是输出字节流的所有类的超类

|--API方法摘要:
|--|--void write(byte[] b) 将 b.length 个字节从指定的 byte 数组写入此输出流。
|--|--abstract void write(int b) 将指定的字节写入此输出流。
|--|--void close() 关闭此输出流并释放与此流有关的所有系统资源。

(2)抽象类 java.io.InputStream,是输入字节流的所有类的超类

|--API方法摘要:
|--|--abstract int read()从输入流中读取数据的下一个字节。
|--|--int read(byte[] b) 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
|--|--void close() 关闭此输入流并释放与该流关联的所有系统资源。

FileOutputStream写文件

// 文件输出流。完整地说,是文件字节输出流。
public class FileOutputStream extends OutputStream

步骤:
1.创建流对象
2.调用write方法,把数据写入文件
3.释放资源

import java.io.*;
public class 文件字节输出流 
    public static void main(String[] args) 
        File file = new File("文件字节输出流.txt"); // 创建文件对象
        try 
            // (1)构造:通过文件对象创建文件输出流对象
            FileOutputStream fos = new FileOutputStream(file);
            // (2)写入文件
            // (2.1)write(int b) 将"单个字节"写入到文件中
            for (int i = 49; i < 97; i++) 
                fos.write(i);
                fos.write(' ');
            
            // (2.2)write(byte[] b) 将"字节数组"中的数据全部写入文件
            byte[] buffer = "I Love Java,你呢?".getBytes();
            fos.write(buffer);
            // (3)关闭流
            fos.close();
         catch (IOException e) 
            e.printStackTrace();
        
    

追加:

使用构造方法:FileOutputStream(File file, boolean append)

            // 构造:通过文件对象创建文件输出流对象
            // 附加第二个参数true,指定进行文件追加,默认为不追加
            fos = new FileOutputStream(file, true);

回车换行:

CR(carriage return),回车,\\r
LF(line feed),换行,\\n

windows:\\r\\n
linux或unix:\\n
mac:\\r

FileInputStream读文件

public class FileInputStream extends InputStream
import java.io.*;
public class 文件字节输入流 
    static final int C_CONDITION = 2;
    public static void main(String[] args) 
        try 
            File file = new File("testRead.dat"); // 创建文件对象
            // 【1】创建输入流对象,相当于打开文件
            FileInputStream fis = new FileInputStream(file);
            if (C_CONDITION == 1) 
                // 【2】.read():读取单个字节
                for (int i = 0; i < file.length(); i++) 
                    // 循环读取"字节",转为字符输出,英文没问题
                    int read = fis.read();
                    char ch = (char) read;
                    System.out.print(ch);
                
                System.out.println();
             else 
                // 【2】.read(byte[] b):读取文件中的数据到字节数组
                // 根据文件的字节长度创建字节数组
                long len = file.length();
                byte[] buf = new byte[(int) len];
                fis.read(buf);
                // 利用字节数组创建字符串
                String str = new String(buf);
                System.out.println(str);
            
            // 【3】关闭流
            fis.close();
         catch (FileNotFoundException fnfe) 
            System.out.println("文件打开失败。");
         catch (IOException ioe) 
            ioe.printStackTrace();
        
    

复制文件

package ahjava.io;
import java.io.*;
public class 复制文件 
    public static void main(String[] args) 
        字节流复制文件();
    
    static void 字节流复制文件() 
        File srcFile = new File("testRead.dat"); // 源文件对象
        File destFile = new File("testCopy.java"); // 目标文件对象
        if (destFile.exists()) 
            // 判断目标文件是否存在,存在则删除
            destFile.delete();
        
        // 目标文件不存在才复制
        try 
            destFile.createNewFile();
            // 创建文件输入/输出流对象
            FileInputStream fis = new FileInputStream(srcFile);
            FileOutputStream fos = new FileOutputStream(destFile);
            // 创建字节数组,作为临时缓冲
            byte[] buf = new byte[128];
            System.out.println("开始复制文件...");
            int len = -1;
            // 循环从文件输入流中读取数据
            while ((len = fis.read(buf)) != -1) 
                System.out.println(len);
                // 写入到文件输出流中
                fos.write(buf, 0, len);
            
            System.out.println("文件复制成功!");
            fis.close(); // 关闭流
            fos.close();
         catch (IOException e) 
            e.printStackTrace();
        
    

上面的代码有哪些风险?

改进版:

    static void 字节流复制文件2() 
        // 1.close()提取到finally中
        // 2.提取FilexxxStream对象
        // 3.初始化(否则不准close)
        // 4.close()时加判空语句
        FileInputStream fis = null;
        FileOutputStream fos = null;
        File srcFile = new File("testRead.dat"); // 源文件对象
        File destFile = new File("testCopy.java"); // 目标文件对象
        if (destFile.exists()) 
            // 判断目标文件是否存在,存在则删除
            destFile.delete();
        
        // 目标文件不存在才复制
        try 
            destFile.createNewFile();
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);
            // 创建字节数组,作为临时缓冲
            byte[] buf = new byte[128];
            System.out.println("开始复制文件...");
            int len = -1;
            // 循环从文件输入流中读取数据
            while ((len = fis.read(buf)) != -1) 
                System.out.println(len);
                // 写入到文件输出流中
                fos.write(buf, 0, len);
            
            System.out.println("文件复制成功!");
            // 关闭流
         catch (IOException e) 
            e.printStackTrace();
         finally 
            if (fis != null) 
                try 
                    fis.close();
                 catch (IOException e) 
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                
                fis = null;
            
            if (fos != null) 
                try 
                    fos.close();
                 catch (IOException e) 
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                
                fos = null;
            
        
    

又臭又长!

Java 7异常处理写法:

try后面增加括号,其中定义流对象,该流对象仅在try中有效,执行完毕自动释放,不需要写finally。

try(流对象)
 catch (IOException e) 

具体代码如下:

    static void 字节流复制文件3() 
        File srcFile = new File("testRead.dat"); // 源文件对象
        File destFile = new File("testCopy.java"); // 目标文件对象
        if (destFile.exists()) 
            // 判断目标文件是否存在,存在则删除
            destFile.delete();
        
        // try(流对象)
        try (FileInputStream fis = new FileInputStream(srcFile);
                FileOutputStream fos = new FileOutputStream(destFile)) 
            destFile.createNewFile();
            // 创建字节数组,作为临时缓冲
            byte[] buf = new byte[128];
            System.out.println("开始复制文件...");
            int len = -1;
            // 循环从文件输入流中读取数据
            while ((len = fis.read(buf)) != -1) 
                System.out.println(len);
                // 写入到文件输出流中
                fos.write(buf, 0, len);
            
            System.out.println("文件复制成功!");
            // 关闭流
         catch (IOException e) 
            e.printStackTrace();
        
    

*Java9异常处理写法

觉得try里的代码太繁琐,try()中可以引入外部的变量:

FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
try  (fis;fos)...
// ↑ 理想状态,代码并不能这么写

然而,fis、fos本身需要抛异常,如果直接try...catch,这两个变量会变成另外的try中的局部变量;
如果把声明提取到try之外,try (fis;fos)又需要变量是final的

        FileInputStream fis = null;
        FileOutputStream fos = null;
        try 
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);
         catch (FileNotFoundException e1) 
            e1.printStackTrace();
        
        try  (fis;fos) 

CopyFile.java:20: 错误: 用作 try-with-resources 资源的变量 fis 既不是最终变量, 也不是实际上的最终变量
try (fis;fos)
^
CopyFile.java:20: 错误: 用作 try-with-resources 资源的变量 fos 既不是最终变量, 也不是实际上的最终变量
try (fis;fos)

所以,fis和fos需要往外抛出异常,外部调用的地方又需要捕获异常。比不用此功能还要麻烦。可运行代码如下:

import java.io.*;
public class CopyFile
    public static void main(String[] args) 
        try 
            copyJDK9();
         catch (FileNotFoundException e) 
            e.printStackTrace();
        
    
    static void copyJDK9() throws FileNotFoundException 
        File srcFile = new File("testRead.dat");
        File destFile = new File("testCopy.java");
        if (destFile.exists()) 
            destFile.delete();
        

        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);
        try  (fis;fos) 
            destFile.createNewFile();
            byte[] buf = new byte[128];
            System.out.println("start copy...");
            int len = -1;
            while ((len = fis.read(buf)) != -1) 
                System.out.println(len);
                fos.write(buf, 0, len);
            
            System.out.println("success");
         catch (IOException e) 
            e.printStackTrace();
        
    

以上是关于Java基础教程——字节流的主要内容,如果未能解决你的问题,请参考以下文章

JAVA零基础小白免费学习教程day16-字节流&字符流

Java基础教程——字符流

Java基础教程——序列化

[Java基础]字节流写数据

Java基础学习 —— io

[Java基础]字节流读数据