Java 的 IO 流

  • 字节流, 字节流可以操作任何数据, 计算机中存储是字节流
    • InputStream
    • OutputStream
  • 字符流, 只能操作纯字符数据, 比较方便
    • Reader
    • Writer

使用IO流要导入包, 使用时要进行异常处理, 使用后要释放资源

FileInputStream 读取一个文件

import java.io.FileInputStream;
import java.io.IOException;

public class Demo1_FileInputStream {
    public static void main(String[] args) throws IOException {
        FileInputStream fps = new FileInputStream("test.txt");
        int x;
        while ((x = fps.read() ) != -1){
            System.out.println(x);
        }
        fps.close();
    }
}

read() 为什么接收的int类型

因为字节输入流可以操作任意类型的文件,比如图片音频等, 这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte, 有可能在读到中间的时候遇到111111111,那么这11111111是byte类型的-1, 我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收, 如果11111111会在其前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完, 而结束标记的-1就是int类型

字节输出流 write()

  • void write(int b) throws IOException 在输出时int 去掉前3个byte字节, 写入第4个byte到文件中, 这个写是覆盖
import java.io.FileOutputStream;
import java.io.IOException;

public class Deom2_FileOutputStream {
    public static void main(String[] args) throws IOException {
        FileOutputStream fps = new FileOutputStream("test.txt");
        fps.write(100);
        fps.write(101);
        fps.write(102);
        fps.close();
    }
}

字节输出流 追加

  • FileOutputStream(File file, boolean append) throws FileNotFoundException 输出字节流是否选择追加
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo3_FileOutputStream {
    public static void main(String[] args) throws IOException {
        FileOutputStream fps = new FileOutputStream("test.txt", true);
        fps.write(100);
        fps.write(101);
        fps.close();
    }
}

复制文件

  • byte字节读取, byte复制
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo4_FileInOutStream {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("test.txt");
        FileOutputStream fos = new FileOutputStream("copy.txt");
        int b = 0;
        while ( (b = fis.read() )!= -1){
            fos.write(b);
        }
        fis.close();
        fos.close();
    }
}

FileInputStream 的 available方法

  • int available() throws IOException 返回输入流的长度
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo5_FileInOutStream {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("test.txt");
        FileOutputStream fos = new FileOutputStream("copy.txt");

        int len = fis.available();
        byte[] arr = new byte[fis.available()];
        fis.read(arr);
        fos.write(arr);
        fis.close();
        fos.close();
    }
}

通过数组 byte[] 读取写入

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo6_FileInOutStream {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("test.txt");
        FileOutputStream fos = new FileOutputStream("copy.txt");

        byte[] arr = new byte[1024 * 1024];
        int b = 0;
        while ( (b =fis.read(arr)) != -1 ){
            fos.write(arr,0,b);
        }
        fis.close();
        fos.close();
    }

    private static void errSimple() throws IOException {
        FileInputStream fis = new FileInputStream("test.txt");
        FileOutputStream fos = new FileOutputStream("copy.txt");

        byte[] arr = new byte[3];
        int b = 0;
        while ( (b =fis.read(arr)) != -1 ){
            fos.write(arr);
        }
        fis.close();
        fos.close();
    }
}

BufferedInputStream BufferedOutputStream

  • 原码先读取1024*8个字节到内存, 复制给 BufferedOutputStream 1024*8 然后才写入文件
  • 只需要关闭BufferedInputStream BufferedOutputStream 就能关闭所有流
import java.io.*;

public class Demo7_BufferInputStream {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("test.txt");
        FileOutputStream fos = new FileOutputStream("copy.txt");

        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);
        int b ;
        while( ( b = bis.read() ) != -1){
            bos.write(b);
        }
        // 只需关闭 BufferedInputStream BufferedOutputStream
        bis.close();
        bos.close();
    }
}

flush和close方法的区别

  • flush 刷新缓冲区, 缓冲区写到文件中, 刷完可以继续写.
  • close 关闭前 就会刷新缓冲区 将缓冲区内容存到文件中
import java.io.*;

public class Demo8_FlushClose {
    public static void main(String[] args) throws IOException {
        FileInputStream fis = new FileInputStream("test.txt");
        FileOutputStream fos = new FileOutputStream("copy.txt");

        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        int b ;
        while ( (b = bis.read()) != -1 ){
            bos.write(b);
            bos.flush();
        }
        bis.close();
        bos.close();
    }

}

字节流读取中文有乱码

  • UTF-8中英文1个字节, 中文3个字节, 按字节读取都会读出乱码
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class Demo9_CharIO {
    public static void main(String[] args) throws IOException {
//        Demo1();
        FileOutputStream fos = new FileOutputStream("chinese.txt");
        fos.write("你好啊, 世界!".getBytes(StandardCharsets.UTF_8));
        fos.write("\r".getBytes(StandardCharsets.UTF_8));
        fos.close();
    }

    private static void Demo1() throws IOException {
        FileInputStream fis = new FileInputStream("chinese.txt");
        byte[] arr = new byte[3];
        String s;
        int len ;
        while ( ( len=fis.read(arr) ) != -1){
            System.out.println(new String(arr,0,len));
        }
    }
}

异常处理

  • 流初始化null
  • try 关闭流
  • 能关闭一个就关闭一个
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class Demo10_IOException {
    public static void main(String[] args) throws IOException{
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("test.txt");
            fos = new FileOutputStream("copy.txt");
        }
        finally {
            try{
                if(null != fis){
                    fis.close();
                }
            } finally {
                if(null != fos){
                    fos.close();
                }
            }
        }
    }
}

图片加密解密

  • 加密把输出的字节异或一个数, 解密时再异或这个数
import java.io.*;
public class Demo12_Encrypt {
    public static void main(String[] args)  throws IOException {
        String src = "beauty.png";
        String dest = "copy.png";
        String dest2 = "copy1.png";
//        extracted(src, dest);
        extracted(dest, dest2);
    }

    private static void extracted( String src, String dest) throws IOException {
        BufferedInputStream fis = new BufferedInputStream(new FileInputStream(src));
        BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(dest));
        int b ;
        while ( (b = fis.read()) != -1){
            fos.write(b ^ 123 );
        }
        fis.close();
        fos.close();
    }
}

输入文件复制到当前路径下

import java.io.*;
import java.util.Scanner;

public class Demo13_CopyFile {
    public static void main(String[] args) throws IOException {

        Scanner sc = new Scanner(System.in);
        String src = null;
        if(sc.hasNext()){
            src = sc.nextLine();
        }
        BufferedInputStream fis =null;
        int b ;
        BufferedOutputStream fos = null;
        if(src != null){
            File file = new File(src);
            fis = new BufferedInputStream(new FileInputStream(src));
            fos = new BufferedOutputStream(new FileOutputStream("./"+file.getName()));
            if( file.isFile()){
                 while ( (b = fis.read()) != -1){
                     fos.write(b);
                 }
            } else if( file.isDirectory()){
                System.out.println("文件夹无法复制");
            }
        }
        fis.close();
        fos.close();
    }
}

练习, 录入输入字符到文件中

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

public class Demo14_InputKey {
    public static void main(String[] args) throws IOException {
        Scanner sc  = new Scanner(System.in);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.txt", true));
        String input = null;
        while ( sc.hasNext()){
            input = sc.nextLine();
            if( "quit".equals(input)){
                break;
            } else{
                bos.write(input.getBytes(StandardCharsets.UTF_8));
                bos.write("\n".getBytes(StandardCharsets.UTF_8));
            }
        }
        bos.close();
    }
}