Java-IO流

1 篇文章 0 订阅

前言:

Java 的 I/O 大概可以分成以下几类进行学习:

  • 磁盘操作:File
  • 字节操作:InputStream 和 OutputStream
  • 字符操作:Reader 和 Writer
  • 对象操作:Serializable
  • 网络操作:Socket

一.IO流的基本概念

IO:Java对数据的操作是通过流的方式,IO流用来处理设备之间的数据传输,上传文件和下载文件,Java用于操作流的对象都在IO包中。

二.IO流的三种分类方式

1.按流的方向分为:输入流和输出流

  • 输入流: 只能从中读取数据,而不能向其写入数据。
  • 输出流:只能向其写入数据,而不能向其读取数据。

或者说:此输入、输出是相对于我们写的代码程序而言:

  • 输入流:从别的地方(本地文件,网络上的资源等)获取资源 输入到 我们的程序中。
  • 输出流:从我们的程序中 输出到 别的地方(本地文件), 将一个字符串保存到本地文件中,就需要使用输出流。

2.按流的数据单位不同分为:字节流和字符流
1个字符 = 2个字节 、 1个字节(byte) = 8位(bit) 、1个字符=16位(bit)

  • 字节流和字符流的用法几乎完全一样,区别在于字节流和字符流所操作的数据单元不同,字节流是8位的字节,字符流操作的是16位的字符。
  • 字符流的由来: Java中字符是采用Unicode标准,一个字符是16位,即一个字符使用两个字节来表示。为此,JAVA中引入了处理字符的流。因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。

3.按流的功能不同分为:节点流和处理流

  • 节点流: 可以从/向一个特定的IO设备(如磁盘,网络)读/写数据的流,称为节点流。节点流也被称为低级流。当使用节点流进行输入和输出时,程序直接连接到实际的数据源,和实际的输入/输出节点连接。 如FileInputStream
  • 处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。总的来说,处理流则用于对一个已存在的流进行连接和封装,通过封装后的流来实现数据的读/写功能。处理流也被称为高级流。

小总结:Java的处理流体现了Java对输入流和输出流设计的灵活性。处理流的功能主要体现在以下两个方面:(1)性能的提高:主要以增加缓冲区的方式来提高输入和输出的效率。(2)操作的便捷:处理流可能提供了一系列便捷的方法来一次输入和输出大批量的内容。(3) 处理流可以“嫁接”在任何已存在的流的基础之上。

三.常用IO流

在这里插入图片描述

四.IO常用的五类一接口

在整个Java.io包中最重要的就是5个类和一个接口。5个类指的是File、OutputStream、InputStream、Writer、Reader;一个接口指的是Serializable

主要的类如下:

 1. File(文件操作与管理):File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹。 File类保存文件和文件夹的各种数据信息,包括文件名、文件长度、最后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前文件夹中的文件列表,创建、删除文件和文件夹等方法。  

 2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。

 3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作,是所有输出流的父类。定义了所有输出流都具有的共同特征。

 4. Reader(文件格式操作):抽象类,基于字符的输入操作。

 5. Writer(文件格式操作):抽象类,基于字符的输出操作。

 6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object类。它的功能丰富,可以从文件的任意位置进行存取(即输入/输出)操作。

五.流的选择与使用(在开发中正确使用IO流)

1、首先要知道是选择输入流还是输出流,这就要根据自己的实际情况而定,如果你想从程序写东西到别的地方,那么就选择输出流,反之输入流。

2、然后考虑你传输数据时,是选择使用字节流传输还是字符流传输。也就是每次传1个字节还是2个字节,有中文肯定就选择字符流。

3、前面两步就可以选出一个合适的节点流,比如字节输入流InputStream,如果要在此基础上增强功能,那么就在处理流中选择一个合适的即可。
        
注: 使用java的io流执行输出时,不要忘记关闭输出流。关闭输出流除了可以保证流的物理资源被回收之外,还可以将输出流缓冲区中的数据flush到物理节点中去(因为在执行close()方法之前,自动执行输出流的flush()方法)。


总之要把握以下原则:
(1)如果是操作二进制文件那我们就使用字节流,如果操作的是文本文件那我们就使用字符流。
(2)尽可能的多使用处理流,这会使我们的代码更加灵活,复用性更好。

六.字节流和字符流的使用范围

  • 字节流一般用来处理图像,视频,以及PPT,Word类型的文件。
  • 字符流一般用于处理纯文本类型的文件,如TXT文件等。
  • 字节流可以用来处理纯文本文件,但是字符流不能用于处理图像视频等非文本类型的文件。

七.字节流和字符流的转换

1.转换流的作用:
文本文件在硬盘中以字节流的形式存储时,通过InputStreamReader读取后转化为字符流给程序处理,程序处理的字符流通过OutputStreamWriter转换为字节流保存输出。

2.转换流的特点:
它是字符流和字节流之间的桥梁;可对读取到的字节数据经过指定编码转换成字符;可对读取到的字符数据经过指定编码转换成字节

3.何时使用转换流?
当字节和字符之间有转换动作时;流操作的数据需要编码或解码时。

4.具体的对象体现:
InputStreamReader(InputStream in):将字节流以字符流形式输入
OutputStreamWriter(OutStreamout):将字符流以字节流形式输出
这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

八.System类对IO的支持

针对一些频繁的设备交互,Java语言系统预定了3个可以直接使用的流对象,分别是:

· System.in(标准输入):通常代表键盘输入。

· System.out(标准输出):通常往显示器输出。

· System.err(标准错误输出):通常往显示器输出。

九.Scanner类

Java 5添加了java.util.Scanner类,这是一个用于扫描输入文本的新的实用程序。Scanner类可以任意地对字符串和基本类型(如int和double)的数据进行分析。借助于Scanner,可以针对任何要处理的文本内容编写自定义的语法分析器。

Scanner套接字节流或字符流:
(1)字节流的套接:在Scanner的构造方法中Scanner(InputStream source),InputStream只要经过适当的套接,总能获得你想要的流接口。

(2)字符流的套接:Scanner(Readable source)

十.总结

InputStream类的功能不足被Scanner解决了

OutputStream类的功能不足被PrintStream解决了

Reader类的功能不足被BufferReader解决了

Writer类的功能不足被PrintWriter解决了

十一.相关代码演示

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class IODemo {
    /**从字节流中获得字符数据:
     * 1. 直接通过字节方式读,然后程序进行字符编码(buffer 大小 < 数据长度/精确控制字符都比较麻烦)
     * 2. 把 Stream 转化为 Reader,进行字符形式读取
     *      2.1 直接读
     *      2.2 BufferedReader      readLine
     * 3. Scanner 也可以
     */
    private static String 从字节流中获得字符数据(InputStream is) throws IOException {

        byte[] buffer=new byte[1024];
        int len=is.read(buffer);
        String message=new String(buffer,0,len,"UTF-8");
        return message;


        /* 第二种:
        Reader reader=new InputStreamReader(is,"UTF-8"); //这里已经转换为字符流了
        char[] buffer=new char[13];
        int len=reader.read(buffer);
        String message=new String(buffer,0,len);
        return message;
               返回的这个message的长度:
                   (1)若缓冲区大小小于文件的长度,那么就读缓冲区大小的字符流
                   (2)若缓冲区大小大于文件的长度,那么就读取文件的大小的字符流
                   (3)字符流包括\r\n,算两个字符
        */

        /* 第三种:
        Scanner sc=new Scanner(is,"UTF-8");
        return sc.nextLine();
        */

        /* 第四种:
        StringBuilder sb=new StringBuilder();
        Reader reader=new InputStreamReader(is,"UTF-8");  //将字节流转换为字符流
             //Reader里面没有readLine()方法
        int len;
        char[] buffer=new char[10];
        while((len=reader.read(buffer))!=-1){
            sb.append(buffer,0,len);
        }
        return sb.toString();
        */

        /* 第五种:
        StringBuilder sb=new StringBuilder();
        Reader reader=new InputStreamReader(is,"UTF-8");
        BufferedReader bufferedReader=new BufferedReader(reader);
              //BufferedReader里面有readLine()方法
        String line;
        while((line=bufferedReader.readLine())!=null){
            sb.append(line+"\r\n");
        }
        return sb.toString();
        */

    }

    /*获取一个输入流():
     *      1. 可以从文件中读(获取输入流)
     *      2. 可以从网络中读(获取输入流)
     *      3. 可以从内存中读(内存中的一段空间当成输入流)
     *      4. 可以从标准输入读(System.in)
     */
    private static InputStream 获取一个输入流() throws IOException {
        /* 第一种:(从本地文件获取输入流)
        InputStream inputStream;
        inputStream=new FileInputStream("本地文件.txt");
        return inputStream;
        */

        /* 第二种:(从缓冲区获得输入流)
        InputStream inputStream;
        byte[] bytes="我是第一行\r\n我是第二行\r\n".getBytes("UTF-8");
        inputStream=new ByteArrayInputStream(bytes);
        return inputStream;
        */

        /* 第三种:(从键盘获得输入流)
        InputStream inputStream;
        inputStream=System.in;   //从键盘输入数据
        return inputStream;
        */

        Socket cilentSocket=new Socket("www.baidu.com",80);

        OutputStream os=cilentSocket.getOutputStream();
        Writer writer=new OutputStreamWriter(os,"UTF-8");
        PrintWriter out=new PrintWriter(os,false);

        out.println("GET / HTTP/1.0\r\n\r\n");
        out.flush();

        InputStream is=cilentSocket.getInputStream();
        return is;
    }

    private static OutputStream 获取一个输出流() throws IOException{
        OutputStream os=new FileOutputStream("本地输出文件.txt");
        return os;
    }

    private static void 输出一段字符(OutputStream os, String message) throws IOException{
        /* 第一种:
        Writer writer=new OutputStreamWriter(os,"UTF-8");
        PrintWriter out=new PrintWriter(writer,false);
        out.println(message);
        out.flush();
        */

        /* 第二种:
        byte[] bytes=message.getBytes("UTF-8");
        os.write(bytes);
        */

        Writer writer=new OutputStreamWriter(os,"UTF-8");
        writer.append(message);
        writer.flush();
    }
    public static void main(String[] args) throws IOException {
        /*
        InputStream is=获取一个输入流();
        String message=从字节流中获得字符数据(is);
        System.out.println(message);
        */

        OutputStream os=获取一个输出流();
        输出一段字符(os,"我是中国人\r\n最喜欢过年了\r\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值