Java IO 的基本划分和代码示例

代码演示需要提前在项目根目录下创建一个 file.txt ,并在其中输入一些信息
不习惯这样看代码的话,我把代码上传到了 github 上:https://github.com/Mr1wangjiabin/java-io

文章目录

      • IO流的划分
        • 按数据来源或者操作对象划分
        • 按数据传输方式或者说是运输方式划分
      • 文本、文件、文本文件
      • 编码
      • File
        • File 类的基本API
        • File 的 list 与 listFile
      • RandomAccessFile
      • 字节流
        • 输入输出流
          • FileInputStream
          • FileOutputStream
          • 练习:实现文件的复制
        • 缓冲流 BufferedInputStream && BufferedOutputStream 进行文件复制
      • 字符流
        • InputStreamReader && OutputStreamWriter 实现文件复制
        • FileReader && FileWriter 实现文件复制
        • BufferedReader && BufferedWriter/PrintWriter 实现文件复制
      • 序列化与反序列化

IO流的划分

按数据来源或者操作对象划分

按数据传输方式或者说是运输方式划分

Java IO 的基本划分和代码示例_第1张图片

文本、文件、文本文件

  • 文本:Java 的文本是 16 位无符号整数,是字符的 unicode 编码
  • 文件:文件时 byte byte byte ... 的数据序列
  • 文本文件:是文本按照某种编码方式序列化为 byte 的存储结果

编码

  • GBK
  • UTF-8
  • UTF-16be
public class EncodeDemo {
    public static void main(String[] args) throws Exception {
        /**
         * 文本文件,可以是任意编码的字节序列
         * 如果我们在中文机器上直接创建文本文件,那么该文件只认识ANSI编码
         *
         * 字节序列只能进行同种编码间的传输,如果编码方式不一致,会出现乱码
         */
        //UTF-8 输出e6 b5 8b e8 af 95 41 42 43
        //一个汉字 3 个字节,字母 1 个字节
        String s = "测试ABC";
        byte[] bytes1 = s.getBytes();//转换成字节是项目默认的编码 UTF-8
        System.out.println("UTF-8编码:");
        for (byte b : bytes1) {
            System.out.print(Integer.toHexString(b & 0xff) + " ");//将字节转换为 16进制 int型输出
        }
        System.out.println();

        //GBK输出b2 e2 ca d4 41 42 43 
        //一个汉字 2 个字节,字母 1 个字节
        System.out.println("GBK编码:");
        byte[] bytes2 = s.getBytes("gbk");
        for (byte b : bytes2) {
            System.out.print(Integer.toHexString(b & 0xff) + " ");
        }
        System.out.println();

        //UTF-16be 输出6d 4b 8b d5 0 41 0 42 0 43 
        //一个汉字 2 个字节,字母 2 个字节
        System.out.println("UTF-16be编码:");
        byte[] bytes3 = s.getBytes("utf-16be");
        for (byte b : bytes3) {
            System.out.print(Integer.toHexString(b & 0xff) + " ");
        }
        //关闭流
        raf.close
    }
}

File

  • java.io.file 用来表示文件或者目录
  • File 类用于表示文件(目录)的信息(名称、大小等)。不能用于文件内容的访问

File 类的基本API

/**
 * File 的构造函数:
 *  File(filepath) filepath为文件全目录
 *  File(filepath,filepath1,filepath2...) filepath1为filepath的子目录
 * File.separator 文件分隔符
 * exists 验证file是否存在
 * mkdir 创建一个文件夹/目录
 * mkdir 创建多级目录
 * delete 删除文件
 * isDirectory 判断file 是否是文件夹
 * isFile 判断file 是否是文件
 * getAbsolutePath 获取全路径
 * getName 获取文件名称
 * createNewFile 创建一个新文件
 */
public class FileDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\Project\\io\\test");
        File file1 = new File("E:" + File.separator
                + "Project" + File.separator
                + "io"+ File.separator
                + "test.text");

        if(!file.exists()){
            file.mkdir();
        }else {
            file.delete();
        }
        System.out.println(file.isDirectory());//判断file 是否是文件夹
        System.out.println(file.isFile());//判断file 是否是文件
        System.out.println(file.getAbsolutePath());//获取全路径
        System.out.println(file.getName());//获取文件名称

        if (!file1.exists()){
            file1.createNewFile();
        }else {
            file1.delete();
        }

    }
}

File 的 list 与 listFile

import java.io.File;

/**
 * list 返回目录/文件下的所有文件名
 * listFiles 返回文件下的所有文件
 *
 * 练习,完成目录下所有子目录的查询
 */
public class FileUtils {
    public static void main(String[] args) throws IllegalAccessException {
        File file = new File("E:/Project/io");
        FileUtils.listFile(file);

    }

    public static void listFile(File file) throws IllegalAccessException {
        //首先判断文件是否存在以及文件是文件夹
        if(!file.exists()){
            throw new IllegalAccessException(file + " 不存在");
        }
        if (!file.isDirectory()){
            throw new IllegalAccessException(file + " 不是一个文件夹");
        }

        File[] files = file.listFiles();
        if (files.length > 0 && files != null){
            for (File file1 : files) {
                if (file1.isDirectory()){
                    FileUtils.listFile(file1);
                }else {
                    System.out.println(file);
                }
            }
        }
  }
}

RandomAccessFile

  • 即可以读取文件内容,也可以向文件中写入内容。但是和其他输入/输入流不同的是,程序可以直接跳到文件的任意位置来读写数据。
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;

/**
 ** java 文件模型
 *      在硬盘上是 byte byte 存储的,是数据的集合
 *  打开文件
 *      有两种模式:"rw"(读写) "r"(只读)
 *      RandomAccessFile raf = new RandomAccessFile("rw")
 *      文件指针,打开文件时,文件指针在开头 pointer = 0
 * 写方法
 *      raf.writer() -->只写一个字节(后8位)同时指针指向下一个位置,准备再次写入
 * 读方法
 *      int b = raf.read() --> 读一个字节
 * 文件读写完成一定要关闭
 *
 * 其他API
 * getFilePointer 获取指针当前所在位置
 *
 *
 */
public class RandomAccessFileDmo {
    public static void main(String[] args) throws IOException {
        //创建文件
        File file = new File("demo");
        if(!file.exists()){
            file.mkdir();
        }
        File file1 = new File(file, "raf.dat");
        if(!file1.exists()){
            file1.createNewFile();
        }

        //对文件的读写操作
        RandomAccessFile raf = new RandomAccessFile(file1, "rw");
        System.out.println("指针当前所在位置为:" + raf.getFilePointer());//获取指针当前所在位置

        //写入一个字节
        //默认编码UTF-8,一个汉字 3 个字节,一个字母 1 个字节
        raf.write('A');
        System.out.println("指针当前所在位置为:" + raf.getFilePointer());//获取指针当前所在位置

        int i = 0x7fffffff;
        //用write方法每次只能写一个字节,如果要把i写进去就得写4次
        raf.write((i >>> 24) & 0xff);//右移 24 位,并清空其余的0值
        raf.write((i >>> 16) & 0xff);
        raf.write((i >>> 8) & 0xff);
        raf.write((i) & 0xff);
        System.out.println("指针当前所在位置为:" + raf.getFilePointer());//获取指针当前所在位置

        //可以直接写一个 int 型变量,底层实现和上面的方法一样
        raf.writeInt(i);

        //写一个汉字
        String s = "中";
        byte[] bytes = s.getBytes();
        raf.write(bytes);
        System.out.println("指针当前所在位置为:" + raf.getFilePointer());//获取指针当前所在位置

        //读文件,必须把指针移动到头部
        raf.seek(0);
        //把文件中的内容都读取到字节数组中
        byte[] bytes1 = new byte[(int) raf.length()];
        raf.read(bytes1);

        System.out.println(Arrays.toString(bytes1));//将数组输出
        //将字节数组转换为字符串输出
        String s1 = new String(bytes1);
        System.out.println(s1);
    }
}

字节流

输入输出流

FileInputStream
  • 实现了在文件上读取数据
package byteStream;

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

/**
 * 读取指定文件内容,按照16进制输出到控制台。并且每输出10个byte换行
 * 批量读取
 */
public class FileInputStreamTest {
    public static void main(String[] args) throws IOException {
        printHex("file.txt");
    }

    public static void printHex(String filename) throws IOException{
        FileInputStream fis = new FileInputStream(filename);
        byte[] bytes = new byte[8 * 1024];
        int b = 0;
        int j = 1;
        while ((b = fis.read(bytes,0,bytes.length)) != -1){
            for (int i = 0; i < b; i++) {
                System.out.print(Integer.toHexString(bytes[i] & 0xff) + "  ");
                if(((j++)%10)==0){
                    System.out.println();
                }
            }

        }

        fis.close();
    }

}

FileOutputStream
package byteStream;

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

/**
 * 从文件中读取数据
 */
public class FileOutPutStreamTest {
    public static void main(String[] args) throws IOException {
        FileOutputStream fos = new FileOutputStream("out.dat");
        byte[] bytes = "你好".getBytes();
        fos.write(bytes);
        fos.close();

        FileInputStreamTest.printHex("out.dat");
    }
}

练习:实现文件的复制
package byteStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * 完成文件的复制
 */
public class FileCopyTest {

    public static void main(String[] args) throws Exception {
        fileCopy(new File("file.txt"),new File("fileout.txt"));
    }

    /**
     * 文件复制
     * 问什么传入参数不用文件名?
     *      需要判断源文件是否存在
     * @param srcFile
     * @param destFile
     */
    public static void fileCopy(File srcFile,File destFile) throws Exception{
        if(!srcFile.exists()){
            throw new IllegalAccessException("文件" + srcFile + "不存在");
        }
        if(!srcFile.isFile()){
            throw new IllegalAccessException("文件" + srcFile + "不是文件");
        }

        FileInputStream fis = new FileInputStream(srcFile);
        FileOutputStream fos = new FileOutputStream(destFile);

        byte[] bytes = new byte[8 * 1024];
        int b = 0;

        if((b = fis.read(bytes,0,bytes.length)) != -1){
            fos.write(bytes,0,b);
            fos.flush();
        }

        fis.close();
        fos.close();
    }
}

缓冲流 BufferedInputStream && BufferedOutputStream 进行文件复制

  • 提供了缓冲区操作,提高的IO的性能
package byteStream;

import java.io.*;

public class BufferedTest {
    public static void main(String[] args) throws Exception{
        copyFile(new File("E:\\Project\\io\\src\\main\\java\\file\\FileDemo.java"),
        new File("fileOut2.txt"));

    }

    public static void copyFile(File srcFile, File destFile) throws Exception{
        if(!srcFile.exists()){
            throw new IllegalAccessException("文件" + srcFile + "不存在");
        }
        if(!srcFile.isFile()){
            throw new IllegalAccessException("文件" + srcFile + "不是文件");
        }

        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcFile));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));

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

        bis.close();
        bos.close();

    }
}

字符流

  • 有了字节流为什么还需要字符流?
    字符流是由Java虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以,I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。
  • 字符的处理
    一次处理一个字符,底层仍然是最基本的字节序列

InputStreamReader && OutputStreamWriter 实现文件复制

  • InputStreamReader 按照编码将 byte 流解析为 char
  • OutputStreamWriter 默认项目的编码,操作的时候要写文件本身的编码
package charStream;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 *  InputStreamReader && OutputStreamWriter 实现文件复制
 */
public class FileCopyTest {
    public static void main(String[] args) throws Exception{
        InputStreamReader isr = new InputStreamReader(new FileInputStream("file.txt"));
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("fileOut3.txt"));

        char[] chars = new char[8 * 1024];
        int c;

        while ((c = isr.read(chars,0,chars.length)) != -1){
            osw.write(chars,0,c);
            osw.flush();
        }

        isr.close();
        osw.close();
    }
}


FileReader && FileWriter 实现文件复制

package charStream;

import java.io.FileReader;
import java.io.FileWriter;

/**
 *  InputStreamReader && OutputStreamWriter 实现文件复制
 */
public class FileCopyByFileTest {
    public static void main(String[] args) throws Exception{
        FileReader fr = new FileReader("file.txt");
        FileWriter fw = new FileWriter("fileOut4.txt");

        char[] chars = new char[8 * 1024];
        int d;

        while ((d = fr.read(chars,0,chars.length)) != -1){
            fw.write(chars,0,d);
        }

        fr.close();
        fw.close();
    }
}

BufferedReader && BufferedWriter/PrintWriter 实现文件复制

  • PrintWriter 用起来比 BufferedWriter 方便不少,因此我不再写 BufferedWriter相关代码,感兴趣的自己查吧
package charStream;

import java.io.*;

public class FileCopyByBuffer {
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("file.txt")));
        PrintWriter pw = new PrintWriter(
                new FileOutputStream("fileOut5.txt"),true);//在文件参数为 OutputStream时,可以设置自动清空缓存

        String line;
        while ((line = br.readLine()) != null){
            pw.println(line);
        }

        br.close();
        pw.close();

    }
}

序列化与反序列化

  • 将对象转换为 byte 存储称为序列化,反之为反序列化
  • 序列化流 ObjectOutputStream 方法 writeObject
  • 反序列化流 ObjectInputStream 方法 readObject
  • 只有实现了 Serializable 接口的类才能序列化
  • 类中 transient 修饰的变量不会被 JVM 自动序列化,但可以手动,用以提高性能(这部分不懂,就简单的提一下)
package SerializableTest;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableTest {

    public static void main(String[] args) throws Exception{
        //对象序列化
        ObjectSerializable();
        //对象反序列化
        ObjectInSerializable();
    }

    /**
     * 对象序列化
     * @throws Exception
     */
    public static void ObjectSerializable() throws Exception{
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("obj.dat"));
        Student student = new Student(1L, "小王");
        oos.writeObject(student);
        oos.flush();
        oos.close();
    }

    public static void ObjectInSerializable() throws  Exception{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("obj.dat"));
        Student student = (Student) ois.readObject();
        System.out.println(student);
        ois.close();
    }

}

你可能感兴趣的:(JAVA学习)