第五章 Java高级编程 5.1 Java多线程机制 5.2 输入输出流类 5.3 网络编程.

Slides:



Advertisements
Similar presentations
7.1 内置对象概述及分类 JSP 视频教学课程. JSP2.2 目录 1. 内置对象简介 1. 内置对象简介 2. 内置对象分类 2. 内置对象分类 3. 内置对象按功能区分 3. 内置对象按功能区分 4. 内置对象作用范围 4. 内置对象作用范围.
Advertisements

高级服务器设计和实现 1 —— 基础与进阶 余锋
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
讓你的程式具有多工(Multitasking) 及多重處理(Multiprocessing)的能力
第十五章 网络编程.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
輸入輸出 學習目標 瞭解串流與輸入輸出的關係 認識InputStream、OutputStream繼承架構
创意源自激情,技术成就梦想 畅翼创新俱乐部 2012年春俱乐部第三次技术培训 赵程.
目标 运用File类进行文件操作 理解流,标准输入/输出流的概念
实验4 基于Socket的C/S程序开发 实验目的
在PHP和MYSQL中实现完美的中文显示
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
Java语言程序设计 清华大学出版社 第9章 网络通信.
Hadoop I/O By ShiChaojie.
第14章 Java网络编程 Java语言提供了强大的网络编程功能,能够处理各种网络资源以及进行网络通信。java.net包定义了Java语言网络编程的主要工具类。其中,包括代表网络IP地址的InetAddress类;与URL有关的URL类和URLConnection类;与网络通信有关的Socket类和ServerSocket类。本章包括以下知识点。
Java 第28讲:建立删除文件 主讲教师:李焱 讲师.
Java语言程序设计 第七部分 多线程.
Multithread 多執行緒 I/O Lecturer:楊昌樺.
JAVA 编 程 技 术 主编 贾振华 2010年1月.
Java程序设计 第18章 二进制I/O.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第九章 输入/输出流.
西南科技大学网络教育系列课程 高级语程序设计(Java) 第十一章 Java 中的网络编程.
走进编程 程序的顺序结构(二).
辅导课程六.
网络常用常用命令 课件制作人:谢希仁.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
Windows网络操作系统管理 ——Windows Server 2008 R2.
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
第五讲 JSP中的文件操作(1) 教学目的 本讲主要讲述JSP中使用Java输入、输出流实现文件的读写 操作 。 知识要点
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
Java语言程序设计 清华大学出版社 第8章 输入输出流(1).
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
5.3 简单的tcp通讯 信息工程系 向模军 Tel: QQ:
SOA – Experiment 2: Query Classification Web Service
《JAVA程序设计》 语音答疑 辅导老师:高旻.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言程序设计 主讲教师:陆幼利.
5.4 利用tcp实现文件传输 信息工程系 向模军 Tel: QQ:
電子郵件簡介.
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
姚金宇 MIT SCHEME 使用说明 姚金宇
实验七 安全FTP服务器实验 2019/4/28.
计算机网络与网页制作 Chapter 07:Dreamweaver CS5入门
信号量(Semaphore).
2019/5/3 JAVA Socket(UDP).
iSIGHT 基本培训 使用 Excel的栅栏问题
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
本节内容 文件系统 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
Chapter 18 使用GRASP的对象设计示例.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第八章 继承 C++语言程序设计.
GIS基本功能 数据存储 与管理 数据采集 数据处理 与编辑 空间查询 空间查询 GIS能做什么? 与分析 叠加分析 缓冲区分析 网络分析
Python 环境搭建 基于Anaconda和VSCode.
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
WSAAsyncSelect 模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang
阻塞式模型 本节内容 视频提供:昆山爱达人信息技术有限公司 视频录制:yang 官网地址:
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
助教:廖啟盛 JAVA Socket(UDP) 助教:廖啟盛
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第四章 UNIX文件系统.
第十二章 Java网络编程 1.URL编程 2.Socket网络编程 3.Datagram网络编程.
创建、启动和关闭Activity 本讲大纲: 1、创建Activity 2、配置Activity 3、启动和关闭Activity
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
9 输入输出及文件操作.
Presentation transcript:

第五章 Java高级编程 5.1 Java多线程机制 5.2 输入输出流类 5.3 网络编程

5.1 Java多线程机制 Java语言从设计之初,就考虑到对多线程的支持,因而在系统级和语言级均提供了对多线程的支持。 使用多线程的优点就是:当程序中有多个可执行线程时,能够充分利用系统资源,提高程序执行效率。 本小结介绍多线程应用程序的设计方法。

5.1.1基本概念 (一) 1.线程 线程是比进程更小的单位,是应用程序中的一个可执行线索,多线程就是同一个应用程序中有多个可执行线索,它们可以并发执行。 前面介绍的所有例程都是单线程的,即一个应用程序只存在一个可执行线索。在执行过程中,如果某部份代码因为等待某个I/O操作而受阻,则程序的其他部分即使与此无关也不能执行,这样就严重地浪费了CPU资源。多线程机制的提出就是为了解决这个问题。

5.1.1基本概念 (二) 回忆一下多进程并行执行的情况,在CPU上执行的某个进程因为等待某种资源而受阻时,多任务操作系统可以使该进程挂起,而根据某种调度原则启动另外一个不同的进程执行,直到前一进程获得其所需资源,才唤醒该进程,让它继续执行。 这样,在多任务操作系统的调度下,可以让多个进程并行执行,能够较好地利用CPU资源,但仍然难以满足现代应用程序的需要。 例如,需要在同一应用程序中完成声音播放、图像显示、网络文件下载等多项工作,如果使用传统的单线程程序,就只能顺序的逐一实现,而使用多线程方法则可以并发实现。

5.1.1基本概念 (三) 多线程就是同一程序中多个任务的并发实现。它与进程有相似之处,可以动态的生成或销毁等,它们之间的差别主要体现在如下两个方面: 作为基本的执行单元,线程的划分比进程小,因此,支持多线程的系统要比只支持多进程的系统并发程度高。 进程把内存空间作为自己的资源之一,每个进程均有自己的内存单元。线程却共享内存单元,通过共享的内存空间来交换信息,从而有利于提高执行效率。 由于线程划分更小,涉及的资源更少,因而使用更加灵活、方便。

5.1.1基本概念 (四) 2.线程调度与优先级 应用程序中的多个线程能够并发执行,但从系统的内部来看,所有线程仍然是串行的一个一个地执行,那么如何来决定哪一个线程先执行,哪一个线程后执行呢? Java引入了优先级的概念,优先级就是线程获得CPU而执行的优先程度,优先级越高,获得CPU的权力越大,执行的机会越多,执行的时间也越长。

5.1.1基本概念 (五) Java把优先级划分为10级,用1至10的整数表示,数值越大,优先级越高。在创建线程时,可以为线程分配优先级。 在Thread类中定义了三个优先级常量:MIN_PRIORITY, MAX_PRIORITY和NORM_PRIORITY,其值分别为1, 10, 5。 在为线程分配优先级时,其值应该在1至10之间,否则将出错。 如果应用程序没有为线程分配优先级,则Java系统为其赋值为NORM_PRIORITY。

5.1.1基本概念 (六) 调度就是分配CPU资源,确定线程的执行顺序。 Java采用抢占式调度方式,即高优先级线程具有剥夺低优先级线程执行的权力。 如果一个低优先线程正在执行,这时出现一个高优先级线程,那么低优先级线程就只能停止执行,放弃CPU,推回到等待队列中,等待下一轮执行,而让高优先级线程立即执行。 如果线程具有相同的优先级,则按"先来先服务"的原则调度。

5.1.1基本概念 (七) 理解了Java的抢占式调度策略后,在设计程序时,应该让高优先级线程执行一段时间后,能够交出使用权,放弃CPU。 有两个方法可以达到这一目的: 一是调用sleep()方法,暂时进入睡眠状态,从而让出CPU,使有相同优先级线程和低优先级线程有执行的机会。 二是调用yield()而放弃CPU,这时和它有相同优先级的线程就有执行的机会。

5.1.1基本概念 (八) 3.线程的状态与生命周期 每个Java程序都有一个缺省的主线程: 对于Application,主线程是main方法执行的线索; 对于Applet,主线程指挥浏览器加载并执行Java小程序。 要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程。

5.1.1基本概念 (九) 新建线程的生命周期如下: 1.新建: 当一个Thread类或其子类的对象被创建后,进入这个状态。 这时,线程对象已被分配内存空间,其私有数据已被初始化,但该线程还未被调度,可用start()方法调度,或用stop()方法中止。 新生线程一旦被调度,就将切换到可执行状态。

5.1.1基本概念 (十) 2.可运行: 处于可执行环境中,随时可以被调度而执行。它可细分为两个子状态: 3.阻塞: 运行状态,已获得CPU,正在执行; 就绪状态,只等待处理器资源。 这两个子状态的过渡由执行调度器来控制。 3.阻塞: 由某种原因引起线程暂停执行的状态。

5.1.1基本概念 (十一) 4.死亡: 线程执行完毕或另一线程调用stop()方法使其停止时,进入这种停止状态。 它表示线程已退出可运行状态,并且不再进入可运行状态。

5.1.1基本概念 (十二) 阻塞 死亡 可运行 start() suspend() sleep() wait() I/O blocking Stop() resume() slepp time_out notify() I/O finished 新建 new语句

5.1.1基本概念 (十三) 4.线程控制方法 Thread类定义了许多控制线程执行的方法。▼ 程序中经常使用下面的方法,对线程进行控制: start():用于调用run()方法使线程开始执行。 stop(): 立即停止线程执行,其内部状态清零,放弃占用资源。 suspend():暂停线程执行。线程的所有状态和资源保持不变,以后可以通过另一线程调用resume()方法来重新启动这个线程。

5.1.1基本概念 (十四) resume():恢复暂停的线程,安排暂停线程执行。 sleep(): 调整Java执行时间,所需参数是指定线程的睡眠时间,以毫秒为单位。 join():调用线程等待本线程执行结束。 yield():暂停调度线程并将其放在等待队列末尾,等待下一轮执行,使同优先级的 其它线程有机会执行 。

5.1.1基本概念 (十四) isAlive(): 线程处于“新建”状态时,线程调用方法返回false。 当一个线程调用start()方法,并占有CUP资源后,该线程的run方法就开始运行,在线程的run方法结束之前,即没有进入死亡状态之前,线程调用isAlive()方法返回true。 当线程进入“死亡”状态后(实体内存被释放),线程仍可以调用方法isAlive(),这时返回的值是false。

5.1.2多线程实现方法 (一) 创建新线程有两种方法: 无论采用那种途径,程序员可以控制的关键性操作有两个: 生成Thread子类 生成一个类,声明实现Runnable接口 无论采用那种途径,程序员可以控制的关键性操作有两个: 定义用户线程的操作,即定义用户线程的run方法; 在适当时候建立用户线程实例。

5.1.2多线程实现方法 (二) 1.创建Thread类的子类 用这种方法生成新线程,可以按以下步骤进行: 生成Thread类的子类。 在子类中覆盖run()方法。 生成子类的对象,并且调用start()方法启动新线程。

5.1.2多线程实现方法 (三) 这三个步骤可以用Java语言表述为 class NewThread extends Thread { ... public void run() }

5.1.2多线程实现方法 (四) 在需要创建NewThread这个线程的类或方法中,生成NewThread对象。 即 NewThread thread = new NewThread(); thread.start();

5.1.2多线程实现方法 (五) 经过这三步后新线程处于可执行状态。 start()方法将调用run()方法执行线程。 run()方法是Java执行时为了启动线程而调用的第一个用户定义方法,就好象main()是Java执行时为了启动Application程序而调用的第一个用户定义方法一样。 ▼

5.1.2多线程实现方法 (六) 2.实现Runnable接口 使用这种方法创建新线程,要完成以下几步: 程序中某个类声明实现Runnable接口,并且在这个类中实现run()方法。 生成这个类的对象。 用Thread(Runnable target)构造函数生成Thread对象,其中target是声明实现了Runnable接口的对象并且用start()方法启动线程。

5.1.2多线程实现方法 (七) 这三个步骤用Java语言表述为: class NewThreadRun implements Runnable { ... public void run() } ▼

5.1.2多线程实现方法 (八) 用下面的代码创建并执行新线程 NewThreadRun n = new NewThreadRun(); Thread thread = new Thread(n); thread.start(); Runnable是java.long包中的一个接口。任何一个类都可以实现这个接口,从而实现创建和执行线程的功能。实现Runnable接口的类必须覆盖接口中定义的run()方法,它仍然是完成具体任务的地方。

5.1.2多线程实现方法 (九) 以上两种方法都可以创建和执行线程,前一种方法要求一定是Thread类的子类,后一种方法可以不是Thread类的子类,但必须实现Runnable接口,这种方法使用更加灵活。 有时还只能使用后一种方法,如某类已经定义为Applet类的子类,由于Java不允许多重继承,这时不能再定义它为Thread类的子类,此时只有声明其实现Runnable接口来创建和执行新线程。

5.2 输入输出流类(一) 计算机不仅对各类信息具有强大的处理能力,而且还能管理各种外部设备,如键盘、串行口、显示器等,它们都是通过I/O端口与计算机相连。 计算机要对外设进行有效控制,必须编写相应的外设驱动程序,由于I/O设备性质各不相同,且不断更新换代,增加了计算机管理外设的难度

5.2 输入输出流类(二) 为了实现对外设的统一管理,屏蔽不同外设的差异,Java用java.io包实现上层软件与硬件的隔离,引入流的概念,抽象地把产生数据的源和使用数据的目的联系起来。 实际应用时,把流分为输入流和输出流: 输入流连在某个产生数据的设备上,从输入流中读取数据, 输出流连在某个接收数据的设备上,把结果写出到输出流中。

5.2 输入输出流类(三) 流是一种抽象的数据类型,具有长度(元素的个数)、当前位置(任意时刻的唯一存取点)和存取方式(只读、只写或读写)。 用户非常熟悉的一种流是传统的磁盘文件,但是流的概念已经扩展为包括内存中的流、来自于键盘的字符流、送往屏幕的字符流以及出入串行口(或其它设备)的字符流。 流的这些概念绝大多数都来自UNIX系统,即“任何事物都是文件”的思想

结构图 FileInputStream FilterInputStream File PipeInputStream InputStream RandomAccessFile InputStream Writer OutputStream File Reader PipeInputStream ObjectInputStream SequenceInputStream Object FileOutputStream FilterOutputStream ObjectOutputStream PipeOutputStream

5.2.1 File类(一) 操作系统的文件管理是向应用程序提供的最基本服务之一,但在计算机的发展过程中,形成了众多的文件管理系统,它们互不兼容,给用户编程留下了相当大的困难,Java消除了这种不兼容性。 File类能够处理由本地文件系统维护的具体文件,它提供独立于平台的文件处理方法。 File类的构造函数: public File(Sting path) ; public File(Sting path , String name) ; public File(File dir , String name) ;

5.2.1 File类(二) 1.文件路径和属性 。 getPath()方法返回File对象的路径。 getAbsolutePath()方法返回File对象的绝对路径 。 getName()方法返回File对象的文件名或目录名。 与getPath()的含义不同,getName()方法要检查给定字符串中是否含有路径分隔符: 如果包含路径分隔符,则取最后一个分隔符后的字符串作为文件名返回给调用者, 如果不包含路径分隔符,则getName()和getPath()返回相同的字符串。 getParent()返回File对象的父目录。

5.2.1 File类(三) 另外,File类还有几个方法说明文件的属性或状态: exist(),canWrite(),canRead(),isFile(), isDirectory(), isAbsolute() 都返回boolean型数据,分别表示文件是否存在,是否写保护,是否读保护,是文件还是目录,是否使用绝对路径。 Java只能查询上述文件属性,其它属性则不能查询,如隐藏、系统、归档等属性则无法查询。File类的平台独立性,以放弃某些系统的个性为代价。 ▼

5.2.1 File类(四) 2.创建目录和删除文件 mkdir()和mkdirs()用于创建目录。创建目录的位置完全取决于File对象的路径。 delete()用于删除文件或目录,删除目录时,应该保证所删目录是一个空目录,否则删除操作失败。 ▼ 3.文件更名 renameTo()方法不但可以给文件更名,而且可以给目录更名。 equals()判断两个File对象是否相等,程序用它来判断用户给定的原文件名和新文件名是否相等,如果相等则不能进行更名操作。 ▼

5.2.1 File类(五) 4.目录清单 list()方法产生目录清单,它只返回指定目录中包含的文件名或子目录名,没有文件长度、修改时间、文件属性等信息。 lastModified()返回文件最后一次被修改的时间,其值是相对于1970年1月1日的时间毫秒数,为了便于阅读,必须变成java.util.Date对象。 说明: File类不允许访问文件内容,即读写文件;也不能改变文件的属性。 ▼

5.2.2 RandomAccessFile类(一) 在java.io包中RandomAccessFile类和输入输出流类具有读写文件的功能。 RandomAccessFile类只能进行文件的输入输出,而流类功能更加强大,它可以进行包括文件的一切输入输出操作。 RandomAccessFile类的定义如下: ▼

5.2.2 RandomAccessFile类(二) 它提供了两个构造函数: public RandomAccessFile(String name, String mode) throws IOException; public RandomAccessFile(File file, String mode) throws IOException; 其使用参数的含义是: name 是一个String对象,表示被访问的文件名。 file 是一个File对象,表示被访问的文件名,用这种方式提供文件名,应用程序独立于平台。 mode 用字符串表示被访问文件的读写模式:"r"表示文件以只读方式打开,"rw"表示文件以读写方式打开。

5.2.2 RandomAccessFile类(三) 如果该文件不存在,则创建该文件,供程序进行读写操作; 如果该文件已经存在,则以覆盖方式(不是改写方式)把输出数据写入到文件中,原文件中没有被覆盖的部分,仍然保留在文件之中。 在RandomAccessFile类中没有专门打开文件的方法,在生成RandomAccessFile对象时,文件即被打开,可供程序访问,这时文件读写指针为0,即读写位于文件的开头。

5.2.2 RandomAccessFile类(四) RadomAccessFile类实现了DataInput和DataOutput两个接口,这两个接口分别定义了读入和写出的方法。 DataInput和DataOutput中定义的方法基本上是相对应的,即在DataInput中定义了一个读入数据的方法,则在DataOutput中就有一个结构相似的写出方法。 但DataInput接口多出几个与写出操作无关的方法: skipBytes() 在输入流中跳过n个字节 readUnsignedByte() 读入一个无符号字节数据 readLine() 读入一行字符。有四种行结束符:回车符'\r',新行符'\n',回车符后紧跟新行符,或者文件结束。读入的一行字符中包含行结束符。

5.2.2 RandomAccessFile类(五) 由于读入和写出方法的含义相似,因此我们用写出方法来说明不同格式的含义。 有的写出方法带有不同的后缀,分别为Byte, Short,Int,Long, Float,Double, Char,Boolean,这些方法表示写出Java基本数据类型的数据,如writeInt()表示写出一个int型整数。 对于用这些方法写出的数据,应该用带有相同后缀的读入方法来读取数据,否则可能出错。 这些方法中writeBoolean()比较特殊,写出数据时用0表示false,用1表示true; 而用readBoolean()读入数据时,如果是0,则返回false,非0返回true。

5.2.2 RandomAccessFile类(六) 有三个方法与字符串的写出有关,它们是: writeBytes() 写出字符串时,每个字符占一个字节,即8位。 writeChars() 在支持Unicode码的机器上写出字符串,每个字符占2个字节,即16位。 writeUTF() 以8位编码的方式写出字符串。 其中的前两个字节,表示以后将要写出数据的字节总数,其值由系统统计。从第三个字节开始写出字符串数据,每个字符占一个字节。 例如:writeUTF("abc"),则其结果用十六进制表示为:00h,03h, 61h, 62h, 63h,共写出5个字节,前两个字节的值表示其后还将写出3个字节。

5.2.2 RandomAccessFile类(七) 另外有三个不带任何后缀的写出方法,都是按字节写数据。 write(int b); write(byte b[]); write(byte b[], int off, int len); 其参数的含义为: b 一个字节数据或字节数组。 off 表示从数组中第几个字节开始写出数据。 len 表示写出字节的总数。 ▼

5.2.2 RandomAccessFile类(八) seek() 支持随机访问文件,它通过移动文件的读写指针实现文件的随机读写。其参数表示读写指针相对于文件起始位置的偏移量。 getFilePoint() 返回当前文件指针的位置。 close() 关闭文件和释放与打开文件有关的资源。在使用完文件或使用中出现异常后,都应该关闭文件。在处理异常的try-catch-finally结构中,无论是try内程序段正常结束,还是发生异常后,都要执行finally中的程序段,所以,close()语句可以安排在finally中。 ▼

5.2.3抽象流类 (一) 流具有处理输入输出的功能,java.io包中的类以流类为主。 Java定义了两个抽象类InputStream类和OutputStream类,还派生了很多与流有关的子类。 InputStream类提供了有关读入数据的方法,读入数据时都是以字节为单位,可以一个字节一个字节的读入数据,也可以读入任意长度的字节块。 OutputStream类输出流写出数据也是以字节为单位,即可以一个字节一个字节地写出数据,也可以一次写出任意长度的字节块。

5.2.3抽象流类 (二) 1.InputStream类 ▼ 类中mark(), reset(), makeSupported()三个方法与标记复位操作有关,它们的作用是: mark()在输入流(如文件)中任意位置作一标记,从标记位置开始,以后读入的字节数据可以用reset()方法取消,使输入流的读入位置复位到标记处。 完成这种标记复位功能的前提条件是markSupported()方法返回值必须为true。如果返回为false,则表示不支持这种功能。

5.2.3抽象流类 (三) 在使用这种标记复位功能时,mark()所需readlimit参数代表一个极限值,它表示从标记位置开始,到用reset()取消读入数据时,最多能读入的字节数。如果读入的字节数已经超过了readlimit限制,再使用reset(),则复位的位置不确定。 所以,在编程中需要使用标记复位功能时,应该小心谨慎。

5.2.3抽象流类 (四) 所有InputStream的子类都是针对不同的输入数据源,其类名的前缀清楚地表示出输入的数据源: FileInputStream类的数据源是文件。 PipedInputStream类的数据源是管道。 FilterInputStream类及其子类是加强流,它的功能更加强大,使用更加灵活。

5.2.3抽象流类 (五) 2.OutputStream类 ▼ OutputStream类的子类: ByteArrayOutputStream类 FileOutputStream类 PipedOutputStream类 FilterOutputStream类和它的子类加强输出流的功能。

5.2.4文件输入输出流类 (一) 1.FileInputStream类 它有三个构造函数,各自使用不同的参数: name 用String对象表示文件名。 file 用File对象表示文件名,使应用程序独立于平台。 fdObj 用FileDescriptor对象表示文件名,FileDescriptor类定义一个本地文件系统。在生成FileInputStream对象时同时打开文件以供应用程序读入数据。

5.2.4文件输入输出流类 (二) FileInputStream类覆盖了InputStream类的read()方法,它们都是按字节读入数据: 不带参数的read()一次只能读入一个字节, 另外两个read()一次可以读入任意多个字节。 在读入数据后,前一个read()方法返回读入的字节数据,后两个方法返回读入的字节数,如果遇到文件结束符,则返回-1。 ▼

5.2.4文件输入输出流类 (三) 2.FileOutputStream类 FileOutputStream类和FileInputStream类在构造函数和方法的参数定义上都十分相似,只是一个针对输入,另一个针对输出。 生成FileOutputStream对象时,如果文件不存在,则创建该文件供程序输出数据,如果文件已经存在,则有改写和附加两种输出数据的方式: 改写的含义是先把原文件长度截为零,原文件数据被丢弃,然后再输出数据; 附加的含义是在原文件末尾追加输出数据,原文件数据仍然存在。

5.2.4文件输入输出流类 (四) 除使用第二个构造函数生成对象外,其余都是以改写方式输出数据。第二个构造函数中增加了append参数,可以选择输出数据的方式,该参数为true表示附加方式,false表示改写方式。 说明:FileInputStream类和FileOutputStream类具有读写文件的方法,但它们读写数据的效率并不高,Java鼓励程序员用更有效的方法覆盖有关读写方法,以提高应用程序的性能。

5.2.5加强输入输出流类 (一) 我们把FilterInputStream类和FilterOutputStream类以及它们的子类,称为加强输入输出流类,因为,利用这些流类不但可以改进程序的输入输出性能,而且功能更加强大。 FilterInputStream类的子类: BufferedInputStream类 DataInputStream类 FilterOutputStream类的子类 BufferedOutputStream类 DataOutputStream类

5.2.5加强输入输出流类 (二) 1.FilterInputStream类和FilterOutputStream类 FilterInputStream类和FilterOutputStream类与InputStream类和OutputStream类相比,并没有增加任何新的方法,只是分别覆盖InputStream类和OutputStream类的所有方法。

5.2.5加强输入输出流类 (二) 它们真正的改变是在其构造函数上: protected FilterInputStream(InputStream in) protected FilterOutputStream(OutputStream out) 它们要求的参数分别是一个InputStream对象、OutputStream对象,即是任意一个输入流或输出流对象,而不是InputStream类和OutputStream类要求的String或File对象。

5.2.5加强输入输出流类 (三) 2. BufferedInputStream和BufferedOutputStream类 这两个类都在标准读写功能和应用程序之间,增加输入输出缓冲机制,从而显著地提高输入输出的速度。 BufferedInputStream类用于提高读入数据的速度,构造函数如下: public BufferedInputStream(InputStream in); public BufferedInputStream(InputStream in, int size);

5.2.5加强输入输出流类 (四) 它的构造函数使用输入流对象,在生成BufferedInputStream对象时可以设置输入缓冲区的大小,也可以使用缺省值,其值是2048字节。生成BufferedInputStream对象后,应用程序在读入数据时,直接取自于缓存区,从而提高读入数据的速度。 BufferedOutputStream类用于提高写出数据的速度,它与BufferedInputStream类相似,使用输出缓冲区来提高输出数据的速度,输出缓冲区的缺省大小为512字节。

5.2.5加强输入输出流类 (五) 3.DataInputStream类和DataOutputStream类 结合RandomAccessFile类就很容易理解这两个类,因为,RandomAccessFile类同时实现了两个接口: dataInput接口和DataOutput接口 而DataInputStream类和DataOutputStream类分别实现了这两个接口。 DataInputStream类中读数据的方法和DataOutputStream类中写数据的方法,与RandomAccessFile类中的读写方法含义完全一致,在此不再赘述。 ▼

5.2.6其它输入输出流类(一) 本节将介绍的输入流类有: SequenceInputStream类 PipedInputStream类 输出流类有: PipedOutputStream类 1.SequenceInputStream类 SequenceInputStream类可以将两个或几个输入流不露痕迹地接合在一起,生成一个长长的接合流,在读入数据时,它忽略前面几个输入流的结束符EOF,直到最后一个流的结束符EOF时,才完成流的输入,其定义如下: ▼

5.2.6其它输入输出流类(二) 2.管道输入输出流类 管道是UNIX的发明,它大大增强了流的概念。其含义如下面的命令串所示: c:\>dir|sort|more 这里使用了两个管道(用|表示)把三个命令连在一起,第一个管道把dir命令的输出连接到sort命令的输入,第二个管道将sort命令的输出连到more命令的输入,从而实现生成目录清单,进行排序后,一页一页地显示。 Java使用了管道技术,用PipedInputStream类和PipedOutputStream类实现管道操作,这两个类必须同时使用 。 ▼

5.2.6其它输入输出流类(三) 管道技术在多线程系统中使用较多,它可以解决不同线程之间同步通讯的问题,从而保证大量数据交换顺利进行。 要实现多线程的同步通讯,必须把管道连接起来,这里有两种方法实现管道的连接: 使用带参数的构造函数。 使用不带参数的构造函数,再调用任何一个类的connect()方法,实现输入管道和输出管道的连接。 ▼

运行结果

5.2.6其它输入输出流类(二) 3.对象流和序列化 ObjectInputStream类和ObjectOutputStream 对象输出流使用writeObject(Object obj)方法将一个对象obj写到输出流送往目的地 对象输入流使用readObject()从源读取一个对象到程序中。 构造方法分别是: ObjectInputStream(InputStream in) ObjectOutputStream(OutputStream out)。

5.2.6其它输入输出流类(二) 3.对象流和序列化 当使用对象流写出或读入对象时,要保证对象是序列化的。 一个类如果实现了Serializable接口,那么这个类的对象就是序列化的对象。 Serializable接口中的方法对程序是不可见的,因此实现该接口的类不需要实现额外的方法。 当把一个序列化对象写出或读入到对象流中的时候,JVM会实现Serializable接口中的方法 ▼

运行结果

5.2.7 Reader和Writer InputStream类和OutputStream类及其子类,读写流内数据时以字节为单位。 两种流类中定义的方法的种类和参数大致相同。 例如: public int read(byte b[], int off, int len); public int read(char b[], int off, int len);

InputStream FileInputStream FilterInputStream PipeInputStream OutputStream FileOutputStream FilterOutputStream PipeOutputStream Object Reader FileReader FilterReader PipeReader Writer FileWriter FilterWriter PipeWriter

5.3 网络编程 IP地址标识Internet上的计算机。 端口号标识正在计算机上运行的进程(程序)。 5.3 网络编程 IP地址标识Internet上的计算机。 端口号标识正在计算机上运行的进程(程序)。 端口号与IP地址的组合得出一个网络套接字。 端口号的范围:0-216 知名端口(Well-Known Ports):范围从0到1023,这些端口号一般固定分配给一些服务。 动态端口(Dynamic Ports):范围从1024到65535,当程序向系统提出访问网络的申请,系统就从这些端口号中分配一个未用的供该程序使用。在关闭程序进程后,就会释放所占用的端口号。

5.3 网络编程 名称 Socket TCP标准套节字服务说明 echo 7 发送数据的回应 discard 9 放弃发送的数据 5.3 网络编程 名称 Socket TCP标准套节字服务说明 echo 7 发送数据的回应 discard 9 放弃发送的数据 daytime 13 产生目标机上的当地时间 chargen 19 字符产生器 ftp 21 文件传送 telnet 23 远程登录 smtp 25 简单邮件传送 gopher 70 Gopher服务 finger 79 用户查询服务 http 80 WWW 服务 pops 110 邮政服务 nntp 119 网络新闻传送

java .net包按功能分组 Internet寻址 UDP/IP无连接服务类 TCP/IP WWW InetAddress类和URL类 DatagramPacket类和DatagramSocket类 TCP/IP Socket类和ServerSocket类 WWW URL类和URLConnection类

5.3.1 InetAddress类 InetAddress类提供有关从域命地址查询IP地址的方法。 public final class InetAddress implements Serializable{ pulic static InetAddress getByName(String host) throws UnknownHostException;//获取主机地址 pulic static InetAddress[] getAllByName(String host) throws UnknownHostException; pulic static InetAddress getLocalHost(String host) throws UnknownHostException;//获取本机地址

5.3.1 InetAddress类 public String getHostName();//获取主机名 public byte[] getAdress(); //获取整数IP地址需转换才可正确显示 public String getHostAddress(); //获取IP地址 public boolean equals(Object obj); public int hashCode(); public boolean isMulticastAddress(); public String toString(); //获取主机名/IP地址 }

例子:运行结果

5.3.2 Socket套接字编程 目的: 学会如何创建采用套接字通信的C/S网络应用程序。 Socket API 1981提出于BSD4.1 UNIX 通过Socket API,网络应用程序明确的创建、使用及释放套接字 client/server模式 通过Socket API,提供2类传输服务: 不可靠的数据报传输 可靠的字节流传输 1. 套接字是一个主机本地应用程序所创建的, 为操作系统所控制的接口 (“门”) . 2. 应用进程通过这个接口跨网络发送(/接收)消息到(/从)其他应用进程。 socket

用TCP进行套接字编程 Socket: 应用进程和传输层协议(UCP or TCP)之间的门。 controlled by application developer controlled by application developer process TCP with buffers, variables socket process TCP with buffers, variables socket controlled by operating system controlled by operating system internet host or server host or server

用TCP进行套接字编程(续) 客户必须初始联系服务器 服务器进程必须先运行 服务器进程必须创建套接字 (门) 来迎候客户的初始联系 客户如何初始联系服务器: 创建客户本地TCP socket 指定服务器进程的IP地址, 端口号 一旦客户创建套接字, 客户TCP 就发起3次握手并建立与服务器 TCP的连接 一旦客户初始联系(敲门)服务器, 服务器TCP为服务器进程创建1个新的socket 与客户进程通信 允许服务器与多个客户通信 源端口号被用来区分客户 TCP 为客户和服务器提供了 可靠的, 顺序的,字节流的 传输 (“管道”) 。 从应用程序的角度来看

Socket类和ServerSocket类 一.通信机制 1.Server端 创建ServerSocket对象,在某个端口提供监听服务 等待来自Client端的请求服务。 接收Client端的请求,用返回的Socket建立连接。 通过向Socket读写数据与Client端通信。 关闭Socket,结束当前通信,等待其它请求。 关闭ServerSocket对象结束监听服务。

一.通信机制:Client端 创建Socket对象,向Server的监听端口发出请求。 通过向Socket读写数据与Server端通信。 关闭Socket,结束与Socket通信。

二.Socket类 构造函数 public Socket(String host, int port) throws IOException; // 主机,端口号 public Socket(InetAddress addresst, int port) throws IOException; public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException; //客户地址,客户端口号 public Socket(InetAddress addresst, int port, InetAddress localAddr, int localPort) throws IOException;,

二.Socket类 常用方法 public InputStream getInputStream() throws IOException; //获得对方发送到本机的数据输入流 public OutputStream getOutputStream() //本机发送给对方的数据输出流 public synchronized void close() thows IOException;

三.ServerSocket类 构造函数 public ServerSocket(int port) throws IOException; public ServerSocket(int port, int backlog) throws IOException; //backlog:允许同时联入服务器的客户机数目,缺省值位50。 public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException; //bindAddr:指该端口捆绑的IP地址,常用于多地址的主机

三.ServerSocket类 创建一个ServerSocket类 ServerSocket myServer = new ServerSocket(port); 监听可能的Client请求: Socket linkSocket = myServer.accept(); 监听端口,使Server端口的程序处于等待状态; 程序将一直阻赛直到捕捉到Client端的请求,并返回一个与该Client通信的Socket对象; 以后Server程序只要向这个Socket对象读写数据,就可实现向远端的Client读写数据。 结束监听: myServer.close(); ▼

Server (running on hostid) TCP客户/服务器套接字交互流程: 注解: incoming request 译为“到来的请求” Server (running on hostid) Client create socket, port=x, for incoming request: welcomeSocket = ServerSocket() TCP connection setup close connectionSocket read reply from clientSocket create socket, connect to hostid, port=x clientSocket = Socket() wait for incoming connection request connectionSocket = welcomeSocket.accept() send request using clientSocket read request from connectionSocket write reply to

5.3.3 DatagramPacket类和DatagramSocket类 public DatagramPacket(byte ibuf[], int ilength); public DatagramPacket(byte ibuf[], int ilength, InetAddress iaddr, int iport); 参数一:接收的字节数组 参数二:长度 参数三:接收者地址 参数四:端口号

DatagramSocket类 构造函数 public DatagramSocket(); //连接到本地主机的任一个可用的端口上 public DatagramSocket(int port); //在指定端口创建对象 public DatagramSocket(int port, InetAddress localAddr); //用于在多IP地址主机上创建对象 三个构造函数都抛出IOException异常。

DatagramSocket类 数据报接收 数据报发送 public synchronized void receive(DatagramPacket p) throws IOException; 该方法使程序线程处于阻塞状态,直至收到信息。 数据报发送 public void send(DatagramPacket p)

数据报的发送 创建DatagramPacket对象 在指定或可用的本机端口创建DatagramSocket对象 包含要发送的数据、长度 发送的目的主机地址、端口号 在指定或可用的本机端口创建DatagramSocket对象 调用该DatagramSocket的send()方法,以DatagramPacket为参数发送数据报。

数据报的接收 创建一个接收数据报的DatagramPacket对象 在指定或可用的本机端口创建DatagramSocket对象 包含空白数据缓冲区 指定数据报长度 在指定或可用的本机端口创建DatagramSocket对象 调用该DatagramSocket的receive()方法,以DatagramPacket为参数接收数据报。 ▼

5.3.4 URL类和URLConnection类 URL类 URL地址由协议、主机名、路径文件名和端口号四个部分组成。 例如:http://www.tsinghua.edu.cn:80/index.html 构造函数 public URL(String protocol, String host, int port, String file); public URL(String protocol, String host, String file) throws MalformedURLException; public URL(String spec) throws MalformedURLException; public URL(URL contex, String spec)

URL类 常用方法: public int getPort(); public String getProtocol(); public String getHost(); public String getFile(); public URLConnection openConnection(); public final InputStream openStream(); public final Object getContent();

读取URL中的资源 URL对象调用InputStream openStream() 方法可以返回一个输入流,该输入流指向URL对象所包含的资源。通过该输入流可以将服务器上的资源信息读入到客户端。 下面的例子,在一个文本框里输入网址,然后单击“确定”按钮,就可以读取服务器上的资源。由于网速或其它因素,URL资源读取可能会引起堵塞,因此程序在一个线程中读取URL资源,避免堵塞主线程。 ▼

URLTest.java

URLConnection类 利用给定的URL地址创建一个URL类对象,调用该对象的openConnection()方法,就可以返回一个对应于URL地址的URLConnection对象。 URL myUrl=new URL(“http://www.tsinghua.edu.cn/”) URLConnection myUrlConn = myUrl.openConnection(); 使用URLConnection可向远方计算机传送信息。