490 likes | 604 Views
é¡¹ç›®ä¹ ç½‘ç»œåŠŸèƒ½çš„å®žçŽ°. å¦ä¹ ç›®æ ‡. 9.1 I/O 基础知识 9.2 Applet 9.3 网络编程 9.4 线程. 9.1 I/O 基础知识. ä»€ä¹ˆæ˜¯æ•°æ®æµ ? æµæ˜¯å¯è¢«é¡ºåºè®¿é—®çš„æ— é™é•¿çš„å—符åºåˆ—。. Java è¯è¨€ä¸æ•°æ®æµæ˜¯å‘逿ˆ–接收数æ®çš„管é“ã€‚é€šå¸¸ï¼Œä½ çš„ç¨‹åºæ˜¯æµçš„ä¸€ä¸ªç«¯ç‚¹ï¼Œå…¶å®ƒç¨‹åºæˆ–文件是æµçš„å¦ä¸€ä¸ªç«¯ç‚¹ã€‚. 文件 , å—符串 å˜å‚¨åŒº. 文件. 文件. 起点. 程åº. 程åº. 网络端点. 终端. æ•°æ®æµ. 网络端点.
E N D
学习目标 • 9.1 I/O基础知识 • 9.2 Applet • 9.3 网络编程 • 9.4 线程
9.1 I/O基础知识 • 什么是数据流 ? • 流是可被顺序访问的无限长的字符序列。
Java语言中数据流是发送或接收数据的管道。通常,你的程序是流的一个端点,其它程序或文件是流的另一个端点。Java语言中数据流是发送或接收数据的管道。通常,你的程序是流的一个端点,其它程序或文件是流的另一个端点。 文件,字符串 存储区 文件 文件 起点 程序 程序 网络端点 终端 数据流 网络端点
流的单向性:源端点和目的端点分别叫做input stream(输入流)和output stream(输出流)。你可以从输入流读,但你不能对它写;同样,你可以向输出流写,但不能从输出流读。
流的分类 InputStream和OutputStream:字节流。其它字节流都是InputStream或OutputStream的子类。 Reader和 Writer:字符流。其它字符流都是Reader或Writer的子类. 流 字节流 字符流
字节流—— • 适用于各类文件 • 每次读写8位字节 • 效率较低 字节流和字符流的比较 • 以字节为对象: • 输入流:InputStream • 输出流:OutputStrea • 以字符为对象: • 输入流: Reader • 输出流: Writer • 字符流 • 适用于16位的字符文件 • 每次读写16位字符 • 效率较高
1 字节流 InputStream的方法 三个方法访问它的数据: int read():简单读方法,返回一个int值,它是从流里读出的一个字节。如果遇到文件结束则返回-1。 int read(byte []):将数据读入到字节数组中,并返回所读的字节数。 int read(byte[], int offset,int length) 将数据读入到字节数组中,并返回所读的字节数。Offset是数组的偏移量,length是读取的长度。
InputStream其他方法: • void close() • int available() • skip(long n) • boolean markSupported() • void mark(int readlimit) • void reset()
OutputStram方法 • 三个基本的write()方法 • int write(int c) • int write(byte[] buffer) • int write(byte[] buffer, int offset,int length) • 其他方法 • void close() • void flush()
2 字符流 Reader方法 • 三个基本的read()方法 • int read() • int read(char[] cbuffer) • int read(char[] cbuffer, int offset ,int length ) • 其他方法 • void close() • int available() • skip(long n) • boolean markSupported() • void mark(int readlimit) • void reset()
Writer方法 • 基本write方法: • void write(int c) • void write(char[] cbuf) • void write(char[] cbuf, int offset, int length) • void write(String string) • void write(String string, int offset,int length) • 其它方法: • void close() • void flush()
FileInputStream和FileOutputStream 这两个节点流用来操作磁盘文件。这些类的构造函数允许你指定它们所连接的文件。要构造一个FileInputStream,所关联的文件必须存在而且是可读的。如果你要构造一个FileOutputStream而输出文件已经存在,则它将被覆盖。主要用于操作二进制或者带有格式的文件:如压缩文件,可执行文件等。 FileInputStream infile = new FileInputStream("myfile.dat"); FileOutputStream outfile = new FileOutputStream("results.dat");
BufferInputStream和BufferOutputStream 带有缓冲区的流,BufferInputStream一次可以读入一定长度的数据(默认2048字节),BufferOutputStream一次可以一定长度的数据(默认512字节),可以提高I/O操作的效率.需要和其它的流类配合使用. BufferOutputStream在使用时,为了确保把数据写出去,建议最后执行flush()将缓冲区中的数据全部写出去。
PipedInputStream和PipedOutputStream 管道流用来在线程间进行通信。一个线程的PipedInputStream对象从另一个线程的PipedOutputStream对象读取输入。要使管道流有用,必须有一个输入方和一个输出方。
DataInputStream和DataOutputStream 用来对java的基本数据类型读写的类 DataInputStream方法 byte readByte() long readLong() double readDouble() String readUTF(DataInput in) DataOutputStream方法 void writeByte(byte) void writeLong(long) void writeDouble(double) void writeUTF(String str)
InputStreamReader 和 OutputStreamWriter 用于字节流与字符流之间的转换接口。 当你构造一个InputStreamReader或OutputStreamWriter时,转换规则定义了16位Unicode和其它平台的特定表示之间的转换。
InputStreamReader从一个数据源读取字节,并自动将其转换成Unicode字符。如果你特别声明,InputStreamReade会将字节流转换成其它种类的字符流。InputStreamReader从一个数据源读取字节,并自动将其转换成Unicode字符。如果你特别声明,InputStreamReade会将字节流转换成其它种类的字符流。 OutputStreamWriter将字符的Unicode编码写到输出流,如果你的使用的不是Unicode字符,OutputStreamWriter会将你的字符编码转换成Unicode编码。
BufferedReader和BufferedWriter 因为在各种格式之间进行转换和其它I/O操作很类似,所以在处理大块数据时效率最高。在InputStreamReader和OutputStreamWriter的结尾链接一个BufferedReader和BufferedWriter是一个好主意。记住对BufferedWriter使用flush()方法。 • FileReader和FileWriter 以字符的方式操作文件的类,主要用于操作文本文件。 • PrintWriter 与PrintStream相类似,使用println()输出内容。
使用i/o 的步骤 • 1 构建数据流,输入用标准i/o即键盘输入System.in来构建数据流。输出到文件用 File的相关输出流类构建数据流。 • 2 使用相应的函数read或write 。 • 3 关闭相应的i/o流。 • 要把输入输出放到try-catch-finally块中。
任务1数据输入的实现 • 数据输入一般是从键盘输入一个数据,然后把数据格式转换为相应的格式,这样就可以实现的数据输入。键盘输入一般由标准输入System.in()。键盘输入一行字符并输出到屏幕上。代码如下:
import java.io.*; • public class IOStreamDemo { • // Throw exceptions to console: • public static void main(String[] args) • throws IOException { • // 1b. Reading standard input: • try { • BufferedReader stdin = new BufferedReader( • new InputStreamReader(System.in)); • System.out.print("Enter a line:"); • System.out.println(stdin.readLine()); • } catch(EOFException e) { • System.err.println("End of stream"); • }}
9.2 Applet • Applet(小应用程序)采用Java创建的基于HTML的程序。浏览器将其暂时下载到用户的硬盘上,并在Web页打开时在本地运行。一般的Applet只能通过appletviewer或者浏览器来运行,一般的Java程序通过继承Applet类也可以嵌入网页运行。
9.2.1 Applet的工作原理 • 含有Applet的网页的HTML文件代码中部带有<applet> 和</applet>这样一对标记,当支持Java的网络浏览器遇到这对标记时,就将下载相应的小应用程序代码并在本地计算机上执行该Applet。Java Applet 是用Java 语言编写的一些小应用程序,这些程序是直接嵌入到页面中,由支持Java的浏览器(IE 或 Netscape)解释执行能够产生特殊效果的程序。它可以大大提高Web页面的交互能力和动态执行能力。包含Applet的网页被称为Java-powered页,可以称其为Java支持的网页。 • 当Applet用户访问这样的网页时,Applet被下载到用户的计算机上执行,但前提是用户使用的是支持Java的网络浏览器。由于Applet是在用户的计算机上执行的,所以它的执行速度不受网络带宽或者Modem存取速度的限制,用户可以更好地欣赏网页上Applet产生的多媒体效果。
9.2.2安全性限制 • 1. 不允许Applet访问本地文件系统。 • 2. Applet不能执行任何本地计算机上的程序。 • 3. 不允许Applet尝试打开除提供Applet的服务器之外的任何系统的Socket。 • 4. 不允许Applet访问用户名、电子邮件地址等与本地系统有关的信息。 • 5. 对于Applet而言,Java环境中的某些标准系统属性是只读的。 • 6. Applet不能创建或装载Applet的机器的网络连接。 • 7. Applet不能充当网络服务器,监听或接收来自远程系统的连接请求。 • 8. 不允许Applet装载动态库或定义本地方法调用。 • 9. Applet不能操纵不在自己线程组中的任何线程。 • 10. Applet不能关闭JVM。
9.2.3开发步骤 • Applet程序开发主要步骤如下: • 1) 选用EDIT或Windows Notepad等工具作为编辑器建立Java Applet源程序。 • 2) 把Applet的源程序转换为字节码文件。 • 3) 编制使用class 的HTML文件。在HTML文件内放入必要的<OBJECT>语句。
任务2一个简单的applet • 根据applet的开发步骤,首先我们要建一个java程序并编译,代码如下: • import java.awt.*; • import java.applet.*; • public class ShowImage extends Applet • { Image picture; • public void init() • { picture=getImage(getCodeBase(),"Image.gif"); //装载图象 • } • public void paint(Graphics g) • { g.drawImage(picture,0,0,this); //显示图象 • } • }
编译为ShowImage.class文件。然后嵌入到HTML文件里,代码如下:编译为ShowImage.class文件。然后嵌入到HTML文件里,代码如下: • <HTML><TITLE> • Show Image Applet • </TITLE><APPLET CODE="ShowImage.class" • WIDTH=390 HEIGHT=400> • </APPLET></HTML>
9.3 网络编程 • 9.3.1基于Java的网络通信 • 1. TCP/IP套接字 • 套接字是网络软件中的一个抽象概念,套接字允许单个计算机同时服务于很多不同客户,并能够提供不同类型信息的服务。该技术由引入的端口处理,该端口既是一个特定机器上的一个被编号的套接字---通信端口.TCP/IP套接字用于在主机和Internet之间建立的可靠、双向、点对点、持续的流式连接。
(1)ServerSocket • ServerSocket被设计成在等待客户建立连接之前不做任何事情的监听器,构造方法的版本如下: • public ServerSocekt(int port) throws IOException
(2)Socket • 该类为建立连向服务器套接字及启动协议交换而设计,当进程通过网络进行通信的时候,java技术使用流模型来实现数据的通信。一个Socket包括两个流,分别为一个输入流和一个输出流,一个进程如果要通过网络向另一个进程发送数据,只需简单地写入与Socket相关联的输出流,同样,一个进程通过从与Socket相关联的输入流来读取另一个进程所写的数据。如果通过TCP/IP协议建立连接,则服务器必须运行一个单独的进程来等待连接,而某一客户机必须试图到达服务器,就好比某人打电话,必须保证另一方等待电话呼叫,这样才能实现两人之间的通信。
2. UDP套接字 • UDP(User Datagrams Protocol)用户数据报协议,是一种使用数据报的机制来传递信息的协议。数据报(Datagrams)是一种在不同机器之间传递的信息包,该信息包一旦从某一机器被发送给指定目标,那么该发送过程并不会保证数据一定到达目的地,甚至不保证目的地的存在真实性。反之,数据报被接受时,不保证数据没有受损,也不保证发送该数据报的机器仍在等待响应。
(1) DatagramPacket • 该类主要有四个常用构造方法,分别如下: • DatagramPacket(byte[] buff, int length) • DatagramPacket(byte[] buf, int offset, int length) • DatagramPacket(byte[] buf, int length, InetAddress address, int port) • DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
(2)DatagramSocket • DatagramSocket() • 创建一个以当前计算机的任意可用端口为发送端口的数据报连接 • DatagramSocket(int port) • 创建一个以当前计算机的port端口为发送端口的数据报连接 • DatagramScoket(int port, InetAddress address) • 创建一个以当前计算机的port端口为发送端口,向IP地址为address的计算机发送数据报连接。
任务3网络功能的实现 • 客户端代码如下: • import java.io.*; • import java.net.*; • class Client • { • public static void main(String[] args) • { • try{ • Socket socket=new Socket("127.0.0.1",6565); • DataOutputStream out=new DataOutputStream(socket.getOutputStream()); • out.writeUTF("我是客户机"); • DataInputStream in=new DataInputStream(socket.getInputStream()); • String s=in.readUTF(); • System.out.println("客户机收到:"+s); • }catch(Exception e){} • } • }
服务器端代码如下: • import java.io.*; • import java.net.*; • class Server • { • public static void main(String[] args) • { • try{ • ServerSocket s_socket=new ServerSocket(6565); • Socket socket=s_socket.accept(); • DataInputStream in=new DataInputStream(socket.getInputStream()); • String s=in.readUTF(); • System.out.println("服务器收到:"+s); • DataOutputStream out=new DataOutputStream(socket.getOutputStream()); • out.writeUTF("我是服务器"); • }catch(Exception e){} • } • }
9.4 线程 • 9.4.1 线程的概念 • 一个关于计算机的简化的视图是:它有一个执行计算的处理机、包含处理机所执行的程序的ROM(只读存储器,在JAVA中也叫堆栈)、包含程序所要操作的数据的RAM(随机存储器,在JAVA中也叫堆)。在这个简化视图中,只能执行一个作业。一个关于最现代计算机比较完整的视图允许计算机在同时执行一个以上的作业。
9.4.2线程状态和调度 • 在Java中,线程是抢占式的,而不是分时的 (一个常见的错误是认为“抢占式”只不过是“分时”的一种新奇的称呼而已) 。 • 抢占式调度模型是指可能有多个线程是可运行的,但只有一个线程在实际运行。这个线程会一直运行,直至它不再是可运行的,或者另一个具有更高优先级的线程成为可运行的。对于后面一种情形,低优先级线程被高优先级线程抢占了运行的机会。 • 一个线程可能因为各种原因而不再是可运行的。线程的代码可能执行了一个Thread.sleep()调用,要求这个线程暂停一段固定的时间。这个线程可能在等待访问某个资源,而且在这个资源可访问之前,这个线程无法继续运行。
9.4.3 创建线程的两种方式 • 从面向对象的角度来看,Thread类是一个虚拟处理机的严格封装,因此只有当处理机模型修改或扩展时,才应该继承类。由于Java技术只允许单一继承,所以如果你已经继承了Thread,你就不能再继承其它任何类。 • 当一个run()方法体出现在继承Thread的类中,用this指向实际控制运行的Thread实例。因此,代码不再需要使用如下控制:
1. 实现Runnable接口 • import java.awt.*; • import java.applet.Applet; • import java.util.*; • import java.text.DateFormat; • public class jsq extends Applet implements Runnable { • Thread clockThread=null; • public void init() { • setBackground(Color.blue); • setForeground(Color.yellow); • } • public void start() { • if (clockThread==null) { • clockThread=new Thread(this,"Clock2"); • clockThread.start(); • } • }
public void run() { • Thread myThread=Thread.currentThread(); • while (clockThread==myThread) { • repaint(); • try { • Thread.sleep(1000); • } • catch (InterruptedException e) {} • } • } • public void paint(Graphics g) { • Date date=new Date(); • DateFormat formatter=DateFormat.getTimeInstance(); • String str=formatter.format(date); • g.drawString(str,5,10); • } • public void stop() { • clockThread=null; • } • }
2. 继承Thread类 • class jsq { • public static void main(String args[]) { • jsq1 t1=new jsq1("thread1"); • jsq1 t2=new jsq1("thread2"); • t1.start(); • t2.start(); • } • } • class jsq1 extends Thread { • public jsq1(String str) { • super(str); // 调用父类的构造方法为线程对象命名 • }
public void run() { • for (int i=0; i<3; i++) { • System.out.println(getName()+"在运行"); • try { • sleep(1000); // 用休眠1000毫秒来区分哪个线程在运行 • System.out.println(getName()+"在休眠"); • } catch (InterruptedException e) {} • } • System.out.println(getName()+"已结束"); • } • }
任务4多线程网络功能的实现 • 任务3已经实现了网络通信功能,我们要实现多线程的网络通信,只需要加入多线程。具体代码如下: • 服务器端: • public class MultiServer { • static final int PORT = 8080; • public static void main(String[ ] args) throws IOException { • ServerSocket s = new ServerSocket(PORT); • System.out.println("Server Started"); • try {
while (true) { • Socket socket = s.accept( ); • try { • new ServerThread(socket); • } catch (IOException e) { • socket.close( ); • } • } • } finally { • s.close( ); • } • } • }
//服务器端线程 • class ServerThread extends Thread { • private Socket socket; • private BufferedReader in; • private PrintWriter out; • public ServerThread(Socket s) throws IOException { • socket = s; • in = new BufferedReader( • new InputStreamReader(socket.getInputStream( ))); • out = new PrintWriter( • new BufferedWriter(new OutputStreamWriter( • socket.getOutputStream( ))), true); • start( ); • } • public void run( ) { • …… • }
客户端: • public class MultiClient { • static final int MAX_THREADS = 40; • public static void main(String[] args) throws IOException, • InterruptedException { • while (true) { • if (ClientThread.threadCount( ) < MAX_THREADS) • new ClientThread(“127.0.0.1”, 8888); • Thread.currentThread( ).sleep(100); • } • } • }
//客户端线程 • class ClientThread extends Thread { • private Socket socket; • private BufferedReader in; • private PrintWriter out; • …… • public ClientThread(String ip, int port) { • threadcount++; • try { • socket = new Socket(ip, port); • in = new BufferedReader( • new InputStreamReader(socket.getInputStream( ))); • out = new PrintWriter( • new BufferedWriter(new OutputStreamWriter( • socket.getOutputStream( ))), true); • start( ); • } catch (IOException e) { • try { socket.close(); } catch(IOException e2) {……} • } • } • public void run( ) { …… } • }
任务5聊天系统的实现 • 本章我们学习了网络通信,上两章我们了界面的设计,请自己完成聊天系统。