Java中的IO流

一、什么是IO流

I:Input O:Output (输入流,输出流)

任何一款操作系统在管理硬盘文件的时候都离不开IO操作。可以理解通过IO完成硬盘文件的读写。比如我们日常在windows系统上复制拷贝某个文件,就是先通过输入流的方式读取文件,再将文件通过输出流输出到指定目录文件下面。

IO流又称为输入输出流,输入和输出均是以内存作为参照物。(内存:是本次IO操作所占用的资源)

java中的I/O操作主要是指使用java进行输入,输出操作。Java所有的I/O机制都是基于数据流进行输入输出,这些数据流表示了字符或者字节数据的流动序列。Java的I/O流提供了读写数据的标准方法。任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法。

1. I/O流的分类?

按照流的方向进行分类:

以内存(IDEA运行的代码程序)作为参照物,往内存中流的,称为输入流、读。从内存往外的,称之为输出流、写。

  • 输入流:磁盘流向内存中去;

  • 输出流:内存(程序)流向外部;

按照读取数据方式不同进行分类:

字节流

字符流

输入流

InputStream

Reader

输出流

OutputStream

Writer

  • 字节流:数据流中最小的数据单元是字节,单位是1字节8byte

  • 字符流:数据流中最小数据单元是字符,java中的字符是Unicode编码,一个字符占用两个字节 16byte

2.java IO流四大抽象类

  • java.io.InputStream 字节输入流

  • java.io.OutputStream 字节输出流

  • java.io.Reader 字符输入流

  • java.io.Writer 字符输出流

所有的流都实现如下接口:

java.io.Colseable接口:都是可关闭的,都有close()方法. 流毕竟是一个管道,这个是内存和硬盘之间的通道,养成一个好习惯,用完流将其关闭。

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

小结:在java中只要"类名"以Stream结尾的都是字节流。以"Reader/Writer"结尾的都是字符流 。

3.根据功能分为节点流和包装流

节点流:可以从或向一个特定的地方(节点)读写数据,直接连接数据源。如最常见的是文件的FileReader,还可以是数组、管道、字符串,关键字分别为ByteArray/CharArray,Piped,String。

处理流(包装流):并不直接连接数据源,是对一个已存在的流的连接和封装,是一种典型的装饰器设计模式,使用处理流主要是为了更方便的执行输入输出工作,如PrintStream,输出功能很强大,又如BufferedReader提供缓存机制,推荐输出时都使用处理流包装。

一个流对象经过其他流的多次包装,称为流的链接。

注意:一个IO流可以即是输入流又是字节流又或是以其他方式分类的流类型,是不冲突的。比如FileInputStream,它既是输入流又是字节流还是文件节点流。

4.一些特别的流类型

转换流:转换流只有字节流转换为字符流,因为字符流使用起来更方便,我们只会向更方便使用的方向转化。如:InputStreamReader与OutputStreamWriter。

缓冲流:有关键字Buffered,也是一种处理流,为其包装的流增加了缓存功能,提高了输入输出的效率,增加缓冲功能后需要使用flush()才能将缓冲区中内容写入到实际的物理节点。但是,在现在版本的Java中,只需记得关闭输出流(调用close()方法),就会自动执行输出流的flush()方法,可以保证将缓冲区中内容写入。

对象流:有关键字Object,主要用于将目标对象保存到磁盘中或允许在网络中直接传输对象时使用(对象序列化)。

二.流的使用

1.文件字节流

FileInputStream

文件字节输入流,万能的,任何类型的文件都可以采用这个流来读,读取单位是1字节。流的方向是(硬盘—>内存)

public class FileInputStreamTest {
    public static void main(String[] args){
        //读取文件
        try {
            FileInputStream fis = new FileInputStream("E:\\Student.txt");
            int read1 = fis.read();//read()是读取到的字节大小
            int read2 = fis.read();
            //如果读不到数据,程序则默认返回-1
            System.out.println(read1);
            System.out.println(read2);
            fis.close();
        }catch (IOException e){
         //因为涉及到外部file读取,java认为这种外部获取文件,是不可控且不可靠的,所以得try{}catch一下
            System.out.println("找不到指定的文件"+e);
        }
    }

错误路径("E:\\Student1.txt")运行结果:

正确路径("E:\\Student.txt")运行结果:

上面的代码只read()了两次并没有将文件读完,read()方法返回类型的亦是int类型。 这里的read()方法在读到文件末尾时会返回-1。

/**
对上面的代码进行改进,采用循环遍历的方式,读完Student.txt文件
*/

public class FileInputStreamTest {
    public static void main(String[] args){
        try {
            FileInputStream fis=null;
            fis=new FileInputStream("E:\\Student.txt");
            while (true){
                int read=fis.read();
                if(read==-1){
                    break;
                }
                 System.out.print(read+" ");
            }
            if(fis !=null){
               fis.close();
            }
        }catch (IOException e){
            System.out.println("找不到指定路径"+e);
        }    
    }
}

运行结果:一大串返回的长度。

read()方法

int read(byte[] b)
一次最多读取b.length个字节
减少硬盘和内存的交互,提高程序的执行效率往byte[]数组当中读
public class FileInputStreamTest {
    public static void main(String[] args){
        try {
            FileInputStream fis = null; // 创建一个流
            fis =  new FileInputStream("E://Student.txt");
            // 开始读  采用byte数组  一次读取多个字节。最多读取数组.length个字节.
            byte[] bytes = new byte[4]; // 准备一个4长度的byte数组,一次最多读取4个字节
            // 返回读到的字节数量(不是字节本身)(把数据读取到了byte数组当中)
            int readCount = fis.read(bytes); // 4
            //System.out.println(new String(bytes)); // 将字节数组全部转换成字符串
            // 不应该全部转换,应该是读取了多少字节,转换多少个
            System.out.println(new String(bytes,0,readCount));
            System.out.println(readCount);
            readCount = fis.read(bytes); // 2
            System.out.println(new String(bytes,0,readCount));
            System.out.println(readCount);
            readCount = fis.read(bytes); // -1 (一个字节都没有读到)
            System.out.println(new String(bytes,0,readCount));
            System.out.println(readCount);

//---------------------------------------------------
            // 准备一个byte数组
//            byte[] bytes = new byte[4];
//            int readCount;
//            while((readCount = fis.read(bytes))!=-1){
//                // 把byte数组转换成字符串,读到多少个转换多少个
//                System.out.print(new String(bytes,0,readCount));
//            }
//            if(fis!=null){
//                fis.close();
//            }
//----------------------------------------------------           
        }
        catch (IOException e){
            System.out.println("找不到指定路径"+e);
        }  
    }
}

运行结果:

补充:FileInputStream类的其它方法:

*      int available();  // 返回流当中的剩余的没有读到的字节数量
*      long skip(long n); // 跳过几个字节不读
//-------------------------------------------------------------------------------
 FileInputStream fis = null;
        fis = new FileInputStream("tempfile");
        System.out.println("总字节数量:"+fis.available());
         fis.skip(3);
        System.out.println(fis.read());
FIleOutputStream

文件字节输出流,负责将数据写出,从内存到硬盘。

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

        try{
            FileOutputStream fos = null;
            // myfile文件不存在的时候会自动新建!
            // 不清空原文件的方式写入  则选择以追加的方式写入  不会清空原文件内容
            fos = new FileOutputStream("E:\\Demo.txt",true); // true表示追加
            // 开始写
            byte[] bytes = {97,98,99,100};//a b c d ,输出转换成字母
            // 将byte数组全部写出
            fos.write(bytes); // abcd
            // 将byte数组的一部分写出 输出2个字节=>ab
            fos.write(bytes,0,2); //ab
            // 以上两种方式都是将原文件清空之后再写入的(谨慎使用)
            // 写完之后,一定要刷新
            String s = "我是一个中国人,我骄傲";
            // 将字符串转换为byte数组
            byte[] bytes1 = s.getBytes();
            fos.write(bytes1);
            fos.flush();
        }catch (IOException e){
            System.out.println(e);
        }
    }
}

输出结果:

文件的复制

文件的拷贝,是先从硬盘中读取到内存里面,再通过内存写入硬盘从而完成文件的复制。使用FileInputStream + FileOutputStream 完成文件的拷贝拷贝的过程应该一边读,一边写。 文件的类型随意,万能的,什么样的文件都能拷贝。(因为是一个个字节的读写,io操作频繁,所以效率相对较低)

public class FileCopyTest {
    public static void main(String[] args) {
        try {
            FileInputStream fis = null;
            FileOutputStream fos = null;
            // 创建一个输入流对象
            fis = new FileInputStream("E://mydemo.txt");
            // 创建一个输出流对象
            fos = new FileOutputStream("D://myfile2.txt");
            // 最核心的: 一边读,一边写(1024个字节是1kb)
            byte[] bytes = new byte[1024 * 1024]; // 一次拷贝1M
            int readCounts = 0;
            while((readCounts = fis.read(bytes)) != -1){
                fos.write(bytes,0,readCounts);
            }
            // 刷新,输出流最后要刷新
            fos.flush();
            fis.close();
            fos.close();
        }catch (IOException e){
            System.out.println(e);
        }
    }
}

fileReader+fileWriter也可以用复制文件:

public class FileCopyTest {
    public static void main(String[] args) {
        try {
            FileReader fileReader = null;
            FileWriter fileWriter = null;
            // 创建一个输入流
            fileReader = new FileReader("myfile.txt");
            // 创建一个输出流(没有文件会先自己创建)
            fileWriter = new FileWriter("myfile2.txt");
            char[] chars = new char[1024*1024];
            int readCounts = 0;
            while((readCounts = fileReader.read(chars))!=-1){
                fileWriter.write(chars,0,readCounts);
            }
            fileWriter.flush();
            fileReader.close();
            fileWriter.close();
            
        }catch (IOException e){
            System.out.println(e);
        }
    }
}

FileReader用法

/*
FileReader:
    读取文本内容时,比较方便,快捷。
    一次读取一个字符。
 */
public class FileReaderTest {
    public static void main(String[] args) {
        FileReader reader=null;
        try {
            //创建文件字符输入流
            reader=new FileReader("text02.txt");
            //开始读
            char[] chars=new char[4]; //一次读取4个字符(1个字符2个字节)
            int readCount=0;
            while((readCount=reader.read(chars))!=-1)
            {
                System.out.print(new String(chars,0,readCount));
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}    

Reader/Writer复制普通文本

package com.jmpower.javase.io;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class Copy02 {
    public static void main(String[] args) {
        FileReader in=null;
        FileWriter out=null;
        try {
            //读
            in=new FileReader("src/com/jmpower/javase/io/FileInputStreamTest02.java");
            //写
            out=new FileWriter("reader");

            //一边读一边写
            char[] chars=new char[1024*512];//1MB
            int readCount=0;
            while((readCount=in.read(chars))!=-1)
            {
                out.write(new String(chars,0,readCount));
            }

            //刷新
            out.flush();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            //关闭流
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: JavaIO流操作基本流程如下: 1. 创建流对象:通过File类或其他相关类创建输入流或输出流对象。 2. 打开流:使用输入流或输出流对象的open()方法打开流,这样就可以读取或写入数据。 3. 读取或写入数据:使用输入流或输出流对象的read()或write()方法读取或写入数据。 4. 关闭流:使用输入流或输出流对象的close()方法关闭流,释放资源。 需要注意的是,在使用IO流操作时,要遵循“先打开、后关闭”的原则,以确保数据的完整性和流的正确性。同时,在操作过程也需要进行异常处理,以避免出现不必要的错误。 ### 回答2: JavaIO流基本操作流程如下: 1. 打开文件或者建立网络连接:使用File类或者URL类打开文件或者建立网络连接。 2. 创建流对象:根据需要选择输入流(读取数据)或输出流(写入数据),并创建相应的流对象。常见的输入流有FileInputStream、BufferedReader等,常见的输出流有FileOutputStream、BufferedWriter等。 3. 读取或写入数据:使用流对象读取或写入数据。对于输入流,可以通过调用相关方法(如read()、readline()等)逐个字符或逐行读取数据;对于输出流,可以通过调用相应方法(如write()、print()等)逐个字符或逐行写入数据。 4. 关闭流:读取或写入完成后,需要关闭文件或网络连接,以释放资源。可以调用流对象的close()方法来关闭流。 需要注意的是,在处理IO流时,应该始终使用try-catch-finally块,以确保在发生异常时能够正确关闭流。可以把IO操作放在try块,catch块用于捕获异常,并在finally块关闭流。 另外,为了提高IO效率,可以考虑使用缓冲流来进行读写操作。缓冲流(BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter)可以通过缓冲区将数据从源读入到缓冲区,再从缓冲区写入到目标,提高读写的速度。 以上就是JavaIO流基本操作的流程。根据实际需要选择合适的流对象,并遵循打开、读取/写入、关闭的流程,可以实现灵活、高效的IO操作。 ### 回答3: 在JavaIO流是用于处理输入输出操作的工具。下面是JavaIO流的基本操作流程: 1. 创建流对象:通过使用Java的InputStream和OutputStream类来创建流对象。InputStream类用于读取输入流,而OutputStream类用于写入输出流。 2. 打开流:通过使用流对象对应的构造函数和方法来打开输入和输出流。根据具体情况,可以选择文件流、网络流或内存流来打开流。 3. 读取/写入数据:使用流对象提供的读取和写入方法来读取和写入数据。例如,使用InputStream的`int read()`方法来读取一个字节的数据,使用OutputStream的`void write(int b)`方法来写入一个字节的数据。 4. 关闭流:在读取或写入结束后,必须关闭流以释放相关资源。通过调用流对象的`close()`方法来关闭流。 需要注意的是,在处理异常的时候,我们需要对可能出现的`IOException`进行处理。可以使用try-catch语句块来捕获和处理异常。 流程示例: ```java import java.io.*; public class IOExample { public static void main(String[] args) { try { // 1. 创建流对象 FileInputStream fis = new FileInputStream("input.txt"); FileOutputStream fos = new FileOutputStream("output.txt"); // 2. 打开流 // 3. 读取/写入数据 int data; while ((data = fis.read()) != -1) { fos.write(data); } // 4. 关闭流 fis.close(); fos.close(); } catch(IOException e) { e.printStackTrace(); } } } ``` 上述示例,我们创建了一个用于将一个文件的内容拷贝到另一个文件的程序。首先,我们创建了一个FileInputStream对象来读取输入文件的内容,然后创建了一个FileOutputStream对象来写入输出文件。接下来,我们通过循环从输入流读取一个字节的数据,并将其写入到输出流,直到读取完所有的数据。最后,我们关闭了流对象来释放资源。 这就是JavaIO流的基本操作流程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值