Java的文件IO编程

IO问题是任何编程语言都无法回避的,可以说,IO问题是整个人机交互的核心问题。在Java中,提供了包名为java.io的专门操作类库。
在这个包下提供了将近有80个类,这些类大致分为四组:

  • 基于字节操作的InputStreamOutputStream
  • 基于字符操作的IO接口: WriterReader
  • 基于磁盘操作的IO接口: File
  • 基于网络操作的IO接口:Socket

要学好Java的文件IO操作,重点需要掌握:

  • 2个代码模型
  • 5个类
    • File
    • OutputStream
    • InputStream
    • Reader
    • Writer
  • 1个接口(Serializable)

1. File类的基本使用

这个类的使用直接产生实例化对象即可。

1.1 File类实例化对象

如果要实例化对象,需要用到两个构造方法。

  1. public File(String pathName)
  2. public File(File parent,String child),设置父路径和子文件

1.2 File类操作文件

如果要进行文件的操作,可以使用下列方法:

  • createNewfile: 根据制订的路径创建新文件
  • exists(); 判断文件是否存在
  • file.delete(); 删除文件

实例: 判断文件是否存在,存在的话就删除,不存在的话就创建

public class FileDemo {
    public static void main(String[] args) throws IOException {
        File file = new File("D:\\hello.txt");   // 定义要操作的文件路径
        if (file.exists()) {   // 判断文件是否存在
            System.out.println("文件已经存在,已经将其删除");
            file.delete();   //删除文件
        } else {
            System.out.println("不存在文件,已经创建了一个新的!");
            file.createNewFile();   //创建一个空文件
        }
    }
}

说明,如果此处操作的都是根路径,如果是含有子路径的话,如果路径不存在,是不会自动创建路径的,会报错

File类基本操作

注意:路径分隔符
由于不同的操作系统对路径分隔符是不同的,因此,使用路径的时候,需要将上述指定操作文件的位置修改为如下:
File file = new File("D:"+File.separator+"hello.txt"); // 定义要操作的文件路径

1.3 File类操作目录

有以下常用的方法操作目录

  • 获得父目录的方法1: getParentFile(),该方法返回的是File类型的值(推荐使用)
  • 获取父目录的方法2: getParent(),该方法返回的是String类型的值
  • 创建父目录,就对获取的父目录的返回对象执行: file.getParentFile().mkdirs(),该方法如果有多层路径,都可以自动创建。
public class FileDemo {
    public static void main(String[] args) throws IOException {
     /**
         * 对路径的操作
         * */
        File file = new File("D:"+File.separator+"hello"+File.separator+"hello.txt");   // 定义要操作的文件路径
        if(!file.getParentFile().exists()){  // 判断父目录是否存在
            System.out.println(file.getParentFile().toString());
            file.getParentFile().mkdirs();   // 默认创建多级父目录
        }
        file.createNewFile();
    }
}

1.4 File类取得文件信息

File类提供很多取得文件信息的方法。方法有很多,使用方式也都类似,直接通过一个例子记录一下吧。

范例

class MyMath {
    // 保留几位小数
    public static double round(double num, int scale) {
        return Math.round(num * Math.pow(10, scale)) / Math.pow(10, scale);
    }
}

public class FileInfoDemo {
    public static void main(String[] args) {
        File file = new File("D:\\4. 暂存待整理\\截图\\Screenshot_2016-07-17-11-21-27.png");   // 定义要操作的文件路径
        if (file.exists() && file.isFile()) {  // 文件存在且是文件
            System.out.println("文件大小:" + MyMath.round((file.length()) / 1024, 2));   // 文件大小为字节数,太大了,仅保留2位小数
            System.out.println("上次修改时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date(file.lastModified())));
        }
    }
}

2. 字节流与字符流

File类本质上不操作文件的内容,要进行文件内容的处理,就需要用到字节流和字符流的概念。
字节流和字符流的区别是什么?

  1. 字节流是指文件作为数据的二进制传输形式,而字符流则是在内存中进行操作的对象的感觉。这么理解不太严密,但是可以简单认为,字符流更靠近文件。
  2. 字节流更多的是文件在磁盘上的保存,网络的数据传输形式等。
  3. 字符更适合处理中文

不管是字节流还是字符流,其处理文件内容的基本步骤都是如下的思路:

  • 要根据文件的路径创建File类的对象
  • 根据字节流或者字符流的子类实例化父类对象
  • 进行数据的读取或者写入操作
  • 关闭流:IO操作属于资源操作,所有的资源操作都必须执行关闭操作。

2.1 字节输出流OutputStream

如果要通过程序进行内容的输出,则可以使用字节输出流OutputStream。

OutputStream的继承关系

OutputStream是一个抽象类,实现了Closeable接口和Flushable接口,通过这两个接口,继承了他们各自的关闭方法和刷新方法。同样的,由于他是一个抽象类,必须使用它的子类进行实例化,那么就会需要针对不同的操作,实现不同的子类实例化。对于文件的操作,使用FileOutputStream进行实例化。 FileOutputStream拥有不同的构造函数,根据构造函数的不同,可以进行文件的覆盖写入和文件的追加写入设置等。

FileOutputStream的不同构造方法

  • 覆盖写入: FileOutputStream(File file)
  • 追加写入:+ 覆盖写入: FileOutputStream(File file,boolean append)

FileOutputStream的写入方法

  • 全部写入: write(byte[] content)
  • 局部写入: write(byte[] content,int start, int len)
  • 写入单个字节: write(int content)

范例:使用FileOutputStream进行文件内容的写入/追加等。

/** 文件内容的写入操作范例 */
public class OutputStreamDemo {
  public static void main(String[] args) throws IOException {
    // 1. 确定要操作的文件
    File file = new File("D:\\filewrite.txt");
    // 2. 实例化一个文件类型的OutputStream
    OutputStream os = new FileOutputStream(file); // 覆写
    //      OutputStream os = new FileOutputStream(file, true);   // 追加

    // 3. 写入文件
    // 3.1 全部写入
    String content = "this is a test String!\r\n";
    os.write(content.getBytes());

    // 3.2 部分写入
    os.write(content.getBytes(), 0, 9);

    // 3.3 写入单个字节
    os.write(65);

    // 4. 关闭流
    os.close();
  }
}

说明:

  1. 使用FileOutputStream进行文件操作的时候,就不在需要进行文件的创建,调用写入的方法时,会进行自动的创建。(只创建文件,如果有多级,那么目录一定要确保是存在的)
  2. 一定要记得关闭文件字节流。

2.2 字节输入流InputStream

InputStream是字节输入流,其使用方法和OutputStream类几乎一样。
原理是通过read方法将流对象中的数据读入的byte数组中,之后通过操作数组实现读取到的内容的操作。

import java.io.*;

public class InputStreamDemo {
  public static void main(String[] args) throws IOException {
    // 1. 定位到要处理的文件
    File file = new File("D:\\ProgramFiles\\kibana-5.6.2-windows-x86\\LICENSE.txt");

    // 2. 使用FileInputStream类实例化InputStream对象
    InputStream input = new FileInputStream(file);

    // 3. 读取流的内容到字节数组中
    byte[] content = new byte[1024];
    int len = input.read(content);
    
    System.out.println("读取文件内容为:【" + new String(content, 0, len) + "】");
    // 4. 关闭流
    input.close();
  }
}

2.3 字符输出流Writer

Writer是一种字符输出流的处理类,使用方法也和OutputStream使用类似,还是使用FileWriter进行父类对象的实例化。
比较有特色的就是,可以直接向文件输出字符数组或者字符串。

范例:使用Writer类进行字符输出。

package org.liyubo.java8demos.fileops;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;

public class WriterDemo {
  public static void main(String[] args) throws IOException {
      // 1. 定位到要操作的文件
      File file = new File("D:\\test\\fileops\\testwriter.txt");

      if(!file.getParentFile().exists()){  // 如果父目录不存在的话,创建父目录
          file.getParentFile().mkdirs();
      }
      // 2. 创建Writer对象,并使用FileWriter进行实例化
      Writer output  = new FileWriter(file);

      // 3. 执行输出,调用输出字符串或者
      output.write("你好,中国!");
      output.append('H');
      char[] content = new char[]{'s','v'};
      output.write(content);

      // 4. 关闭
      output.close();
  }
}
Writer写入结果

2.4 字符输入流Reader

Reader类是一个字符输入类,使用方法和Writer类似,不同的是,其只有将字符输入流读入字符数组的功能,没有读入字符串的功能。

不写例子了,没啥意思。

字节输入/出流和字符输入/出流区别

其实,字符流的核心还是因为对中文操作更好,但是现在使用一些方法也能将中文使用字节流很好的处理了。 在正常的开发中,还是字节流使用更多一些。

那么,所谓的一些操作又是怎么实现的呢?
原因就在于,其实,从流到文件中间,还有一层就是内存的缓冲。在流关闭之前,内容都是缓冲在内容中的,只有通过flush()操作强制刷新,内容才会写入到文件。因此,所谓的一些操作,就是如何在内存中对流的缓冲进行操作的问题。在内存的缓冲区中,就可以进行字节流和字符流之间的相互转换。

3. 转换流

如何在缓冲区中进行字符流和字节流的互相转换呢,此处就主要涉及两个类:

  • OutputStreamWriter: 将字节输出流转换成字符输出流。
  • InputStreamReader:将字节输入流转换成字符输入流。
image.png

范例: 使用转换流的操作

public class OutputStreamWriterDemo {
  public static void main(String[] args) throws IOException {
      // 1. 定位到要操作的文件
      File file = new File("D:\\test\\fileops\\testwriter.txt");

      if(!file.getParentFile().exists()){  // 如果父目录不存在的话,创建父目录
          file.getParentFile().mkdirs();
      }
      OutputStream os = new FileOutputStream(file);
      OutputStreamWriter writer = new OutputStreamWriter(os);

      // 3. 执行输出,调用输出字符串或者
      writer.write("你好,中国!");
      writer.append('H');

      char[] content = new char[]{'s','v'};
      writer.write(content);

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

推荐阅读更多精彩内容

  • 1 IONo18 1.1IO框架 【 IO:Input Output 在程序运行的过程中,可能需要对一些设备进...
    征程_Journey阅读 943评论 0 1
  • 一、流的概念和作用。 流是一种有顺序的,有起点和终点的字节集合,是对数据传输的总成或抽象。即数据在两设备之间的传输...
    布鲁斯不吐丝阅读 10,015评论 2 95
  • 之所以写这个是因为Hadoop的IO与·这个类似 但要比这个深入,而且都还涉及到网络传输原理的五个层次。所以,一...
    起个什么呢称呢阅读 986评论 0 6
  • 一转眼,假期就快要开学了,这周,有好的事,也有坏的事,我觉得坏的事比较多一些,也许我这人比较记仇吧。 我的阅读 这...
    牛涵葳阅读 194评论 0 0
  • 第一阶段:2017-04-12 ~ 2017-04-21 十天时间刷完leetcode上所有简单的题。 leetc...
    健时总向乱中忙阅读 1,024评论 0 1