Java基础知识——6、输入输出流

6 输入输出流

6.1 Java IO 流实现机制

在Java语言中,输入输出流都被称为抽象的流,流可以被看作一组有序的字节集合,即数据在两设备之间的传输。
流的本质是数据传输,根据处理数据类型的不同,六可以分为两大类:字节流 和 字符流。

字节流以字节(8bit)为单位,分为两大抽象类:输入流(InputStrem) 和 输出流(OutputStrem)。
字符流以字符(16bit)为单位,分为两大抽象类:输入流(Reader) 和 输出流(Writer)。
在这里插入图片描述
字节流与字符流的区别:
字节流:在处理输入输出时不会用到缓存。
字符流:在处理输入输出时会用到缓存。


6.2 管理文件和目录的类

Java语言提供了一个 File 类来管理文件和文件夹,通过该类能够查看目录的或文件的属性,还可以进行文件或目录的增删改查操作。

File 类的常用方法:

方法作用
File(String pathname)根据指定的路径创建一个File对象
createNewFile()若目录或文件存在则返回false,否则就创建文件或文件夹
delete()删除文件或文件夹
isFile()判断这个对象表示的是否是一个文件
idDirectory判断这个对象表示的是否是一个文件夹
listFile若对象代表目录,则返回目录中所有文件的File对象
mkdir根据当前对象指定的路径创建目录
exists判断对象对应的文件是否存在

例:

import java.io.File;

public class Main {
    public static void main(String[] args) {
        File file = new File("D:\\home");

        //判断目录是否存在
        if (file.exists()) {
            System.out.println("目录存在");
        } else {
            System.out.println("目录不存在");
        }

        File[] fileList = file.listFiles();
        for (int i = 0; i < fileList.length; i++) {
            //判断是否为目录
            if (fileList[i].isDirectory()) {
                System.out.println("目录是:" + fileList[i].getName());
            }
        }
    }
}

结果:
目录存在
目录是:delta


6.3 Java Socket 是什么

网络上的两个程序通过一个双向的通信连接实现数据交换,这个双向链路的一端为一个Socket。Socket 也成称为套接字,可以用来实现不通虚拟机或不同计算机之间的通信。
在Java中Socket 可以分为两种类型:面向连接的 Socket 通信协议(TCP) 与 面向无连接的 Socket 通信协议(UDP),任何一个Socket都是由IP地址和端口号唯一确定的。

基于TCP通信过程:
Server(服务器)端 Listen(监听)指定的某个端口(建议使用大于1024的端口)是否有请求➡Client(用户端)向 Server(服务器)端发出 Connect(链接)请求➡ Server(服务器)端向 Client(用户端)发回 Accept(接受)消息。
一个链接基于这三个步骤就建立起来了,会话随即产生。

Socket 生命周期的三个阶段:
打开 Socket ➡使用 Socket 收发数据➡关闭 Socket。
在Java语言中可以使用 ServerSocket 来作为服务器端,Socket作为客户端来实现网络通信。

例:用 Socket 来实现客户端和服务器端通信

import java.io.*;
import java.net.*;

public class Main {
    public static void main(String[] args) {
        BufferedReader br = null;
        PrintWriter pw = null;
        try {
            ServerSocket server = new ServerSocket(2000);
            Socket socket = server.accept();

            //获取输入流
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            //获取输出流
            pw = new PrintWriter(socket.getOutputStream(), true);

            //获取接收数据
            String s = br.readLine();

            //发送相同的数据给客户端
            pw.println(s);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                br.close();
                pw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

其次创建一个客户端程序:

import java.io.*;
import java.net.*;

public class Main {
    public static void main(String[] args) {
        BufferedReader br = null;
        PrintWriter pw = null;
        try {
            Socket socket = new Socket("localhost", 2000);

            //获取输入流
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));

            //获取输出流
            pw = new PrintWriter(socket.getOutputStream(), true);

            //向服务器发送数据
            pw.println("hello");

            String s = null;

            while (true) {
                s = br.readLine();
                if (s != null)
                    break;
            }
            System.out.println(s);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                br.close();
                pw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

最后启动服务器端程序,然后运行客户付按程序,客户端会把从服务器端转发过来的 “hello” 打印出来。


6.4 Java NIO

在非阻塞IO出现之前,Java是通过传统的 Scoket 来实现基本的网络通信功能的。

如果客户端还没有对服务器发起连接请求,那么 accept 就会阻塞。如果连接成功,但是数据还没准备好,对 read 的调用也会阻塞。当要处理多个连接时就需要采用多线程的方式,由于每个线程都拥有自己的栈空间,而且由于阻塞会导致大量线程进行上下文切换,使得程序运行效率低下,因此引入了NIO来解决这个问题。

NIO通过Selector、Channel 和 Buffer 来实现非阻塞IO操作。

具体原理请点击➡疯狂创客圈 - 博客园(不往下写是因为本人也没搞懂。。。)


6.5 Java 序列化

Java提供了两种对象持久化方式:序列化 与 外部序列化。

序列化
在分布式环境下,当进行远程通信时,无论是何种数据类型,都会以二进制序列的形式在网络上传送。序列化可以将对象以一连串的字节描述的过程,用于解决对对象流进行读写 操作时所引发的问题。序列化可以将对象的状态写入流里进行网络传输,或者保存到文件、数据库等系统里,并在需要的时候把流读取出来重新构造一个相同对象。

实现序列化的类都必须要实现 Serializable 接口,Serializable 接口位于 java.lang 包中,它里面没有任何方法。使用一个输出流来构造一个对象流对象,然后使用该对象的 writeObject方法就可以将OBJ对象写出。

序列化的两个特点:
1)如果一个类能被序列化,那么它的子类也能够被序列化
2)由于static 代表类的成员,transient 代表对象的临时数据,因此声明为这两种类型的数据成员不能被序列化

序列化使用会影响系统性能,需要在特定的情况下使用序列化:
1)需要通过网络来发送对象,或者对象的状态需要被持久化到数据库或者文件中。
2)序列化能实现深复制,即可以复制引用对象。

与序列化相对的是反序列化,它将流转换为对象。在序列化与反序列化过程中,seriVersionUID 有着非常重要的作用,每个类都有特定的seriVersionUID ,在反序列化中通过 seriVersionUID 来判断类的兼容性。如果待序列化的对象与目标对象的 seriVersionUID 不同就会抛出InvalidClassException 异常。作为一个好的编程习惯,最好在被序列化的类中显式的声明 seriVersionUID (该字段必须被声明为 static final)。

自定义 seriVersionUID 主要有三个优点:
1)提高程序的运行效率
2)提高程序不同平台的兼容性
3)增强程序各个版本的可兼容性

外部序列化
外部序列化与序列化主要区别在于内置API,只需要实现Serializable接口,开发人员不需要编写任何代码就可以实现对象的序列化,而使用外部序列化时,Externalizable 接口中的读写方法必须由开发人员来实现。





输入输出流因为本人理解不深,目前也没有时间去学习,所以仅仅更新了最基础的理念,后续会更新的







注:

此文来源于《Java程序员面试笔试宝典》一书

仅作为本人学习过程的记录

填写原创是因为找不到相关链接

如有不妥请联系本人,会立即删除

此书对于我这种小白来说非常有用,讲解详细,知识点全面,目前正在根据此书学习,陆续会记录更多知识点。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值