Java IO流系列② — 流的分类与节点流

导读:本篇文章讲解 Java IO流系列② — 流的分类与节点流,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

也许你感觉自己的努力总是徒劳无功,但不必怀疑,你每天都离顶点更进一步。今天的你离顶点还遥遥无期。但你通过今天的努力,积蓄了明天勇攀高峰的力量。加油!

IO流原理

I/O是Input/Output的缩写, I/O技术是非常实用的技术,用于处理设备之间的数据传输。如读/写文件,网络通讯等。
io流示意图
Java程序中,对于数据的输入/输出操作以“流(stream)” 的方式进行。
java.io包下提供了各种“流”类和接口,用以获取不同种类的数据,并通过标准的方法输入或输出数据。

流的分类

  • 按操作数据单位不同分为:字节流(8 bit),字符流(16 bit)
  • 按数据流的流向不同分为:输入流,输出流
  • 按流的角色的不同分为:节点流,处理流(也就是节点流外面包着的那层流)

io流2
这所有的流均有四个抽象的基类:(按照两种分法)

(抽象基类) 字节流 字符流
输入流 InputStream Reader
输出流 OutputStream Writer

io流3

节点流和处理流

节点流:直接从数据源或目的地读写数据
节点流
处理流:不直接连接到数据源或目的地,而是“连接”在已存在的流(节点流或处理流)之上,通过对数据的处理为程序提供更为强大的读写功能。
数据流

节点流(或文件流)

使用FileReader读入数据的基本操作(方式一:适合小数量的读入)

步骤

  • 1.实例化File类的对象,指明要操作的文件
  • 2.提供具体的流(也就是流的实例化)
  • 3.数据的读入
  • 4.流的关闭操作

三个注意点

  • read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
  • 异常的处理:为了保证流资源一定可以执行关闭操作。需要使用try-catch-finally处理
  • 读入的文件一定要存在,否则就会报FileNotFoundException。

主要方法
int read()
读取单个字符。作为整数读取的字符,范围在 0 到 65535 之间 (0x00-0xffff)(2个字节的Unicode码),如果已到达流的末尾,则返回 -1

代码实现:

@Test
    public void testFileReader(){
        FileReader fr = null;
        try {
            //1.实例化File类的对象,指明要操作的文件
            File file = new File("hello.txt");//相较于当前Module
            //2.提供具体的流
            fr = new FileReader(file);
            //3.数据的读入
            //read():返回读入的一个字符。如果达到文件末尾,返回-1
        
            int data;
            while((data = fr.read()) != -1){
                System.out.print((char)data);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.流的关闭操作
              try {
                  if(fr != null)fr.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
        }

    }

前三个步骤均在try中,最后一个在try中加入一个判断语句(if(fr != null))是因为有可能在读文件的时候就报异常,从而这个流的对象没有成功的创建出来,如果是这样的话那么close()方法也就无从说起了。

使用FileReader读入数据的基本操作(方式二:使用read的重载方法)

主要方法
int read(byte[] b)
将字符读入数组。如果已到达流的末尾,则返回 -1。否则返回本次读取的字符数。

代码实现:

//对read()操作升级:使用read的重载方法
    @Test
    public void testFileReader1()  {
        FileReader fr = null;
        try {
            //1.File类的实例化
            File file = new File("hello.txt");

            //2.FileReader流的实例化
            fr = new FileReader(file);

            //3.读入的操作
            //read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1
            char[] cbuf = new char[5];
            int len;
            while((len = fr.read(cbuf)) != -1){
                // 方式一:
                  for(int i = 0;i < len;i++){
                      System.out.print(cbuf[i]);
                  }
                // 方法二:
                String str = new String(cbuf,0,len);
                System.out.print(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fr != null){
                //4.资源的关闭
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }
        }

    }

注意:不管是方式一中的for循环还是方法二中的将char型数组转化为字符串,他的读取长度都不能为char型数组的长度,而应该是实际读取的字节数(也就是read的返回值len),否则当读入的内容填充不满一个数组时,打印出来的结果会发生错误。

使用FileWriter写出数据的操作

主要方法
主要方法

说明:
1. 输出操作,对应的File可以不存在的。并不会报异常
2.  File对应的硬盘中的文件如果不存在,在输出的过程中,会自动创建此文件。
     File对应的硬盘中的文件如果存在:
            如果流使用的构造器是:FileWriter(file,false) / FileWriter(file):对原有文件的覆盖
            如果流使用的构造器是:FileWriter(file,true):不会对原有文件覆盖,而是在原有文件基础上追加内容

代码实现:

@Test
    public void testFileWriter() {
        FileWriter fw = null;
        try {
            //1.提供File类的对象,指明写出到的文件
            File file = new File("hello1.txt");

            //2.提供FileWriter的对象,用于数据的写出
            fw = new FileWriter(file,false);

            //3.写出的操作
            fw.write("I have a dream!\n");
            fw.write("you need to have a dream!");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.流资源的关闭
            if(fw != null){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

使用FileReader和FileWriter实现文本文件的复制

代码实现:

 @Test
    public void testFileReaderFileWriter() {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            //1.创建File类的对象,指明读入和写出的文件
            File srcFile = new File("hello.txt");
            File destFile = new File("hello2.txt");

            //2.创建输入流和输出流的对象
            fr = new FileReader(srcFile);
            fw = new FileWriter(destFile);

            //3.数据的读入和写出操作
            char[] cbuf = new char[5];
            int len;//记录每次读入到cbuf数组中的字符的个数
            while((len = fr.read(cbuf)) != -1){
                //每次写出len个字符
                fw.write(cbuf,0,len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //4.关闭流资源
            //方式一:
//            try {
//                if(fw != null)
//                    fw.close();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }finally{
//                try {
//                    if(fr != null)
//                        fr.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
            //方式二:
            try {
                if(fw != null)
                    fw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

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

使用FileInputStream和FileOutputStream读写非文本文件

代码实现:

/*
    实现对图片的复制操作
     */
    @Test
    public void testFileInputOutputStream()  {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
      
            File srcFile = new File("爱情与友情.jpg");
            File destFile = new File("爱情与友情2.jpg");

            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);

            //复制的过程
            byte[] buffer = new byte[5];
            int len;
            while((len = fis.read(buffer)) != -1){
                fos.write(buffer,0,len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null){
                //
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

指定路径下文件的复制(通用方法)

public void copyFile(String srcPath,String destPath){
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //
            File srcFile = new File(srcPath);
            File destFile = new File(destPath);

            //
            fis = new FileInputStream(srcFile);
            fos = new FileOutputStream(destFile);

            //复制的过程
            byte[] buffer = new byte[1024];
            int len;
            while((len = fis.read(buffer)) != -1){
                fos.write(buffer,0,len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(fos != null){
                //
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fis != null){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

一个小注意点

在创建路径的时候,有两种情况:

  • main()方法中
  • 单元测试中(@Test)

如果你是在main方法中创建路径(相对路径),他是以整个工程为基础。而如果是在单元测试中,则它是以这个module为基础。

定义文件路径时,注意:可以用“/”或者“\”。

总结

  • 对于文本文件(.txt,.java,.c,.cpp),使用字符流处理
  • 对于非文本文件(.jpg,.mp3,.mp4,.avi,.doc,.ppt,…),使用字节流处理
  • 字节流可以处理文本文件或非文本文件的复制,但不能读取或写入文本文件。

那么同理:能不能用字符流去复制非文本文件呢?

可以复制,但是复制完以后,不能保证图片还能正常显示!
因为字符流是读取字节后,缓存,然后去码表查找匹配,若是匹配不到就会到位置码表位置寻找类似的,此时返回的数据就可能不正确。因此生成的新图片的编码和老图片的编码是不一致的,从而导致图片不能正常显示。
所以不要用字符流拷贝媒体文件。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/122324.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!