Java第十四周作业

本文深入讲解Java中的IO流概念,包括流的分类、特点及体系结构。详细介绍File类的使用,以及FileInputStream/FileOutputStream和FileReader/FileWriter的操作方法。并通过综合实例演示不同流的文件复制过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本周主题:IO数据流

目录

本周主题:IO数据流

一、流的基础知识

(一)、流的概念

(二)、流的分类与特点

(三)、IO流的体系结构

1、IO流的总体分类

2、字节流和字符流体系

二、常用类的使用

(一)、File类

(二)、FileInputStream和FileOutputStream

(三)、FileReader和FileWriter

(四)、综合实例Demo


一、流的基础知识

(一)、流的概念

大多数应用程序都需要实现与设备之间的数据传输,如键盘可以输入数据,显示器可以显示程序运行的结果等。任何一种编程语言都必须拥有输入/输出的处理方式,Java也不例外。在Java中将这种通过不同输入、输出设备(键盘、内在、显示器、网络等)之间的数据传输抽象表达为“流”,程序允许通过流的方式与输入/输出设备进行数据传输。Java提供了大量的类来对流进行操作,从而实现了输入/输出功能。

James Gosling所著《Java程序设计》中描述Java I/O流模式图如下。Program是中间环节,用于对Source进行处理,然后输出到Dest处。

从Java 1.0开始,引入java.io包;到Java 1.4再扩展了java.nio包;再到java 1.7又添加了新的流类,使得Java的流机制变得十分强大。Java中的“流”都位于java.io/java.nio包中,称为IO(输入/输出)流,如下图所示。

(二)、流的分类与特点

IO流有很多种,按照不同的分类标准可以分为不同的类别。

1、按数据传输方向的不同,数据流可分为输入流输出流

判断当前流是输入流还是输出流,依据的是二进制数据相对于计算机内存的位置,由于程序就是运行在内存中的,所以判断当前流是输入流还是输出流都是站在程序的立场来看待的,比如输入流是输入到计算机内存的二进制数据,输出流是从计算机内存中输出的二进制数据。比如键盘键入数据属于输入流,内存数据持久化存储到磁盘中则属于输出流。

2、按照操作数据的不同,可以分为字节流字符流

从物理层面来看,流中数据都是二进制比特流。而计算机中储存信息的基本单位是字节(Byte)。因此,可以认为计算机中信息传输在底层是靠字节流来实现的。字符流只是通过不同的字符编码方式,对字节流的封装,即字符流的实现还是得依靠字节流。

一般情况下,我们习惯使用字符流来处理文本类型的数据,如文本文件的读写、键盘输入的处理等,而使用字节流来处理二进制数据,如图像、音频、视频数据等。

  • a)字节流默认是不带缓冲区的,而字符流默认是带缓冲区的。
  • b)字节流是底层数据流,是数据有意义的最小单位。字符流是字节流的包装,底层实现是字节流。
  • c)基于b点,文本文件可以用字节流来实现,当然使用字符流速度会更快。

字节流用来处理没有进行加工的原始数据,字符流是经过了编码的符合某种格式规定的数据。程序从输入流中读取数据,向输出流中写入数据。

3、按照流的功能来分,流又可以分为:节点流(又称低级流)、过滤流(又称高级流、处理流、包装流)

节点流(Node Stream)是流管道两端直接连接data source和data destination上的,即为取放数据的真实载体,在流通道本身不对数据做任何加工,因而也被称为低级流。

  过滤流(Filter Stream)是套在节点流或过滤上的,而且过滤流是不能够脱离节点流(低级流)存在的,因此称为高级流。过滤流的流管道本身封装方法,能够对低级流数据进行处理,因此也被称为处理流。究其本质,过滤流就是把不符合通过管道条件的数据过滤掉,而让满足条件的数据通过过滤流管道。

(三)IO流的体系结构

1、IO流的总体分类

2、字节流和字符流体系

二、常用IO类的使用

(一)、File类

在介绍其他IO流及其使用方法之前先介绍File类,因为大多数流是以文件为数据源和目的地的。Java提供的File类既可以表示文件,也可以表示目录,利用File类可以对文件或目录及其属性进行基本操作,创建和删除等,也可以获取与文件相关的信息,如名称、最后的修改日期、文件大小等。

File中的方法是对磁盘上的文件进行属性读写操作,但是无法读取文件的内容。 需要注意的是,创建一个文件对象和创建一个文件在Java中是两个不同的概念,前者是在JVM中创建了一个文件,但并没有将它真正地创建(写入)到OS的文件系统中(磁盘)。

举个File类使用测试的例子:

import java.io.File;

/**
 * 文件名:MyFileTest.java
 * 功能描述:File类的使用测试Demo
 */
public class MyFileTest {
    public static void main(String[] args) {
        //此处实例化了一个文件对象,并非是在磁盘上创建了一个文件,且此File对象是无法读取文件内容的
        File file = new File("example.txt");
        System.out.println("文件名称:"+file.getName());
        System.out.println("文件路径:"+file.getPath());
        System.out.println("文件绝对路径:"+file.getAbsolutePath());
        System.out.println("文件父路径:"+file.getParent());
        System.out.println(file.canRead()?"文件可读":"文件不可读");
        System.out.println(file.canWrite()?"文件可写":"文件不可写");
        System.out.println(file.isFile()?"是一个文件":"不是一个文件");
        System.out.println(file.isDirectory()?"是一个目录":"不是一个目录");
        System.out.println(file.isAbsolute()?"是一个绝对路径":"不是一个绝对路径");
        System.out.println("文件最后修改时间:"+file.lastModified());
        System.out.println("文件大小:"+file.length()+"bytes");
        System.out.println("文件删除是否成功:"+file.delete());
    }
}

运行结果:

  

分析:

本例子中, E:\xxx\java_demo\week14\MyFileTest\ 目录下并不存在example.txt,因此file变量所获取的对象,既不是一个目录也不是一个文件,其父路径为null,且不可读、不可写,无文件大小,无最后修改日期、无法删除……。

(二)、FileInputStream和FileOutputStream

FileInputStream和FileOutputStream是专门用于读取/写入文件中的数据,它们操作文件的字节流的输入/输出。

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

/**
 * 文件名:ByteStreamTest.java
 * 功能描述:字节流文件读写测试
 */
public class ByteStreamTest {
    void readFile() throws IOException {
        FileInputStream in = null;
        try {
            in = new FileInputStream("test.txt");
            int b = 0;
            while (true) {
                b = in.read(); //一次读取一个字节
                if (b == -1)
                    break;
                System.out.printf("%d ", b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null)
                in.close();
        }
    }

    void writeFile() throws IOException {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream("test.txt");
            String str = "Java数据写入";
            byte[] b = str.getBytes();
            for (int i = 0; i < b.length; i++) {
                out.write(b[i]);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            out.close();
        }
    }

    public static void main(String[] args) {
        ByteStreamTest test = new ByteStreamTest();
        try {
            test.writeFile();
            test.readFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

 

(三)、FileReader和FileWriter

 在程序开发中,经常需要对文本文件的内容进行读取/写入,如果想从文件中直接读取/写入字符,便可以使用字符输入流FileReader和输出流FileWriter。

import java.io.*;

/**
 * 文件名:CharStreamTest.java
 * 功能描述:字符流文件读写测试
 */
public class CharStreamTest {
    void readFile() throws IOException {
        FileReader in = null;
        try {
            in = new FileReader("test.txt");
            int b = 0;
            while (true) {
                b = in.read(); //一次读取一个字符
                if (b == -1)
                    break;
                System.out.printf("%c", b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null)
                in.close();
        }
    }

    void writeFile() throws IOException {
        FileWriter out = null;
        try {
            out = new FileWriter("test.txt");
            String str = "Java数据写入";
            out.write(str);
            out.write("\r\n");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            out.close();
        }
    }

    public static void main(String[] args) {
        CharStreamTest test = new CharStreamTest();
        try {
            test.writeFile();
            test.readFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

  

(四)、综合实例Demo

 分别使用字节流(FileInputStream、FileOutputStream)、字节流+缓存流(BufferedInputStream、BufferedOutputStream)、字符流(InputStreamReader、OutStreamReader)、字符流+缓存流(BufferedReader、BufferedWriter)进行文件复制的综合实例Demo。

1、文件操作类

import java.io.*;
/**
 * 文件名:StreamOperator.java
 * 功能描述:流操作类文件
 */
public class StreamOperator {
    private final int BUF_SIZE = 10; //为演示效果,故意把缓存设置得很小,正常一般为1024的倍数

    //-----------------字节流文件复制方法---------------//
    void CopyFileByByteStream(String sFileName,String dFileName) throws IOException {
        FileInputStream fis = null;
        FileOutputStream fos = null;

        long byteStart = System.currentTimeMillis();//获取系统当前时间戳
        try {
            fis = new FileInputStream(sFileName);
            fos = new FileOutputStream(dFileName);

            int len = 0;

            byte[] byteArray = new byte[BUF_SIZE];

            while ((len = fis.read(byteArray))>0) {
                fos.write(byteArray,0,len);
            }
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null)
                fis.close();
            if (fos != null)
                fos.close();

            long byteEnd = System.currentTimeMillis();
            System.out.println("字节流复制文件完毕!共花费"+(byteEnd-byteStart)+"毫秒。");
        }

    }

    //-----------------字节流+缓存流文件复制方法---------------//
    void CopyFileByByteBufferedStream(String sFileName,String dFileName) throws IOException {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        long startTime = System.currentTimeMillis();
        try {
            bis = new BufferedInputStream(new FileInputStream(sFileName));
            bos = new BufferedOutputStream(new FileOutputStream(dFileName));

            int len = 0;
            byte[] bufArray = new byte[BUF_SIZE];
            while ((len = bis.read(bufArray))>0) {
                bos.write(bufArray,0,len);
            }
            bos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null)
                bis.close();
            if (bos != null)
                bos.close();

            long endTime = System.currentTimeMillis();
            System.out.println("字节流+缓存流复制文件完毕!共花费"+(endTime-startTime)+"毫秒。");
        }
    }

    //-----------------字符流文件复制方法---------------//
    void CopyFileByCharStream(String sFileName,String dFileName) throws IOException {
        InputStreamReader reader = null;
        OutputStreamWriter writer = null;

        //FileReader fileReader = null;
        //FileWriter fileWriter = null;

        long startTime = System.currentTimeMillis();
        try {
            String charsetName = getFileCharsetName(sFileName);
            reader = new InputStreamReader(new FileInputStream(sFileName),charsetName);
            writer = new OutputStreamWriter(new FileOutputStream(dFileName),charsetName);

            //fileReader = new FileReader(sFileName);
            //fileWriter = new FileWriter(dFileName);

            int len = 0;
            char[] charArray = new char[BUF_SIZE];
            while ((len = reader.read(charArray))>0) {
                writer.write(charArray,0,len);
            }
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null)
                reader.close();
            if (writer != null)
                writer.close();
            long endTime = System.currentTimeMillis();
            System.out.println("字符流复制文件完毕!共花费"+(endTime-startTime)+"毫秒。");
        }
    }

    //-----------------字符流+缓存流文件复制方法---------------//
    void CopyFileByCharBufferedStream(String sFileName,String dFileName) throws IOException {
        InputStreamReader reader = null;
        OutputStreamWriter writer = null;

        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;

        long startTime = System.currentTimeMillis();
        try {
            String charsetName = getFileCharsetName(sFileName);
            reader = new InputStreamReader(new FileInputStream(sFileName),charsetName);
            writer = new OutputStreamWriter(new FileOutputStream(dFileName),charsetName);

            bufferedReader = new BufferedReader(reader);
            bufferedWriter = new BufferedWriter(writer);

            int len = 0;
            char[] charArray = new char[BUF_SIZE];
            while ((len = bufferedReader.read(charArray))>0) {
                bufferedWriter.write(charArray,0,len);
            }
            bufferedWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bufferedReader != null)
                bufferedReader.close();
            if (bufferedWriter != null)
                bufferedWriter.close();
            if (reader != null)
                reader.close();
            if (writer != null)
                writer.close();
            long endTime = System.currentTimeMillis();
            System.out.println("字符流+缓存流复制文件完毕!共花费"+(endTime-startTime)+"毫秒。");
        }
    }

    /**
     * 获取文本文件的编码格式
     * @param fileName :file
     * @return 文件编码格式
     * @throws IOException
     */
    public static String getFileCharsetName(String fileName) throws IOException {
        InputStream inputStream = new FileInputStream(fileName);
        byte[] head = new byte[3];
        inputStream.read(head);

        String charsetName = "GBK";//或GB2312,即ANSI
        if (head[0] == -1 && head[1] == -2 ) //0xFFFE
            charsetName = "UTF-16";
        else if (head[0] == -2 && head[1] == -1 ) //0xFEFF
            charsetName = "Unicode";//包含两种编码格式:UCS2-Big-Endian和UCS2-Little-Endian
        else if(head[0]==-27 && head[1]==-101 && head[2] ==-98)
            charsetName = "UTF-8"; //UTF-8(不含BOM)
        else if(head[0]==-17 && head[1]==-69 && head[2] ==-65)
            charsetName = "UTF-8"; //UTF-8-BOM

        inputStream.close();

        //System.out.println(charsetName);
        return charsetName;
    }
}

2、测试类文件: 

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

/**
 * 文件名:StreamOperatorTest.java
 * 功能描述:测试文件
 */
public class StreamOperatorTest {
    public static void main(String[] args) {
        StreamOperator streamTest = new StreamOperator();

        //获取*.class文件所在的目录
        String path = StreamOperatorTest.class.getProtectionDomain().getCodeSource().getLocation().getPath();
        //System.out.println(path);
        //System.out.println(System.getProperty("user.dir"));

        String sFileName = path+"回到明朝当王爷.txt";
        String fileName = path+"*结果文件.txt";
        String dFileName;

        try {
            long fileSize = new FileInputStream(sFileName).available();
            System.out.printf("源文件大小为:%,d Byte!字符编码为:%s \n",fileSize,StreamOperator.getFileCharsetName(sFileName));
            dFileName = fileName.replace("*","字节流复制");
            streamTest.CopyFileByByteStream(sFileName,dFileName);

            dFileName = fileName.replace("*","字节缓存流复制");
            streamTest.CopyFileByByteBufferedStream(sFileName,dFileName);

            dFileName = fileName.replace("*","字符流复制");
            streamTest.CopyFileByCharStream(sFileName,dFileName);

            dFileName = fileName.replace("*","字符缓存流复制");
            streamTest.CopyFileByCharBufferedStream(sFileName,dFileName);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

3、运行结果:

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值