手记

IO流(2) - 字节流

字节流

IO流分为输入流、输出流。

java中读文件/写文件时又分为字节流、字符流。

1、字节流

(1)字节流的抽象父类:InputStream,OutputStream.

​ InputStream抽象了应用程序读取数据的方式;

​ OutputStream抽象了应用程序写出数据的方式。

(2)EOF = End 读到-1就是读到了结尾

(3)输入流基本方法

int b = in.read(); //读取一个字节无符号填充到int低八位,读到-1就是读到了结尾	此方法为读取一个字节
in.read(byte[] buf); //读到一个字节数组中
in.read(byte[] buf, int start, int size); //数据从开始到指定长度读到一个字节数组中

(4)输出流基本方法

out.write(int b); //写出一个byte到流,b的低八位
out.write(byte[] buf); //将buf字节数组都写入到流
out.write(byte[] buf); //将buf字节数组从开始到指定长度写入到流

(5)FileInputStream --> InputStream的子类,具体实现了在文件上读取数据

(6)FileOutputStream --> OutputStream的子类,具体实现了向文件中写出byte数据的方法

(7)DataInputStream/DataOutputStream(数据流)

对“流”功能的扩展,可以更加方便的读取int、long、String等类型数据。

(8)BufferedInputStream&BufferedOutputStream(缓冲流)

这两个流为IO提供了带缓冲区的操作,一般打开文件进行写入或读取操作时,都会加上缓冲,这种流模式提高了IO的性能。

从应用程序中把输入放进文件,相当于将一缸水倒入另一个缸中:

FileOutputStream --> write() 方法相当于将水一滴一滴“转移”过去,

DataOutputStream --> writeXxx() 方法会方便一些,相当于把水一瓢一瓢地“转移”过去,

BufferedOutputStream --> write() 方法更方便,相当于一瓢一瓢先放入桶中,再从桶中倒入缸中。

案例:FileInputStream读取文件内容

写一个IOUtils工具类,用于读取指定文件内容并按照16进制输出到控制台(两种方法):

public class IOUtils {
    /**
     * 读取指定文件内容,按照16进制输出到控制台
     * 并且每输出10个byte换行
     * @param fileName
     * @throws IOException
     */
    public static void printHex(String fileName) throws IOException {
        // 把文件作为字节流进行读操作
        FileInputStream fis = new FileInputStream(fileName);
        int len;
        int i = 1;
        while ((len = fis.read()) != -1) {
            if (len <= 0xf) { //len <= 0xf:说明只读到了一位
                // 单位数前面补零
                System.out.print("0");
            }
            System.out.print(Integer.toHexString(len) + " ");
            if (i++ % 10 == 0) {
                System.out.println();
            }
        }
        fis.close();
    }
    
        public static void printHexByByteArray(String fileName) throws IOException {
        FileInputStream fis = new FileInputStream(fileName);
        byte[] buf = new byte[1024];
        /**
         * 从fis中批量读取字节,放入到buf这个字节数组中,
         * 从第0个位置开始放,最多放buf.length个,
         * 返回的是读到的字节的个数
         */
        int bytes = fis.read(buf, 0, buf.length); //如果一次性读完了,说明字节数组足够大
        int j = 1; //用于计数
        for (int i = 0; i < bytes; i++) {
            if (buf[i] <= 0xf) {
                System.out.print("0"); //单位数补零
            }
            System.out.print(Integer.toHexString(buf[i] & 0xf) + " ");
            if (j++ % 10 == 0) {
                System.out.println();
            }
        }
    }
}

测试类:

public class IOTest {
    public static void main(String[] args) {
        try {
            IOUtils.printHex("F:\\Code\\JavaSE\\raf.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        System.out.println("========================");
        
        try {
            IOUtils.printHexByByteArray("F:\\Code\\JavaSE\\raf.txt");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

以上两种方式的输出结果相同,只是读出的方法稍微不同。

案例:FileOutputStream写出数据

public class FileOutputTest {
    public static void main(String[] args) throws IOException {
        // 如果该文件不存在,则直接创建;如果存在,则删除后创建
//        FileOutputStream fos = new FileOutputStream("F:\\Code\\JavaSE\\raf.txt");

        /*
           如果该文件不存在,则直接创建;如果存在,则向该文件中追加数据
           其中,第二个参数为是否追加数据,true表示追加,false表示不追加
         */
        FileOutputStream fos = new FileOutputStream("F:\\Code\\JavaSE\\raf.txt", true);
        fos.write('A');// 写出'A'的低八位
        fos.write('B');// 写出'B'的低八位
        int a = 10;// write只能写8位,则写一个int类型的数据需要写4次,每次8位
        fos.write(a >>> 24);
        fos.write(a >>> 16);
        fos.write(a >>> 8);
        fos.write(a);
        byte[] bytes = "中国".getBytes("GBK");
        fos.write(bytes);
        fos.close();
        
        IOUtils.printHex("F:\\Code\\JavaSE\\raf.txt");
    }
}

案例:输入输出流结合 - 拷贝文件(开辟字节,批量读取)

IOUtils工具类中添加copyFile方法:

public static void copyFile(File srcFile, File dirFile) throws IOException {
    if (!srcFile.exists()) {
        throw new IllegalArgumentException(srcFile+"文件不存在~");
    }
    if (!srcFile.isFile()) {
        throw new IllegalArgumentException(srcFile+"不是文件~");
    }
    FileInputStream fis = new FileInputStream(srcFile);
    FileOutputStream fos = new FileOutputStream(dirFile);
    byte[] buf = new byte[1024];
    int len;
    while ((len = fis.read(buf)) != -1) {
        fos.write(buf, 0, len);
        fos.flush();// 清空缓冲区数据
    }
    System.out.println("copy完成~");
    fos.close();
    fis.close();
}

测试类:

public class CopyFileTest {
    public static void main(String[] args) {
        try {
            IOUtils.copyFile(new File("F:\\Code\\JavaSE\\raf.txt"), new File("F:\\Code\\JavaSE\\raf_copy.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

输出结果:copy完成~

打开目标文件位置,可以看到已存在拷贝的文件。

案例:使用数据流将数据写入文件中并读出

public class DosDemo {
    public static void main(String[] args) {
        DataOutputStream dos = null;
        DataInputStream dis = null;
        try {
            String file = "F:\\Code\\JavaSE\\dos.txt";
            dos = new DataOutputStream(
                    new FileOutputStream(file));
            dos.write(10);
            dos.writeByte(20);
            dos.writeInt(30);
            dos.writeLong(-10L);
            dos.writeDouble(-20.5);
            dos.writeUTF("中国"); //以utf-8编码写出
            dos.writeChars("雄狮"); //以utf-16be编码写出

            dis = new DataInputStream(new FileInputStream(file));
            int read = dis.read();
            System.out.println(read);
            byte b = dis.readByte();
            System.out.println(b);
            int i = dis.readInt();
            System.out.println(i);
            long l = dis.readLong();
            System.out.println(l);
            double v = dis.readDouble();
            System.out.println(v);
            String s = dis.readUTF();
            System.out.println(s);
            System.out.print(dis.readChar());
            System.out.println(dis.readChar());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (dis != null) {
                    dis.close();
                }
                if (dos != null) {
                    dos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

    }
}

输出结果:

10
20
30
-10
-20.5
中国
雄狮

案例:使用缓冲流拷贝文件(速度最快)

IOUtils工具类中写一个缓冲流拷贝文件方法:

    // 进行文件的拷贝,利用带缓冲的字节流
    public static void copyFileByBuffered(File srcFile, File dirFile) throws IOException {
        if (!srcFile.exists()) {
            System.out.println(srcFile + "文件不存在~");
        }
        if (!srcFile.isFile()) {
            System.out.println(srcFile + "不是一个文件~");
        }
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dirFile));
        int len;
        while ((len = bis.read()) != -1) {
            bos.write(len);
            bos.flush();// 刷新缓冲区,否则写入不到文件中(不带缓冲可以不刷新缓冲区)
        }
        // 关闭流
        bos.close();
        bis.close();
        System.out.println("拷贝完成~");
    }
}

测试类:

public class BufferedTest {
    public static void main(String[] args) throws IOException {
        IOUtils.copyFileByBuffered(
                new File("F:\\Code\\JavaSE\\raf.txt"), new File("F:\\Code\\JavaSE\\buf.txt"));
    }
}

输出结果:拷贝完成~

传输速度:

(FileOutputStream)单字节输出流 > (FileOutputStream)输出流批量读取 > (BufferedOutputStream)缓冲流读取.

0人推荐
随时随地看视频
慕课网APP