JavaSE IO

一、IO的定义:

  • I : Input
  • O : Output
  • 通过IO可以完成硬盘文件的读和写。

二、IO流的分类

1. 流的方向:输入流输出流

  • 相对内存来定义的
往内存中去 从内存中出来
输入(Input)。或者读(Read) 输出(Output)。或者写(Write)
将文件或其它输入设备的数据加载到内存的过程 将内存中的数据保存到文件或其他输出设备

2. 读取数据方式不同:字节流字符流

字节流 字符流
按照字节的方式读取数据,一次读取1个字节byte,等同于一次读取8个二进制位 按照字符的方式读取数据的,一次读取一个字符
这种流是万能的,什么类型的文件都可以读取。包括:文本文件,图片,声音文件,视频文件等 这种流是为了方便读取普通文本文件而存在的,这种流不能读取:图片、声音、视频等文件。只能读取纯文本文件(例如:.txt结尾的),word文件也无法读取(能用记事本编辑的都是普通文本文件)
用字节流读 用字符流读
假设有一txt文件 内容是:a东bc土
-- --
第一次读:一个字节,正好读到'a' 第一次读:'a'字符('a'字符在windows系统中占用1个字节)
第二次读:一个字节,正好读到'东'字符的一半。 第二次读:'东'字符('东'字符在windows系统中占用2个字节)
第三次读:一个字节,正好读到'东'字符的另外一半。 第三次读:'b'字符('b'字符在windows系统中占用1个字节)

三、java.io.*

1 四类io流的父类

java.io.InputStream 字节输入流
java.io.OutputStream 字节输出流

java.io.Reader 字符输入流
java.io.Writer 字符输出流

  • 四大分类的父类都是抽象类。(abstract class)

注意:在java中只要“类名”以Stream结尾的都是字节流。以“Reader/Writer”结尾的都是字符流。

    所有的流都实现了:
        java.io.Closeable接口,都是可关闭的,都有close()方法。
        流毕竟是一个管道,这个是内存和硬盘之间的通道,用完之后一定要关闭

    所有的输出流都实现了:
        java.io.Flushable接口,都是可刷新的,都有flush()方法。
        输出流在最终输出之后,一定要记得flush()刷新一下。这个刷新表示将通道/管道当中剩余未输出的数据强行输出完(清空管道!)刷新的作用就是清空管道。注意:如果没有flush()可能会导致丢失数据。

2. java.io包下16个重要流:

文件专属:
java.io.FileInputStream
java.io.FileOutputStream
java.io.FileReader
java.io.FileWriter

转换流:(将字节流转换成字符流)
java.io.InputStreamReader
java.io.OutputStreamWriter

缓冲流专属:
java.io.BufferedReader
java.io.BufferedWriter
java.io.BufferedInputStream
java.io.BufferedOutputStream

数据流专属:
java.io.DataInputStream
java.io.DataOutputStream

标准输出流:
java.io.PrintWriter
java.io.PrintStream

对象专属流:
java.io.ObjectInputStream
java.io.ObjectOutputStream

四、FileInputStream和FileOutputStream

1. 测试FileInputStream

public static void main(String[] args) {
        FileInputStream fis = null;
        // 传入路径的构造方法:
        // 路径格式:D:\\javadownload\\ideaworkplace\\com.vigil\\java-base\\resources\\test.txt
        //D:/javadownload/ideaworkplace/com.vigil/java-base/resources/test.txt
        try {
            fis = new FileInputStream("resources/test.txt");
//            int data = -1;
//            while((data = fis.read()) != -1) {//read() 返回从这个输入流读取一个字节的数据。
//                System.out.println(data);
//            }
//            System.out.println(data);


            //fis.available()
            //返回一个剩余的字节数的估计,可以从这个输入流读取(或跳过),而不阻塞该输入流的方法的下一次调用。0时返回的文件位置是在EOF。下一个调用可能是同一个线程或另一个线程。一个单一的读或跳过这许多字节将不会阻止,但可以读取或跳过更少的字节数。 
            //返回可以从这个输入流中读取(或跳过)的剩余字节数的估计。 
            System.out.println("文件总字节数:" + fis.available());

            //跳过并丢弃 n字节输入流中的数据。
            fis.skip(6);

            //read(byte[] b)
            //读到 b.length从输入流到字节数组数据字节。该方法块,直到有一个输入可用。
            //返回读入缓冲的字节总数,或 -1如果没有更多的数据,因为已经到达文件末尾。
            int readCount = 0;
            byte[] bytes = new byte[16];
            while((readCount = fis.read(bytes)) != -1) {
//                System.out.print(readCount + ",");
                System.out.print(new String(bytes,0,readCount));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

IDEA 默认的当前路径:工程Project的根

2. 测试FileOutputStream

public static void main(String[] arges) {
        FileOutputStream fos = null;
        try {
            //没有文件,会在该路径新建文件
            //有文件,会清空源文件内容,在重新写入
//            fos = new FileOutputStream("resources/myfile");

            //以追加的方式写入
            fos = new FileOutputStream("resources/myfile",true);
            byte[] bytes = {97,98,99,100,101,102};
            fos.write(bytes);

            //字符串
            String str = "测试一下";
            //字符串转字节数组
            bytes = str.getBytes();
            //写入
            fos.write(bytes);
            //写完后,要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

3. 字节流完成拷贝

  • 使用java.io.FileInputStream和java.io.FileOutputStream
//拷贝过程:一边读,一边写
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //输入流对象
            fis = new FileInputStream("resources/testjpg.jpg");
            //输出流对象
            fos = new FileOutputStream("coypjpg.jpg");
            //最核心的一边写一边读
            byte[] bytes = new byte[1024];
            int readCount = 0;
            while((readCount = fis.read(bytes)) != -1) {
                fos.write(bytes,0,readCount);
            }
            //写完之后刷新,输出流要刷新
            fos.flush();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

五、FileReader 和 FileWriter

字符流完成拷贝

    //使用字节流只能完成 “普通文本” 拷贝
    public static void main(String[] args) {
        FileReader reader = null;
        FileWriter writer = null;
        try {
            //创建输入流对象
            reader = new FileReader("resources/test.txt");
            //创建输出流对象
            writer = new FileWriter("resources/file.txt");
            //一边读一边写
            char[] chars = new char[1024];
            int readCount = 0;
            while((readCount = reader.read(chars)) != -1) {
                writer.write(chars,0,readCount);
            }
            String str = "通过字符流复制完成";
            writer.write("\n");
            writer.write(str);
            writer.write(str,5,4);
            writer.write("\n");
            writer.write(97);
            //输出完后要刷新
            writer.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流,分别try保证都关闭互不影响
            if (writer == null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (reader == null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

六、 BufferedReader和BufferedWriter

使用BufferedReader、BufferedWriter完成拷贝

public class CopyTest03 {

    public static void main(String[] args) {
        /*
         BufferedReader、BufferedWriter
         带有缓冲区的字符输入流、字符输出流
         使用这个流不用自定义char数组或者byte数组。该流自带缓冲
        */
        BufferedReader br = null;
        BufferedWriter bw = null;

        try {
            // BufferedReader、BufferedWriter的构造方法需要传入一个流的对象
            //被传入的流被称为:节点流
            //外部负责包装的流被称为:包装流、处理流

            br = new BufferedReader(new FileReader("src/com/vigil/ioTest/CopyTest03.java"));
            bw = new BufferedWriter(new FileWriter("resources/JavaCopy.txt"));
            String str = null;
            //读一行,当没有可读的行,会返回null
            //readLine()方法读取一行,不带换行符
            while((str = br.readLine()) != null) {
                bw.write(str);
                bw.write("\n");
            }
            str = "通过BufferedReader、BufferedWriter复制完成";
            bw.write("\n");
            bw.write(str,31,4);
            //输出结束,刷新
            bw.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //对于包装流来说,只要关闭最外层的流就行,里面的节点流会自动关闭
            try {
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

七、标准输出流:PrintStream

  • 日志文件的雏形
    public static void main(String[] args) {
        PrintStream out = System.out;
        out.println("测试");
        try {
            // 标准输出流不再指向控制台,指向具体路径下的log文件
            out = new PrintStream(new FileOutputStream("resources/log",true));
            // 修改输出方向,将输出方向修改到“log”文件
            System.setOut(out);
            // 输出
            System.out.println("泼墨");
            System.out.println("丰富");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            out.close();
        }
    }

八、File

  • 抽象表示的文件和目录的路径名

注意:构造函数只是创建一个File实例,并没有以文件做读取等操作,因此路径即使是错误的,也可以创建实例不报错

构造方法 作用
File(File parent, String child) 通过父路径File实例对象和子路径字符串创建新的File实例
File(String pathname) 通过给定的字符串路径(一般是文件的绝对路径)转为抽象路径名用来创建File实例
File(String parent, String child) 从父路径名字符串和子路径名字符串(一般是相对父类的相对路径)创建新的File实例
File(URI uri) 通过将给定的 file: URI 转换为一个抽象路径名来创建一个新的 File 实例
  • 常用方法
方法名 作用
boolean exists() 实例对象代表的文件是否存在
String getAbsolutePath() 获取实例对象代表的文件的绝对路径
String getName() 获取实例对象代表的文件名字(包含文件后缀)
String getParent() 获取实例对象代表的文件上级目录,如果路径名不叫父目录则返回 null
File getParentFile() 获取实例对象的父项的实例对象,如果此路径名未指定父目录,则返回null;也就是获取对象的上级目录然后再实例化一个对象
String getPath() 获取实例对象代表的文件的实际路径
long length() 获取文件的字节个数,只能针对文件使用,不能针对文件夹使用
File[] listFiles() 返回文件夹中的所有内容的File对象(不包含子文件夹中的内容)
boolean mkdir() 根据实例对象的路径名创建目录(若目录已存在,则false;若路径是文件,则fasle;若路径的上级目录不存在则false)
boolean mkdirs() 根据实例对象的路径创建目录,包括创建那些必须的且不存在的父级目录
boolean isFile() 检测实例对象代表的是否是文件
long lastModified() 返回文件的抽象路径名表示上次修改时间

九、对象流

  1. ObjectOutputStream
    序列化:把对象转换为字节序列的过程称为对象的序列化。

  2. ObjectInputStream
    反序列化:把字节序列恢复为对象的过程称为对象的反序列化。

  3. 能够序列化的对象必须实现Serializable接口

  4. transient关键字
    被该关键字修饰的属性不会被序列化,游离的意思

  5. 序列化多个对象

    • 可以借助ArrayList,该类实现了Serializable接口,同时 T 类也要实现。因为要实现序列化的对象,所有涉及的引用,都需要实现序列化接口才可以Serializable接口
  6. serialVersionUID,序列化版本号:
    实现了Serializable接口的类,都会有这个属性

    • 若没有在类中显式书写该编号,那么每次更改后编译,java虚拟机都会自动加上一个新的版本号
    • private static final long serialVersionUID = 1L; 显式在类中写出,那么每一次更改编译后都不会改变序列化版本号
  7. jdk api 文档里面关于接口 Serializable 的一些描述

    • 类通过实现 java.io.Serializable 接口以启用其序列化功能。
    • 未实现此接口的类将无法使其任何状态序列化或反序列化。
    • 可序列化类的所有子类型本身都是可序列化的。因为实现接口也是间接的等同于继承。
    • 序列化接口没有方法或字段,仅用于标识可序列化的语义。
  8. 序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。

  9. 好文:Java 之 Serializable 序列化和反序列化的概念,作用的通俗易懂的解释

十、IO + Properties联合使用。

  • IO流:文件的读和写。
  • Properties:是一个Map集合,key和value都是String类型。
    - [ ] key=value

Properties可以用来保存属性集(类似Map, 以键值的形式保存数据,不同的是Properties都是String类型的)。这个类的优势是可以从流中加载属性集,或者把属性集报错到流中。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容