Java IO流基础

JavaIO流

File类

File类的理解

  • File类的一个对象,代表一个文件或一个文件目录(俗称:文件夹)

  • FiLe类声明在java.io包下。

  • File类中涉及到关于文件或文件目录的创建、删除、重命名、修改时间、文件大小等方法,并未涉及到写入或读取文件内容的操作。如果需要读取或写入文件内容,必须使用Io流来完成。

  • 后续File类的对象常会作为参数传递到流的构造器中,指明读取或写入的"终点"。

File的构造器
  • File(String filePath)

  • File(string parentPath,string childPath)

  • File(File parentFile,string childPath)

路径的分类
  • 相对路径:相较于某个路径下,指明的路径。
  • 绝对路径:包含盘符在内的文件或文件目录的路径。

说明:IDEA中:
如果大家开发使用JUnit中的单元测试方法测试,相对路径即为当前Module下.如果大家使用main()测试,相对路径即为当前的Project下。
Eclipse中:
不管使用单元测试方法还是使用main()测试,相对路径都是当前的Project下。

路径分隔符
  • windows和DOS系统默认使用"\"来表示
  • UNIX和URL使用"/"来表示
File类的常用方法

File类的获取功能

  • **public String getAbsolutePath():**获取绝对路径。
  • public String getPath():获取路径。
  • public String getName():获取名称。
  • **public String getParent():**获取上层文件目录路径。若无,返回null。
  • public long length():获取文件长度(即:字节数)。不能获取目录的长度。
  • public long lastModified():获取最后一次的修改时间,毫秒值。
  • public String[] list():获取指定目录下的所有文件或者文件目录的名称数组。
  • public File[] listFiles():获取指定目录下的所有文件或者文件目录的File数组。

File类的重命名功能

  • public boolean renameTo(File dest):把文件重命名为指定的文件路径

File类的判断功能

  • **public boolean isDirectory():**判断是否是文件目录。
  • **public boolean isFile():**判断是否是文件。
  • **public boolean exists():**判断是否存在。
  • public boolean canRead():判断是否可读。
  • public boolean canWrite() :判断是否可写。
  • public boolean isHidden():判断是否隐藏。

File类的创建功能

  • **public boolean createNewFile():**创建文件。若文件存在,则不创建,返回false。
  • public boolean mkdir():创建文件目录。如果此文件目录存在,就不创建了。如果此文件目录的上层目录不存在,也不创建。
  • **public boolean mkdirs():**创建文件目录。如果上层文件目录不存在,一并创建注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目路径下。

File类的删除功能

  • **public boolean delete():**删除文件或者文件夹删除
  • 注意事项:
    Java中的删除不走回收站。
    要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录。

IO流

Java IO 原理
  • I/O是Input/Output的缩写,I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
  • Java程序中,对于数据的输入/输出操作以“流(stream)”的方式进行。
  • java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。
  • **输入input:**读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
  • **输出output:**将程序(内存)数据输出到磁盘、光盘等存储设备中。
流的分类
  • 按操作数据单位不同分为:字节流(8bit),字符流(16bit).
  • 按数据流的流向不同分为:输入流,输出流。
  • 按流的角色的不同分为:字节流,处理流。
(抽象基类)字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter
  1. Java的Io流共涉及40多个类,实际上非常规则,都是从如下4个
    抽象基类派生的。
  2. 由这四个类派生出来的子类名称都是以其父类名作为子类名后缀。
IO流体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pQTob3gk-1618457017080)(JavaIO流.assets/image-20210412152119265.png)]

字节流

FileReader
package com.zy.TestIO;

import org.junit.Test;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class TestFileReader {
//    说明点:
//            1. read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
//            2.异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
//            3.读入的文件一定要存在,否则就会报FiLeNotFoundException。
    @Test
    public void Test01(){
        //创建流
        FileReader fr = null;
        try {
            //1.实例化File对象,指明要操作的文件
            File file = new File("src/com/zy/TestIO/hello.txt");
            //2.具体的操作流
            fr = new FileReader(file);
            //3.创建接收
            int data ;
            //4.数据读入
            //read()每次读入一个字符,如果到文件末尾,返回-1
            while ((data=fr.read())!=-1)
            {
                //read()返回的是字符对应的ascii码
                System.out.print((char) data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //判断流存在,再关闭
            if(fr!=null) {
                try {
                    //关闭流
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void Test02(){
        //创建流
        FileReader fr = null;
        try {
            //1.实例化File对象,指明要操作的文件
            File file = new File("src/com/zy/TestIO/hello.txt");
            //2.具体的操作流
            fr = new FileReader(file);
            //3.创建接收字符数组,长度为5
            char[] cbuffer = new char[5];
            int len;
            //4.数据读入
            //read()每次读入字符数组长度,如果到文件末尾,返回-1
            while ((len=fr.read(cbuffer))!=-1)
            {
                //方法1
//                for(int i=0;i<len;i++)
//                {
//                    System.out.print(cbuffer[i]);
//                }
                //方法2
                String str =new String(cbuffer,0,len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //判断流存在,再关闭
            if(fr!=null) {
                try {
                    //关闭流
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
FileWriter
package com.zy.TestIO;

import org.junit.Test;

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

public class TestFileWriter {
    public static void main(String[] args) {

    }
//    说明:
//            1.输出操作,对应的File可以不存在的。并不会报异常
//            2.File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
//            File对应的硬盘中的文件如果存在:如果流使用的构造器是:Filewriter(file,false) / Filewriter(file)(默认为false):,对文件的进行覆盖
//            对原如果流使用的构造器是:Filewriter(file,true):不会对原有文件覆盖,而是在后面继续添加

    @Test
    public void Test01(){
        FileWriter fw = null;
        try {
            //创建File的对象,指定操作
            File file = new File("src/com/zy/TestIO/Hellot.txt");
            //创建操作流
            fw = new FileWriter(file);
            //开始写入
            fw.write("hello world\n");
            fw.write("你好!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                if(fw!=null)
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}
前两者结合
@Test
    public void TestFileReaderFileWriter(){
        FileReader fr = null;
        FileWriter fw = null;
        try {
            //1.创建读写的文件
            File rfile = new File("src/com/zy/TestIO/hello.txt");
            File wfile = new File("src/com/zy/TestIO/Hellot.txt");
            //2.创建对应操作流
            fr = new FileReader(rfile);
            fw = new FileWriter(wfile);

            //3.创建字符数组,开始读写
            char[] cbuffer = new char[5];
            int len;
            while ((len = fr.read(cbuffer))!=-1)
            {
                fw.write(cbuffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            //方法1
//            try {
//                if(fw!=null)
//                fw.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }finally {
//                try {
//                    if(fr!=null)
//                    fr.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }

            //方法2,两者没有区别
            try {
                if(fw!=null)
                fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if(fr!=null)
                    fr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

不能用字符流实现图片视频的复制,要用字节流

FileInputStream FileOutputStream
package com.zy.TestIO;

import org.junit.Test;

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

public class TestFileInputStreamFileOutputStream {
//方法使用和字符流类似
// 测试FiLeInputstream和FileoutpuStream的使用*
//    结论:
//        1.对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
//        2.对于非文本文件(.jpg,.mp3 ,.mp4, .avi,.doc,.ppt,. ..),使用字节流处理

    @Test
    public void Test01(){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //使用字节流操作文本文件可能会出现乱码
            //1.复制图片,开创建文件
            File ipsFile = new File("src/com/zy/TestIO/bj.jpg");
            File opsFile = new File("src/com/zy/TestIO/bj2.jpg");
            //2.创建对应操作字节流
            fis = new FileInputStream(ipsFile);
            fos = new FileOutputStream(opsFile);
            //3.创建字节数组
            byte[] buffer = new byte[1024];
            int len;
            //4.开始复制
            while ((len = fis.read(buffer))!=-1)
            {
                fos.write(buffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //5.关闭流
            try {
                if(fos!=null)
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(fis!=null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

缓冲流

BufferedInputStream,BufferedOutputStream
package com.zy.TestIO;

import org.junit.Test;

import java.io.*;

public class TestBuffered {
//    作用:提高流的读取、写入的速度
//    提高读写速度的原因:内部提供了一个缓冲区,大小为8192,bos.flush();刷新缓冲区,没存满就先输出,满了会自动调用
    public static void CopyBuffered(String srcFile,String destFile){

        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            //创建文件
            File srcfile = new File(srcFile);
            File destfile = new File(destFile);
            //创建节点流
            FileInputStream fis = new FileInputStream(srcfile);
            FileOutputStream fos = new FileOutputStream(destfile);
            //创建缓冲流
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
            //创建字节数组,开始复制
            byte[] bytes = new byte[1024];
            int len;
            while ((len = bis.read(bytes))!=-1){
                bos.write(bytes,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            //先关外面的,再关里面的
            //不过缓冲流的关闭会自动关闭内部的流
            if(bos!=null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bis!= null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    @Test
    public void Test01(){
        long start =  System.currentTimeMillis();
        String srcFile = "E:\\QLDownload\\新世界\\新世界 第69集 蓝光(1080P).qlv";
        String destFile = "E:\\视频\\xsj.qlv";
        TestBuffered.CopyBuffered(srcFile,destFile);
        long end = System.currentTimeMillis();
        System.out.println("时间:"+(end-start));//时间:4119,没有用缓冲流的时间为6451
    }
}
BufferedReader,BufferedWriter

使用方法和上面的相同,只是是字符流

读写的特殊方法

@Test
    public void Test02(){
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            //创建流
            br = new BufferedReader(new FileReader(new File("src/com/zy/TestIO/hello.txt")));
            bw = new BufferedWriter(new FileWriter(new File("src/com/zy/TestIO/hellot.txt")));
            //方法一:
//            char[] cb = new char[1024];
//            int len;
//            while((len=br.read(cb))!=-1){
//                bw.write(cb,0,len);
//            }
            //方法二:
            String data;
            while ((data=br.readLine())!=null)//每次返回一行,结束返回null
            {
//                bw.write(data);//没有换行符,复制的内容会在一排
                //1.
//                bw.write(data+"\n");
                //2.
                bw.write(data);
                bw.newLine();//相当于一个换行行符
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if(bw!=null) {
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(br!=null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

转换流

  • 转换提供了在字符流和字节流之间的转换
  • Java API 提供了两个转换流:
    • InputStreamReader:将InputStream转换为Reader
    • OutputStreamWriter:将Writer转换为OutputStream
    • 这两个流属于字符流
  • 字节流中的数据都是字符时,转换字符流操作更高效。
  • 很多时候我们使用转换流来处理文件乱码问题。实现编码和解码的功能。
    • 解码:字节、字节数组—>字符数组、字符串
    • 编码:字符数组、字符串—>字节、字节数组
package com.zy.TestIO;

import org.junit.Test;

import java.io.*;

public class TestInputStreamReader {
    /**
     * 结合使用,可以定义字符集,定义复制的文件的字符集
     */
    @Test
    public void Test01(){
        InputStreamReader isr = null;
        OutputStreamWriter osw = null;
        try {
            //1.创建流和操作的文件
            isr = new InputStreamReader(new FileInputStream(new File("src/com/zy/TestIO/hello.txt")),"UTF-8");
            osw = new OutputStreamWriter(new FileOutputStream(new File("src/com/zy/TestIO/hello_gdk.txt")),"gbk");

            //2.读写操作
            char[] cbuffer =new char[1024];
            int len;
            while ((len=isr.read(cbuffer))!=-1){
                String str = new String(cbuffer,0,len);
                System.out.println(str);
                osw.write(cbuffer,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.关闭流,外面关闭,内部一起
            try {
                if(osw!=null)
                osw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if(isr!=null)
                isr.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
字符编码
  • 编码表的由来
    计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。这就是编码表。

  • 常见的编码表

    • **ASCII:**美国标准信息交换码。
      • 用一个字节的7位可以表示。
    • **ISO8859-1:**拉丁码表。
      • 欧洲码表用一个字节的8位表示。
    • **GB2312:**中国的中文编码表。最多两个字节编码所有字符
    • **GBK:**中国的中文编码表升级,融合了更多的中文文字符号。最多两个字节编码
    • **Unicode:**国际标准码,融合了目前人类使用的所有字符。为每个字符分配唯一的字符码。所有的文字都用两个字节来表示
    • **UTF-8:**变长的编码方式,可用1-4个字节来表示一个字符。
  • Unicode不完美,这里就有三个问题,一个是,我们已经知道,英文字母只用一个字节表示就够了,第二个问题是如何才能区别Unicode和IASClI?计算机怎么知道两个字节表示一个符号,而不是分别表示两个符号呢?第三个,如果和GBK等双字节编码方式一样,用最高位是1或O表示两个字节和一个字节,就少了很多值无法用于表示字符,不够表示所有字符。unicode在很长一段时间内无法推广,直到互联网的出现。

  • 面向传输的众多UTF (UCS Transfer Format)标准出现了,顾名思义,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。

  • Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体存储成什么样的字节流,取决于字符编码方案。推荐的Unicode编码是UTF-8和UTF-16。

其他类型流

标准的输入输出流
  • System.in和System.out分别代表了系统标准的输入和输出设备
  • 默认输入设备是:键盘,输出设备是:显示器
  • System.in的类型是lnputStream
  • System.out的类型是PrintStream,其是OutputStream的子类FilterOutputStream的子类
  • 重定向:通过System类的setIn,setOut方法对默认设备进行改变。
    • public static void setln(InputStream in)
    • public static void setOut(PrintStream out)
package com.zy.TestIO;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Locale;

public class TestOtherIO {
    public static void main(String[] args) {
        BufferedReader br = null;
        try {
            //创建,要使用到缓冲流和转换流,测试System.in
            br = new BufferedReader(new InputStreamReader(System.in));

            //获取键盘输入的内容,exit结束
            while (true){
                System.out.println("输入:");
                String str = br.readLine();
                if(str.equalsIgnoreCase("exit")){
                    System.out.println("程序结束");
                    break;
                }
                String data = str.toUpperCase(Locale.ROOT);
                System.out.println(data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            try {
                if(br!=null)
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
打印流
  • 实现将基本数据类型的数据格式转化为字符串输出
  • 打印流:PrintStream和PrintWriter
    • 提供了一系列重载的print()和println()方法,用于多种数据类型的输出
    • PrintStream和PrintWriter的输出不会抛出IOException异常
    • PrintStream和PrintWriter有自动flush功能
    • PrintStream打印的所有字符都使用平台的默认字符编码转换为字节。在需要写入字符而不是写入字节的情况下,应该使用PrintWriter 类。
    • System.out返回的是PrintStream的实例

打印流就是可以将输出到页面的内容,自己定义一个文件,打印到那个文件中去

@Test
    public void TestPrint(){
        PrintStream ps = null;
        try {
            //创建文件输出流
            FileOutputStream fos = new FileOutputStream(new File("src/com/zy/TestIO/print.txt"));
            //创建打印流
            ps = new PrintStream(fos,true);
            //将标准输出改为文件
            if(ps!=null)
            {
                System.setOut(ps);
            }
            //执行
            for(int i =0;i<255;i++)
            {
                System.out.print((char) i);//输出AscII码字符
                if(i%50==0)//每五十个换行
                {
                    System.out.println();
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if(ps!=null)
            ps.close();
        }
    }
数据流
  • 为了方便地操作Java语言的基本数据类型和Strirjg的数据,可以使用数据流。
  • 数据流有两个类:(用于读取和写出基本数据类型、String类的数据)
    • DatalnputStream和 DataOutputStream
    • 分别“套接”在 lnputStream和 OutputStream子类的流上
  • DatalnputStream中的方法
    boolean readBoolean()
    byte readByte()
    char readChar()
    float readFloat()
    double readDouble()
    short readShort()
    long readLong()
    int readInt()
    String readUTF()
    void readFully(byte[] b)
  • DataOutputStream中的方法
    将上述的方法的read改为相应的write即可。
 @Test
    public void TestDataOutputStream(){
        DataOutputStream dos = null;
        try {
            //创建数据流,将内存中的数据写入文件
            dos = new DataOutputStream(new FileOutputStream(new File("src/com/zy/TestIO/data.txt")));
            //写入数据
            dos.writeUTF("字符串");
            dos.flush();//刷新缓冲,将上面内容保存到文件中
            dos.writeInt(22);//int
            dos.flush();
            dos.writeBoolean(true);//boolean
            dos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if(dos!=null) {
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Test
    public void TestDateInputStream(){
        DataInputStream dis = null;
        try {
            //将基本类型从文件中输入出来
            dis = new DataInputStream(new FileInputStream(new File("src/com/zy/TestIO/data.txt")));
            //要按写入的顺序将它们输入
            String str = dis.readUTF();
            int i = dis.readInt();
            boolean b = dis.readBoolean();
            System.out.println("String:"+str+" int:"+i+" boolean:"+b);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //关闭流
            if(dis!=null) {
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

用数据流存入文件的内容,只能用数据流再输出,不能直接查看

数据流只能操作基本数据类型和Strirjg的数据,要操作对象要使用对象流

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值