天天看点

Java中的IO流和File类的简单概述IO流File类

文章目录

  • IO流
    • IO流概述和分类
      • IO流概述
      • IO流分类
        • 字节流
          • 字节流写数据的3种方式
          • 字节流写数据的两个小问题
          • 字节流读数据(一次读一个字节数据)
          • 字节流读数据(一次读一个字节数组数据)
          • 字节缓冲流
        • 字符流
          • 编码表
          • 字符串中的编码解码问题
          • 字符流中的编码解码问题
          • 字符流写数据的5种方式
          • 字符流读数据的2种方式
  • File类
    • File类概述和构造方法
    • File类创建功能
    • File类判断和获取功能
    • File类删除功能

IO流

IO流概述和分类

IO流概述

IO:输入/输出(Input/Output)

流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输,IO流就是用来处理设备间数据传输问题的,常见的应用有:文件复制;文件上传;文件下载。

IO流分类

按照数据的流向: 输入对应的是读数据,输出对应的是写数据

按照数据类型: 字节流(字节输入流,字节输出流),字符流(字符输入流,字符输出流),能读的懂的(例如用记事本打开一个txt文档)称为字符流,不能读懂的(例如用记事本打开一张图片,看到的是一堆乱码)称为字节流(如果不知道用字节流还是用字符流,默认 使用字节流)。

字节流

抽象父类:

字节输入流(InputStream)

字节输出流(OutputStream)

字节流写数据:

FileOutputStream: 文件输出流用于将数据写入File

步骤:一,创建字节流输出流对象,二,调用字节输出流对象的写数据方法,三,释放资源。

public static void main(String[] args) throws IOException {
        //一,创建字节流输出对象 FileOutputStream(String name): 创建文件输出流以指定的名称写入文件
        //1.调用系统功能创建了文件
        //2.创建了字节输出流对象
        //3.让字节输出流对象指向创建好的文件
        FileOutputStream fos = new FileOutputStream("fos.txt");

        //二,void write(int b):将指定的字节写入此文件输出流
        fos.write(97);

        //三,释放资源
        //void close(): 关闭此文件输出流并释放与此相关联的任何系统资源
        fos.close();
    }

           
字节流写数据的3种方式
方法名 说明
void write(int b) 将指定的字节写入此文件输出流一次写一个字节数据
void write(byte[] b) 将b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据
void write(byte[]b,int off,int len) 将len字节从指定的字节数组开始,从偏移量(索引)off开始写入此文件输出流一次写一个字节数据的部分数据
public static void main(String[] args) throws IOException {
        //构造方法1:FileOutputStream(String name): 创建文件输出流以指定的名称写入文件
        FileOutputStream fos=new FileOutputStream("fos.txt");

        //构造方法2:FileOutputStream(File file):创建文件输出流以写入由指定的File对象表示的文件
        File file=new File("fos.txt");
        FileOutputStream fos2=new FileOutputStream(file);

        //写数据的三种方式:

        //方式1:void write(int b):将指定的字节写入此文件输出流
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.write(100);
        fos.write(101);

        //方式2:void write(byte[] b):将b.length字节从指定的字节数据写入此文件输出流
        byte[] bys={97,98,99,100,101};
        fos.write(bys);

        //方式2的简化写法(用到String类的getBytes();返回字符串对应的字节数组方法)
        String str="abcde";
        byte[] bytes = str.getBytes();
        fos.write(bytes);

        //方式3:void write(byte[]b,int off,int len):将len字节从指定的字节数组开始,从偏移量off处开始写数据
        String str2="abcde";
        byte[] bytes1 = str2.getBytes();
        fos.write(bytes1,0,bys.length);
    }

           
字节流写数据的两个小问题
  1. 字节流写数据如何实现换行?
public static void main(String[] args) throws IOException {
        //问题1:字节流写数据如何实现换行呢?
        //创建字节流对象
        FileOutputStream fos = new FileOutputStream("fos.txt");

        //写数据
        for (int i = 0; i < 100; i++) {
            fos.write("hello".getBytes());
            //换行
            fos.write("\n".getBytes());
        }

        //释放资源
        fos.close();
    }

           
  1. 字节流写数据如何实现追加写入呢?
public static void main(String[] args) throws IOException {
        //问题2:如何追加写入?true追加数据
        FileOutputStream fos1 = new FileOutputStream("fos.txt", true);
        //写数据
        for (int i = 0; i < 100; i++) {
            fos1.write("hello".getBytes());
            //换行
            fos1.write("\n".getBytes());
        }

        //释放资源
        fos1.close();
    }

           
字节流读数据(一次读一个字节数据)

FileInputStream : 从文件系统中的文件获取输入字节

需求:把文件fos.txt中的内容读取出来在控制台输出

使用字节输入流读取数据的步骤:

  1. 创建字节输入流对象
  2. 调用字节输入流对象的读数据方法
  3. 释放资源
public static void main(String[] args) throws IOException {
        //1.创建字节输入流对象
        FileInputStream fis=new FileInputStream("fos.txt");

        //2.调用字节流输入流对象的读数据方法
        //int read(): 从该输入流读取一个字节的数据
        int by;
        while ((by=fis.read())!=-1){
            System.out.println((char) by);
        }

        //3.释放资源
        fis.close();
    }

           
字节流读数据(一次读一个字节数组数据)

需求:把文件fos.txt中的内容读取出来在控制台输出

使用字节输入流读数据的步骤:

  1. 创建字节输入流对象
  2. 调用字节输入流对象的读数据方法
  3. 释放资源
public static void main(String[] args) throws IOException {
        //1.创建字节输入流对象
        FileInputStream fis=new FileInputStream("fos.txt");

        //2.调用字节输入流对象的读数据方法
        //int read(byte[] b):从该输入流读取最多 b.length个字节的数据到一个字节数组
        byte []bys=new byte[1024];//1024及其整数倍
        int len;
        while ((len=fis.read(bys))!=-1){
            String s = new String(bys, 0, len);
            System.out.println(s);
        }
        
        //3.释放资源
        fis.close();
    }

           
字节缓冲流

BufferedOutputStream:该类实现缓冲输出流。通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用。

BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。

构造方法:

  • 字节缓冲输出流:BufferedOutputStream(OutputStream out)
  • 字节缓冲输入流:BufferedInputStream(InputStream in)

为什么构造方法需要的是字节流,而不是具体的文件或路径呢?

字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作

public static void main(String[] args) throws IOException {
        //字节缓冲输出流:BufferedOutputStream(OutputStream out)
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));

        //写数据
        bos.write("hello\r\n".getBytes());
        bos.write("world\r\n".getBytes());

        //释放资源
        bos.close();
        
    }

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

        //字节缓冲输入流:BufferedInputStream(InputStream in)
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bos.txt"));

        //一次读取一个字节数据
        //int by;
        //while ((by=bis.read())!=-1){
        //    System.out.println((char)by);
        //}

        //一次读取一个字节数组数据
        byte[] bys = new byte[1024];
        int len;
        while ((len = bis.read(bys)) != -1) {
            System.out.println(new String(bys, 0, len));
        }

        //释放资源
        bis.close();


    }

           

字符流

为什么会出现字符流?

由于字节流操作中文不是特别方便,所以Java就提供字符流

字符流=字节流+编码表

用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因时最终底层操作会自动进行字节拼接成中文,如何识别时中文的呢?

汉字在存储的时候,无论选择哪种编码存储,第一个字节都是负数

编码表

计算机中存储的信息都是用二进制数表示的;我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果

按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制数按照某种规则解析出来,称为解码。这里强调一下:按照A编码存储,必须按照A编码解析,这样才能显示正确的文本符号。否则就会导致乱码现象。

字符集

是一个系统支持的所有字符的集合,包括各个国家文字、标点符号、图形符号、数字等。计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。常见字符集有ASCII字符集、GBXXX字符集、Unicode字符集。

ASCII(American Standard Code for Information Interchange,美国信息交换标准代码):是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车键、退格、换行键等)和可显示字符(英文大小写字符、阿拉伯数字和西文符号)。

基本的ASCII字符集,使用7位表示一个字符,共128字符。ASCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符的集合,包括各国家文字、标点符号、图形符号、数字等。

GB2312:简体中文码表。一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合包括7000多个简体汉字,此外数学符号、罗马希腊的字母、日文的假名等都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码、这就是常说的“全角”字符,而原来在127号以下的那些就叫“半角”字符了。

GBK:最常用的中文码表。是在GB2312标准的基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩汉字等。

GB18030:最新的中文码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩汉字等。

Unicode字符集:为了表示任意语言的任意字符而设计,是业界的一种标准,也称为统一码,标准万国码。它最多使用4个字节的数字来表示每个字母、符号,或者文字。有三种编码方案,UTF-8、UTF-16和UTF-32。最为常用的是UTF-8编码。

UTF-8编码可以用来表示Unicode标准中的任意字符,它是电子邮件、网页及其其他存储或传送文字应用中,优先采用的编码。互联网工程小组(IETF)要求所有互联网协议都必须支持UTF-8编码。它使用一至四个字节为每个字符编码

编码规则:

  1. 128个US-ASCII字符,只需要一个字节编码
  2. 拉丁文等字符,需要二个字节编码
  3. 大部分常用字(含中文),使用三个字节编码
  4. 其他极少数使用的Unicode辅助字符,使用四个字节编码

小结:采用何种规则编码,就要采用对应规则解码,否则就会出现乱码

字符串中的编码解码问题

编码:

  1. byte[] getBytes(); 使用平台的默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
  2. byte[] getBytes(String charsetName); 使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中

解码:

  1. String(byte[] bytes); 通过使用平台的默认字符集解码指定的字节数组来构造新的String
  2. String(byte[] bytes,String charsetName); 通过指定的字符集解码指定的字节数组来构造新的String

使用默认编码:

public static void main(String[] args) {
        //编码
        //1.先定义一个字符串
        String s="中国";
        //2.编码 使用平台默认的字符集编码
        byte[] bytes = s.getBytes();
        System.out.println(Arrays.toString(bytes));
    }

           

结果如下:

使用指定编码:

public static void main(String[] args) throws UnsupportedEncodingException {
        //编码
        //1.先定义一个字符串
        String s="中国";
        //2.编码 使用指定编码 如GBK
        byte[] bytes = s.getBytes("GBK");
        System.out.println(Arrays.toString(bytes));
    }

           

打印结果如下:

使用默认解码:

public static void main(String[] args) throws UnsupportedEncodingException {
        //解码
        //1.先定义一个字符串
        String s="中国";
        byte[] bytes = s.getBytes();
        //2.使用默认解码
        String str=new String(bytes);
        System.out.println(str);
    }

           

打印结果如下:

中国
           

使用指定字符集解码:

public static void main(String[] args) throws UnsupportedEncodingException {
        //解码
        //1.先定义一个字符串
        String s="中国";
        //使用GBK字符集编码
        byte[] bytes = s.getBytes("GBK");
        //2.使用GBK字符集解码
        String str=new String(bytes,"GBK");
        System.out.println(str);
    }

           

打印结果如下:

中国
           
字符流中的编码解码问题

字符流抽象基类

Reader:字符输入流的抽象类

Writer:字符输出流的抽象类

字符流中和编码解码问题相关的两个类:

InputStreamReader: 是从字节流到字符流的桥梁;他读取字节,并使用指定的charset将其解码为字符。它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

OutputStreamWriter: 是从字符流到字节流的桥梁;使用指定的charset将写入的字符编码为字节。它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。

OutputStreamWriter

构造方法:

  1. OutputStreamWriter(OutputStream out):创建一个使用默认字符编码的OutputStreamWriter
  2. OutputStreamWriter(OutputStream out,String charsetName):创建一个使用命名字符集的OutputStreamWriter

使用OutputStreamWriter(OutputStream out)构造方法写数据:

public static void main(String[] args) throws IOException {
        //1.创建字符流输出对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写数据
        osw.write("中国");
        //3.关闭
        osw.close();
    }
           

使用OutputStreamWriter(OutputStream out,String charsetName)构造方法写数据:

public static void main(String[] args) throws IOException {
        //1.创建字符流输出对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"GBK");
        //2.写数据
        osw.write("中国");
        //3.关闭
        osw.close();
    }
           

InputStreamReader:

  1. InputStreamReader(InputStream in); 创建一个使用默认字符集的InputStreamReader
  2. InputStreamReader(InputStream in,String charsetName); 创建一个使用命名字符集的InputStreamReager

使用InputStreamReader(InputStream in,String charsetName); 构造方法

public static void main(String[] args) throws IOException {
        //1.创建字符流输出对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"GBK");
        //2.写数据
        osw.write("中国");
        //3.关闭
        osw.close();


        InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt"),"GBK");
        //一次读取一个字符数据
        int ch;
        while ((ch=isr.read())!=-1){
            System.out.println((char)ch);
        }
        isr.close();
    }

           
字符流写数据的5种方式
方法名 说明
void write(int c) 写一个字符
void write(char[] cbuf) 写一个字符数组
void write(char[] cbuf,int off, int len) 写入字符数组的一部分
void write(String str) 写一个字符串
void write(String str, int off, int len) 写一个字符串的一部分
  1. 写入一个字符
public static void main(String[] args) throws IOException {
        //1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写一个字符
        osw.write(97);
        //3.刷新流(不刷新时,写入的数据还存在于缓冲区中,刷新后才写入文件)
        osw.flush();
        //4.释放资源(关闭流,会先刷新)
        osw.close();
    }
           
  1. 写入一个字符数组
//1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写入一个字符数组的数据
        char [] chs={'a','b','c','d','e'};
        //3.写入
        osw.write(chs);
        //4.关闭资源
        osw.close();
           
  1. 写入部分的字符数组
//1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写入一个字符数组的数据
        char [] chs={'a','b','c','d','e'};
        //3.写入一部分(从索引1往后写3个)
        osw.write(chs,1,3);
        //4.关闭资源
        osw.close();

           
  1. 写一个字符串
//1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //3.写入一个字符串
        osw.write("abcde");
        //4.关闭资源
        osw.close();
           
  1. 写入字符串的一部分
//1.创建一个默认字符编码的OutputStreamWriter对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //2.写入一个字符串(从索引1往后写3个)
        osw.write("abcde",0,3);
        //3.释放资源
        osw.close();
           
字符流读数据的2种方式
方法名 说明
int read() 一次读一个字符数据
int read(char [] cbuf) 一次读一个字符数组数据

一次读一个字符数据:

//1.创建一个默认字符集对象
        InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt"));
        //2.读数据
        int ch;
        while ((ch=isr.read())!=-1){
            System.out.println((char)ch);
        }
        //3.释放资源
        isr.close();
           

一次读一个字符数组数据:

//1.创建一个默认字符集对象
        InputStreamReader isr=new InputStreamReader(new FileInputStream("osw.txt"));
        //2.读数据
        char[] chs=new char[1024];
        int len;
        while ((len=isr.read(chs))!=-1){
            System.out.println(new String(chs,0,len));
        }
        //3.释放资源
        isr.close();
           

File类

File类概述和构造方法

File:它是文件和目录路径名的抽象表示,文件和目录可以通过File封装成对象,对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的。

方法名 说明
File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
File(String parent,String child) 从父路径名字符串和子路径字符串创建新的File实例
File(String parent,String child) 从父抽象路径和子路径名字符串创建新的File实例
public static void main(String[] args) {
        //1.通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
        File f1=new File("E:\\test\\java.txt");
        System.out.println(f1);

        //2.从父路径名字符串和子路径字符串创建新的File实例
        File f2=new File("E:\\test","java.txt");
        System.out.println(f2);

        //3.从父抽象路径和子路径名字符串创建新的File实例
        File f3=new File("E:\\test");
        File f4=new File(f3,"java.txt");
        System.out.println(f4);
    }

           

File类创建功能

方法名 说明
public boolean createNewFile() 当具有该文件不存在时,创建一个由该抽象路径名命名的新文件
public boolean mkdir() 创建由此抽象路径命名的目录
public boolean mkdirs() 创建由此抽象路径命名的目录,包括任何必须但不存在的父目录
public static void main(String[] args) throws IOException {
        //1.在E:\\test目录下创建一个文件java.txt
        File f1=new File("E:\\test\\java.txt");
        //如果文件不存在,就创建文件,并返回true,如果文件存在,就不创建文件,返回false
        boolean newFile = f1.createNewFile();
        System.out.println(newFile);

        //2.在E:\\test目录下创建一个目录JavaSE
        File f2=new File("E:\\test\\JavaSE");
        //如果目录不存在,就创建目录,并返回true,如果目录存在,就不创建目录,并返回false
        boolean mkdir = f2.mkdir();
        System.out.println(mkdir);

        //3.在E:\\test目录下创建一个多级目录JavaWEB\\HTML
        File f3=new File("E:\\test\\JavaWEB\\HTML");
        //如果目录不存在,就创建多级目录,并返回true,如果该多级目录存在,就不创建多级目录,并返回false
        boolean mkdirs = f3.mkdirs();
        System.out.println(mkdirs);

        //4.在E:\\test目录下创建一个文件java.txt
        File f4=new File("E:\\test\\javase.txt");
        //如果该文件存在,就创建文件,并返回true,如果该文件不存在,就不创建文件,并返回false
        boolean newFile1 = f4.createNewFile();
        System.out.println(newFile1);
    }
    
           

File类判断和获取功能

方法名 说明
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
public boolean String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径名字符串
public String getName() 返回由此抽象路径名表示的文件或目录的名称
public String[] list() 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles() 返回此抽象路径名表示的目录中的文件和目录的File对象数组
public static void main(String[] args) {
        //创建一个File对象
        File file=new File("test\\java.txt");
        //测试此路径抽象路径名表示的File是否为目录
        boolean directory = file.isDirectory();
        System.out.println(directory);

        //测试此抽象的路径名表示的File是否为文件
        boolean file1 = file.isFile();
        System.out.println(file1);

        //测试此抽象路径名表示的File是否存在
        boolean exists = file.exists();
        System.out.println(exists);

        //返回此抽象路径名的绝对路径名字符串
        String absolutePath = file.getAbsolutePath();
        System.out.println(absolutePath);

        //将此抽象路径名转换为路径名字符串
        String path = file.getPath();
        System.out.println(path);

        //返回此抽象路径名表示的文件或目录的名称
        String name = file.getName();
        System.out.println(name);


        File file2=new File("E:\\test");

        //返回此抽象路径名表示的目录中的文件和目录名称字符串
        String[] list = file2.list();
        for(String str:list){
            System.out.println(str);
        }

        //返回此抽象路径名表示的目录中的文件和目录的File对象数组
        File[] files = file2.listFiles();
        for(File file3:files){
            System.out.println(file3);
        }
    }

           

File类删除功能

方法名 说明
public boolean delete() 删除由此抽象路径名表示的文件或目录

删除目录时的注意事项:如果一个目录中有内容(目录、文件),不能直接删除。应该先删除目录中的内容,最后才能删除目录