2007年2月26日星期一

Eclipse 开发环境的调试功能总结(ZZ)

转载自http://www.javaeye.com/article/799
本文概述了怎样使用 Eclipse 平台的内置调试功能来调试您的软件项目。调试是程序员无法回避的工作。调试方法有许多种,但归根结底,就是找到引发错误的代码。举例来说,在 Linux 应用程序中,分段故障被认为是最常见的错误之一。当程序尝试访问未分配给它的内存并因为分段违例而终止时,将产生这种错误。要修正这种错误,您需要找到引发该行为的那行代码。一旦找到有问题的代码行,这对于知道引发错误的上下文及其相关的值、变量和方法也是有所帮助的。使用调试器将使查找这些信息变得相当简单。Eclipse 调试器及 Debug 视图Eclipse 平台的特色在于内置了 Java 调试器,该调试器提供所有标准调试功能,包括进行单步执行、设置断点和值、检查变量和值以及暂挂和恢复线程的能力。此外,您还可以调试在远程机器上运行的应用程序。Eclipse 平台主要是一个 Java 开发环境,但其体系结构同时也向其它编程语言开放。如以下您将看到的,同一个 Eclipse 的 Debug 视图也可用于 C 和 C++ 编程语言。Eclipse 平台工作台(Eclipse Platform Workbench)及其工具是基于 Java 开发工具(JDT)组件所构建的。这些组件向 Eclipse 提供以下功能:* 项目管理工具* 透视图和视图* 构建器、编辑器、搜索和构建功能* 调试器Eclipse 调试器本身是作为 Eclipse 二进制文件中包含的标准插件而存在的。Eclipse 还有一个特别的 Debug 视图,允许您在工作台中管理程序的调试和运行。它为调试中的每个目标显示其暂挂线程的堆栈帧。程序中的各个线程以作为树的节点出现,而 Debug 视图则显示运行中的各目标的进程。如果暂挂一个线程,则其堆栈帧显示为子元素。在您开始使用 Eclipse 调试器之前,假定您已经安装了适当的 Java SDK/JRE(我推荐您使用 Java VM 1.4)和 Eclipse 平台 SDK 2.0/2.1,且两者都工作正常。一般来说,先使用 Eclipse 样本来测试一下调试选项是一个好主意。如果您要开发和调试 C/C++ 项目,您还需要得到并安装 C/C++ 开发工具(C/C++ Development Tool,CDT)。有关 Java SDK/JRE、Eclipse 平台和样本以及 CDT 的链接,请参阅本文后面的参考资料。图 1 显示了 Debug 用户界面的常规视图。图 1. Eclipse Debug 视图用户界面的常规视图[myimg]upload/debug.png[/myimg]调试 Java在您能调试您的项目之前,需要先完整地编译和运行代码。您首先需要为您的应用程序创建运行配置并确认其正常启动。之后,您需要使用 Run > Debug... 菜单,以同样的方式设置调试配置。您还需要选择作为主 Java 类的由调试器使用的类(也请参阅图 2)。对一个项目,您希望有几种调试配置就可以有几种。当调试器启动后(通过 Run > Debug...),会在一个新窗口打开它,您可以准备开始调试。图 2. 在调试配置中设置项目的主 Java 类[myimg]upload/debug-config.png[/myimg]以下是最常见的 Eclipse 调试操作的示例指示信息:设置断点当您启动应用程序以进行调试时,Eclipse 自动切换到 Debug 透视图。无庸置疑,最常见的调试过程就是设置断点,以允许检查在条件语句和循环中的变量和值。要在 Java 透视图的 Package Explorer 视图中设置断点,双击所选的源代码文件,在编辑器中打开它。遍历全部代码,将光标放置在含有可疑代码的那一行的标记栏上(在编辑器区域的左侧)。双击以设置断点(也请参阅图 3)。图 3. 在编辑器左侧边缘可看到两个断点标记[myimg]upload/breakpoints2.png[/myimg]现在通过 Run > Debug... 菜单启动调试会话。有一点很重要,不要把数条语句放在同一行,因为您不能在同一行的多条语句上单步跳过或设置行断点(也请参阅图 4)。图 4. 视图通过左侧边缘的箭头指出当前正在执行的行[myimg]upload/pointer.png[/myimg]条件断点一旦您找到出错的地方,您会想要了解在崩溃前程序在干些什么。完成该工作的一种方法是单步执行程序中的每条语句,一次一句,直到到达出问题的地方。有时候更好的方法是仅运行某段代码并在出问题的地方终止其执行,这样就可以检查该位置上的数据。要实现这一点,可能要声明每当表达式的值更改时就被触发的条件断点(请参阅图 5)。此外,在输入条件表达式时还可以使用代码辅助。图 5. 设置条件断点触发器[myimg]upload/conditional.png[/myimg]对表达式求值要在 Debug 透视图的编辑器中求表达式的值,选中设置有断点的一整行,并在上下文菜单中选择 Inspect 选项(请参阅图 6)。表达式是在当前堆栈帧的上下文中求值的,其结果显示在 Display 窗口的 Expressions 视图中。图 6. 用 Inspect 选项求表达式的值[myimg]upload/debug-menu1.png[/myimg]查看变量Variables 视图(在 Display 窗口中)显示了选中的堆栈帧中的变量值(请参阅图 7)。要查看所请求的变量,只需展开 Variables 视图中的树直到您看到所请求的元素为止。您也可以在 Debug 视图中单步执行代码的同时,在 Variables 视图中查看变量。图 7. 在 Display 窗口中查看变量[myimg]upload/variables.png[/myimg]当调试器在断点上停止时,您可以通过在 Run > Debug... 菜单上选择 Step Over 选项来继续调试器会话(请参阅图 8)。这将单步跳过突出显示的代码行并执行同一个方法中的下一行(或者它在调用当前方法的方法中继续)。作为最后一步的结果而发生更改的变量用颜色突出显示(缺省值是红色),所用颜色可在“Changed Variable Value Color”首选项(由 Debug Variable Views 指定)中指定。图 8. Run... 菜单中的调试器命令[myimg]upload/debug-menu.png[/myimg]要在 Debug 视图中暂挂线程的执行,选择一个运行中的线程并单击 Debug 视图工具栏中的 Suspend 按钮。会显示该线程的当前调用堆栈,并且在 Debug 透视图的编辑器中突出显示当前执行的行。暂挂线程时,将光标放置到 Java 编辑器中的变量上,该变量的值显示在一个小悬浮窗口中。同样,该线程的顶部堆栈帧被自动选中,该堆栈帧中的可视变量显示在 Variables 视图中。可以通过在 Variables 视图中单击变量名来检查相应的变量。热交换错误修正:实时代码修正如果您运行的是 JVM 1.4(Java 虚拟机,Java Virtual Machine),Eclipse 2.0.2 和 2.1 提供一个叫做热交换错误修正(Hotswap Bug Fixing)的新功能(无法用于 JVM 1.3 或更低版本 - 也请参阅图 9)。它允许在调试器会话过程中更改源代码,这要比“退出应用程序,更改源代码,重新编译,再启动另一个调试会话”的一系列步骤好多了。要使用该功能,只需在编辑器中更改代码并恢复调试。由于 JVM 1.4 与 Java 平台调试器体系结构(Java Platform Debugger Architecture,JPDA)兼容,所以能使用该功能。JPDA 实现了在运行中的应用程序中用经过修改的代码进行替换的能力。当然,当启动您的应用程序或找到出错点需要花费很长时间的时候,该功能极其有用。图 9. 热交换错误修正功能不能在 JVM 1.3 及更低版本中使用[myimg]upload/hot-code.png[/myimg]如果您完成调试时程序还没有被完整地执行过,请在 Debug 视图中的上下文菜单中选择 Terminate 选项。一个常见的错误是您在调试器会话中使用了 Debug 或 Run 而不是 Resume。这样将会启动另一个调试器会话,而不是继续当前的会话。远程调试Eclipse 调试器提供了一个有趣的选项,可用于调试远程应用程序。它可以连接到一个运行 Java 应用程序的远程 VM 上,并将其连接到内部调试器上。处理远程调试会话非常类似于本地调试。不过,远程调试配置要求对 Run > Debug... 窗口进行不同的设置。您首先要选择左侧视图中的 Remote Java Application 项,单击 New 按钮。这样就创建了一个新的远程启动配置,并显示三个选项卡:Connect、Source 和 Common。在 Connect 选项卡的 Project 域中,选择用作启动首选项的项目(用于查找源代码)。在 Connect 选项卡的 Host 域中,输入运行 Java 程序的远程主机的 IP 地址或域名。在 Connect 选项卡的 Port 域中,输入远程 VM 接受连接的端口。一般来说,该端口是在远程 VM 启动时指定的。当您想让调试器确定 Terminate 命令在远程会话中是否可用,可以选择 Allow termination of remote VM 选项。如果您希望能终止所连接的 VM,则选择该选项。现在当您选择 Debug 选项时,调试器将尝试按指定的地址和端口连接远程 VM,并在 Debug 视图中显示结果。如果启动器无法连接至指定位置上的 VM,将显示错误消息。一般来说,远程调试功能的可用性完全取决于远程主机上运行的 Java VM(虚拟机,Virtual Machine)。图 10 显示了远程调试会话的连接属性的设置。图 10. 设置远程调试会话的连接属性[myimg]upload/remote-debug.png[/myimg]调试其它语言Java 是 Eclipse 平台的主语言。然而,Eclipse 平台同时也是一个可支持许多其它语言的可扩展平台,而其中最重要的就是支持 C/C++(因为其流行性)。Eclipse 通过用 C/C++ 开发工具(CDT)支持 C/C++。请参阅参考资料以获取相关链接。CDT 通过调试 C/C++ 代码的功能扩展了标准的 Eclipse Debug 视图,同时 CDT Debug 视图允许您在工作台中管理 C/C++ 项目的调试。CDT 不包含其内部调试器,但它向必须可在本地使用的 GNU GDB 调试器提供了一个前端。下载并安装了 CDT 之后,只需切换到 Debug 视图,您就可以开始调试当前的 C/C++ 项目了(请参阅参考资料,以获取一篇介绍如何安装 CDT 的文章的链接)。这样您可以设置(并在执行过程中任何时候更改)代码中的断点,并且跟踪变量和寄存器。Eclipse 调试器显示您调试中各个目标的暂挂线程的堆栈帧。程序中的各个线程作为树的节点出现。它显示了运行中各目标的进程。请记住当 GNU GDB 调试一个带有调试符号链接的程序时,它最有效。这是在编译过程中由命令行参数 -g 来实现的。需要更多的信息请使用 -ggdb 开关,该参数包含有特定于 GNU GDB 的调试符号。如果您要调试 servlet,使用 Sysdeo Eclipse Tomcat Launcher。该插件使您能够管理 Tomcat 4.x/3.3 servlet 容器(通过创建和导入一个 Tomcat WAR 项目)。它同时在一个内部 Java Eclipse 调试器中注册一个 Tomcat 进程,这样您就能方便地调试 Tomcat 应用程序了。还有其它几个 Eclipse 插件,使我们能够对 servlet 使用内部 Eclipse 调试器,比如 Cactus 的 Eclipse 插件,Resin 插件和 X-Parrots ServletExec 插件。在下面的参考资料中可获得这些插件的链接。结束语Eclipse 平台提供了内置的 Java 调试器,该调试器具有标准调试功能,包括进行单步执行、设置断点和值、检查变量和值以及暂挂和恢复线程的能力。它还可以用于调试在远程机器上运行的应用程序。Eclipse 平台主要是一个 Java 开发环境,但是同一个 Eclipse 的 Debug 视图也可用于 C 和 C++ 编程语言。参考资料* 在 eclipse.org 加入 Eclipse 平台社区并下载该平台。Eclipse 平台源代码是通过普通公共许可证(Common Public License)进行许可的。您还能在 eclipse.org 找到 Eclipse 项目的术语词汇表及描述,以及技术文章和新闻组。Eclipse 平台白皮书详细描述了 Eclipse 的主要组件和功能。* 在 eclipse.org 下载 C/C++ 开发工具。* 下载 Sysdeo Eclipse Tomcat Launcher。* 以下是另外一些用于 servlet 的 Eclipse 插件的链接:o Cactus 的 Eclipse 插件o Resin 插件o X-Parrots ServletExec 插件* 查看 Eclipse 插件的分类注册表。* 以下文章可以帮助您开始学习用 Eclipse 进行调试:o 请参阅由 Greg Adams 和 Marc Erickson 撰写的 developerWorks 文章“Working the Eclipse Platform”,介绍了 Eclipse 平台及其工作方式。o 要着手使用 Eclipse 平台开发应用程序,请参阅由 David Gallardo 撰写的 developerWorks 文章“Getting started with the Eclipse Platform”。o 要学习 Eclipse 中的启动框架(Launching Framework),请参阅 eclipse.org 文章“We Have Lift-off: The Launching Framework in Eclipse”。o 要获取关于产品构建器和特性的更多信息,请参阅 eclipse.org 文章“Project Builders and Natures”。* 如果您是一名开发人员,且希望参与和实现不同 Eclipse 组件相关的讨论,请访问为该项目中各组件所创建的开发人员邮件列表。* 在 developerWorks 查找更多为 Eclipse 用户准备的参考资料。关于作者Paul Leszek,是 Studio B 的一名作者,同时也是专长于 Linux/Win/Mac OS 系统体系结构和管理的独立软件顾问。在许多操作系统、编程语言和网络协议,尤其是 Lotus Domino 和 DB2 方面,他都有经验。Paul 同时还是“LinuxWorld”系列文章的作者,以及波兰语版“PC World”的 Linux 专栏作家。

2007年2月25日星期日

Nutch=lucene+Crawler(转载)

Nutch 是一个开源Java 实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。可以为什么我们需要建立自己的搜索引擎呢?毕竟我们已经有google可以使用。这里我列出3点原因:
透明度:Nutch是开放源代码的,因此任何人都可以查看他的排序算法是如何工作的。商业的搜索引擎排序算法都是保密的,我们无法知道为什么搜索出来的排序结果是如何算出来的。更进一步,一些搜索引擎允许竞价排名,比如百度,这样的索引结果并不是和站点内容相关的。因此 Nutch 对学术搜索和政府类站点的搜索来说,是个好选择。因为一个公平的排序结果是非常重要的。
对搜索引擎的理解:我们并没有google的源代码,因此学习搜索引擎Nutch是个不错的选择。了解一个大型分布式的搜索引擎如何工作是一件让人很受益的事情。在写Nutch的过程中,从学院派和工业派借鉴了很多知识:比如:Nutch的核心部分目前已经被重新用 Map Reduce 实现了。看过开复演讲的人都知道 Map Reduce 的一点知识吧。Map Reduce 是一个分布式的处理模型,最先是从 Google 实验室提出来的。你也可以从下面获得更多的消息。 http://www.domolo.com/bbs/list.asp?boardid=29http://domolo.oicp.net/bbs/list.asp?boardid=29并且 Nutch 也吸引了很多研究者,他们非常乐于尝试新的搜索算法,因为对Nutch 来说,这是非常容易实现扩展的。
扩展性:你是不是不喜欢其他的搜索引擎展现结果的方式呢?那就用 Nutch 写你自己的搜索引擎吧。 Nutch 是非常灵活的:他可以被很好的客户订制并集成到你的应用程序中:使用Nutch 的插件机制,Nutch 可以作为一个搜索不同信息载体的搜索平台。当然,最简单的就是集成Nutch到你的站点,为你的用户提供搜索服务。
Nutch 的安装分为3个层次:基于本地文件系统,基于局域网,或者基于 internet 。不同的安装方式具有不同的特色。比如:索引一个本地文件系统相对于其他两个来说肯定是要稳定多了,因为没有 网络错误也不同缓存文件的拷贝。基于Internet 的搜索又是另一个极端:抓取数以千计的网页有很多技术问题需要解决:我们从哪些页面开始抓取?我们如何分配抓取工作?何时需要重新抓取?我们如何解决失效的链接,没有响应的站点和重复的内容?还有如何解决对大型数据的上百个并发访问?搭建这样一个搜索引擎是一笔不小的投资呀!在 " Building Nutch: Open Source Search," 的作者 Mike Cafarella 和 Doug Cutting 总结如下::
... 一个具有完全功能的搜索系统:1亿页面索引量,每秒2个并发索引,需要每月800美元。10亿页面索引量,每秒50个页面请求,大概需要每月30000美元。
这篇文章将为你演示如何在中等级别的网站上搭建Nutch。第一部分集中在抓取上。Nutch的抓取架构,如何运行一个抓取程序,理解这个抓取过程产生了什么。第二部分关注搜索。演示如何运行Nutch搜索程序。以及如何订制Nutch
Nutch Vs. Lucene
Nutch 是基于 Lucene的。Lucene为 Nutch 提供了文本索引和搜索的API。一个常见的问题是;我应该使用Lucene还是Nutch?最简单的回答是:如果你不需要抓取数据的话,应该使用Lucene。常见的应用场合是:你有数据源,需要为这些数据提供一个搜索页面。在这种情况下,最好的方式是直接从数据库中取出数据并用Lucene API建立索引。中文用户,可以参考 WebLucene 或者 车东 的一些列文章。如果需要中文分词帮助还可以联系作者。 http://domolo.oicp.net/bbs/list.asp?boardid=24 Erik Hatcher 和 Otis Gospodneti?'s 的 Lucene in Action 中详细讲述了这个过程。Nutch 适用于你无法直接获取数据库中的网站,或者比较分散的数据源的情况下使用。
架构
总体上Nutch可以分为2个部分:抓取部分和搜索部分。抓取程序抓取页面并把抓取回来的数据做成反向索引,搜索程序则对反向索引搜索回答用户的请求。抓取程序和搜索程序的接口是索引。两者都使用索引中的字段。()
实际上搜索程序和抓取程序可以分别位于不同的机器上。()
这里我们先看看Nutch的抓取部分。
抓取程序:
抓取程序是被Nutch的抓取工具驱动的。这是一组工具,用来建立和维护几个不同的数据结构: web database, a set of segments, and the index。下面我们逐个解释上面提到的3个不同的数据结构。
The web database, 或者WebDB, 是一个特殊存储数据结构,用来映像被抓取网站数据的结构和属性的集合。WebDB 用来存储从抓取开始(包括重新抓取)的所有网站结构数据和属性。WebDB 只是被 抓取程序使用,搜索程序并不使用它。WebDB 存储2种实体:页面 和 链接。页面 表示 网络上的一个网页,这个网页的Url作为标示被索引,同时建立一个对网页内容的MD5 哈希签名。跟网页相关的其它内容也被存储,包括:页面中的链接数量(外链接),页面抓取信息(在页面被重复抓取的情况下),还有表示页面级别的分数 score 。链接 表示从一个网页的链接到其它网页的链接。因此 WebDB 可以说是一个网络图,节点是页面,链接是边。
Segment 是 网页 的集合,并且它被索引。 Segment 的 Fetchlist 是抓取程序使用的 url 列表 , 它是从 WebDB中生成的。Fetcher 的输出数据是从 fetchlist 中抓取的网页。Fetcher 的输出数据先被反向索引,然后索引后的结果被存储在segment 中。 Segment 的生命周期是有限制的,当下一轮抓取开始后它就没有用了。默认的 重新抓取间隔是30天。因此删除超过这个时间期限的segment是可以的。而且也可以节省不少磁盘空间。Segment 的命名是 日期加时间 ,因此很直观的可以看出他们的存活周期。
索引库 是 反向索引所有系统中被抓取的页面,他并不直接从页面反向索引产生,它是合并很多小的 segment 的索引中产生的。Nutch 使用 Lucene 来建立索引,因此所有 Lucene 相关的工具 API 都用来建立索引库。需要说明的是 Lucene 的 segment 的概念 和 Nutch 的 segment 概念是完全不同的,不要混淆哦。 可以参考 车东 的相关文章。 http://www.chedong.com/ 简单来说 Lucene 的 segment 是 Lucene 索引库的一部分,而 Nutch 的 Segment 是 WebDB 中 被 抓取和索引的一部分。

Java I/O 学习笔记4(利用Socket进行Java网络编程) ZZ

出自:天极网 郗旻
Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以较为方便的编写网络上数据的传递。在Java中,有专门的Socket类来处理用户的请求和响应。利用Socket类的方法,就可以实现两台计算机之间的通讯。这里就介绍一下在Java中如何利用Socket进行网络编程。   
在Java中Socket可以理解为客户端或者服务器端的一个特殊的对象,这个对象有两个关键的方法,一个是getInputStream方法,另一个是getOutputStream方法。getInputStream方法可以得到一个输入流,客户端的Socket对象上的getInputStream方法得到的输入流其实就是从服务器端发回的数据流。GetOutputStream方法得到一个输出流,客户端Socket对象上的getOutputStream方法返回的输出流就是将要发送到服务器端的数据流,(其实是一个缓冲区,暂时存储将要发送过去的数据)。  
程序可以对这些数据流根据需要进行进一步的封装。本文的例子就对这些数据流进行了一定的封装(关于封装可以参考Java中流的实现部分)。  
为了更好的说明问题,这里举了一个网上对话的例子,客户端启动以后,服务器会启动一个线程来与客户进行文字交流。  
要完成这个工作,需要完成三个部分的工作,以下依次说明:  
一、建立服务器类  Java中有一个专门用来建立Socket服务器的类,名叫ServerSocket,可以用服务器需要使用的端口号作为参数来创建服务器对象。
ServerSocket server = new ServerSocket(9998)   这条语句创建了一个服务器对象,这个服务器使用9998号端口。当一个客户端程序建立一个Socket连接,所连接的端口号为9998时,服务器对象server便响应这个连接,并且server.accept()方法会创建一个Socket对象。服务器端便可以利用这个Socket对象与客户进行通讯。Socket incoming = server.accept()   
进而得到输入流和输出流,并进行封装BufferedReader in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));PrintWriter out = new PrintWriter(incoming.getOutputStream(),true);   
随后,就可以使用in.readLine()方法得到客户端的输入,也可以使用out.println()方法向客户端发送数据。从而可以根据程序的需要对客户端的不同请求进行回应。  
在所有通讯结束以后应该关闭这两个数据流,关闭的顺序是先关闭输出流,再关闭输入流,即使用 out.close();in.close();
二、建立客户端代码  
相比服务器端,客户端要简单一些,客户端只需用服务器所在机器的ip以及服务器的端口作为参数创建一个Socket对象。得到这个对象后,就可以用"建立服务器"部分介绍的方法实现数据的输入和输出。Socket socket = new Socket("168.160.12.42",9998);in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out = new PrintWriter(socket.getOutputStream(),true);   以上的程序代码建立了一个Socket对象,这个对象连接到ip地址为168.160.12.42的主机上、端口为9998的服务器对象。并且建立了输入流和输出流,分别对应服务器的输出和客户端的写入。  
三、建立用户界面  
读者可以根据自己的喜好建立自己的用户界面,这不是本文的重点。  经过以上三个步骤,就可以建立一个比较简单的对话程序。但是,为了使这个程序更加完善,应进行以下几个改进:  一、现在服务器只能服务一个客户,也就是单线程的。可以将它改进为多线程服务器。try{ file://建立服务器 ServerSocket server = new ServerSocket(9998); int i=1; for(;;) {  Socket incoming = server.accept();  new ServerThread(incoming,i).start();  i++; }}catch (IOException ex){ ex.printStackTrace(); }   循环检测是否有客户连接到服务器上,如果有,则创建一个线程来服务这个客户,这个线程的名称是ServerThread,这个类扩展了Thread类,它的编写方法与前述的服务器的写法相同。 
 二、为了可以随时得到对方传送过来的消息,可以在服务器以及客户端各建立一个独立的线程来察看输入流,如果输入流中有输入,则可以即时显示出来。代码如下:new Thread(){ public void run() {  try  {    while(true)   {    checkInput();    sleep(1000);//每1000毫秒检测一次   }  }catch (InterruptedException ex) { }catch(IOException ex) {  } }}.start();其中的checkInput()方法为private void checkInput() throws IOException{ String line; if((line=in.readLine())!=null) file://检测输入流中是否有新的数据  t.setPartner(line); file://将数据流中的消息显示出来}

附:服务器的实现代码:
import java.net.*;import java.io.*;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;
public class talkServer{ public static void main(String[] args) { try  { file://建立服务器   ServerSocket server = new ServerSocket(9998);   int i=1;   for(;;)    { Socket incoming = server.accept();     new ServerThread(incoming,i).start();     i++;    }   }catch (IOException ex){   ex.printStackTrace();  } }}
class ServerThread extends Thread implements ActionListener{ private int threadNum; private Socket socket; talkServerFrm t; BufferedReader in; PrintWriter out; private boolean talking=true; public ServerThread(Socket s,int c) { threadNum = c;  socket = s; }
public void actionPerformed(ActionEvent e){ Object source = e.getSource(); try{  if(source==t.btnSend)   { out.println(t.getTalk());    t.clearTalk();  }else  if(source==t.btnEnd)   { out.println("谈话过程被对方终止");    out.close();    in.close();    talking = false;   } }catch(IOException ex){ }}
public void run(){ try{  t=new talkServerFrm(new Integer(threadNum).toString(),this);  t.setSize(500,500);  t.show();  in = new BufferedReader(new       InputStreamReader(socket.getInputStream()));  out = new PrintWriter(socket.getOutputStream(),true); }catch(Exception e){} new Thread() { public void run()  { try{    while(true)    { checkInput();     sleep(1000);  } }catch (InterruptedException ex){ }catch(IOException ex){ } } }.start(); while(talking) { } t.dispose(); }
private void checkInput() throws IOException{ String line; if((line=in.readLine())!=null)  t.setPartner(line); file://这是界面类里的方法,  file://用来将line的内容输出到用户界面 }}

java I/O 学习笔记3 转载

摘自http://blog.csdn.net/csusuntao/archive/2005/04/04/336354.aspx
低级流类用于与磁盘文件的通信,高级流类用于组织那些通过低级流移动的信息,高级流类也适用于组织发送到网络或者从网络接受的信息。
抽象上级流类:(都继承于类Object)
InputStream-------OutputStream.:所有面向字节的输入和输出流的父类(自己本身是抽象类)
Reader------Writer:所有面向字符的输入和输出流得的父类(自己本身是抽象类)
低级流类:
ByteArrayInputStream (extends InputStream): 从字节数组或字节数组中的一部分读取输入。
ByteArrayOutputStream (extends OutputStream) :向字节数组写入。
附:有几种方法可以将字节数组输出流变成可以访问的数据。
一: String toString() 返回迄今为止写入流的所有字节构成的字符串。
二: byte[] toByteArray() 返回包涵迄今为止写入流的所有字节的数组。这个数组是流内容的备份,可以修改而不会影响原始数据。
高级流类: 高级输入流从其他输入流读取输入,而高级输出流从其他输出流写入输出。
一: DataInputStream (extends InputStream) :
DataInputStream类从另一流读取字节并将其翻译成Java原型,字符数组和字符串。没有面向字符的对应读取器类。
boolean readBoolean(); byte readByte(); char readChar(); int readInt();
long readLong(); floag readFloat(); double readDouble(); String readUTF();
Static String readUTF(DataInput din) 静态方法。从指定的输入流读取UTF字符串。
二:DataOutputStream (extends OutputStream) :
DataOutputStream类支持将Java的原型数据写入输出流。也可以写入字符串和字节数组。没有相应的面向字符的写入器类。
void writeBoolean(boolean b);
void writeByte(int i) 写入i的低位字节。
void writeShort(int i) 写入i的低两位字节。
void write int(int i) 写入i的所有字节
void writeBytes(String s) 将S写成一系列字节,只写入每个双字节Unicode代码的低位字节。
void writeChars(String s); 将S 写成一系列Unicode代码。每个Unicode代码写成两个字节,从高位字节开始。
void writeUTF(String s) 将S写成UTF字符串。

java I/O 学习笔记2

Java 输入/输出(I/O)机制提供了一套简单的,标准化的API以便从不同的数据源读取和写入字符和字节数据。在“面向对象编程:Java collection更有效管理elements”一文中,我们讨论了Java 集合类架构中的类和功能并介绍了它的排序功能。在本文中,我们将学习Java 平台提供的这些I/O类,接口和操作。让我们先从了解Java 数据流开始。
数据流 Java所有的I/O机制都是基于数据流的,这些数据流表示了字符或者字节数据的流动序列。Java的I/O流提供了读写数据的标准方法。任何Java中表示数据源的对象都会提供以数据流的方式读写它的数据的方法。
Java.io是大多数面向数据流的输入/输出类的主要软件包。这个软件包包含了两个抽象类,InputStream和OutputStream。所有其它面象数据流的输入/输出类都要扩展这两个基类。
java.io软件包提供了一些类和接口,它们在由InputStream和OuputStream类提供的读写操作的顶端定义了一些有用的抽象。例如,ObjectInputStream类提供了让你把输入/输出流中的数据当成对象来读取的方法,而ObjectOutputStream类提供了让你能够把Java对象写入数据流中的方法。
优化读写过程JDK 1.1 增加了一套读写类,它们提供了比现有数据流类更有用的抽象和更好的输入/输出性能。例如,BufferedReader和BufferedWriter 类被用来从基于字符的输入和输出流中读取和写入文本。BufferdReader 类缓存字符以更高效的读取字符串,数组和文本行。BufferedWriter类缓存字符以更高效的写入字符串,数组和文本行。BufferedReader和BufferedWriter 类可以按需求进行设置。
Java输入/输出架构提供的读取器和写入器类包括 LineNumberReader 类,CharArrayReader类,FileReader类,FilterReader类,PushbackReader类,PipedReader类,StringReader类以及其它一些类。这些类是在InputStream和OuputStream类顶部的包裹类因此提供了与InputStream和OuputStream类相似的方法。但是,这些类为读写特定的对象,比方文件,字符数组和字符串等等提供了更高效而有用的抽象。
读取数据当你从一个相应的数据源对象里提取输入流或者是创建一个读取器对象的时候就会自动打开一个输入流。例如,要为一个文件打开输入流,我们只需要以下面的方式把文件名传递给Java.io.FileReader对象的构造函数:
java.io.FileReader fileReader = new java.io.FileReader("/home/me/myfile.txt");
要按顺序读取FileReader底层的输入流中的一个字节数据,只需要使用不带参数的read方法。表A中的代码段从一个文件读取文本数据,一次一个字符,然后把它写入System.out里。
要从输入流读取指定数目的字节数据到char数组里,只需要使用带一个char[]参数的read方法。数组的长度被用来确定应该读取的字符的个数。表B演示了这个技术。
要关闭一个输入流以及这个流使用的所有系统资源,你只需要以下面的方式调用close方法:
fileReader.close();
写入数据象一个输入流一样,输出流通常在你从相应的数据源提取它或者是在你创建一个写入对象的时候被自动的打开。例如,要为一个文件打开输出流,我们把文件的名字传递给java.io.FileWriter对象的构造函数,如下所示:
java.io.FileWriter fileWriter = new java.io.FileWriter("/home/me/out.txt");
要将一个特定的字符写入到输出流中,可以使用带一个int参数的write方法,int参数代表要定入的字符。
int aChar = (int)'X'; fileWriter.write(aChar);
要在输出流给定的偏移地址写入一个char数组中特定数目的字符,你可以使用带一个char[]参数,一个int 偏移量参数和一个int长度参数的write方法,如下面的例子所示:
fileWriter.write(buffer, 0, byteCount);
要关闭一个输出流并释放所有与之相关的系统资源,可以使用close方法,就象这样:
fileWriter.close();
要强迫写出一个输出流中的所有数据,可以使用下面的flush方法:
fileWriter.flush();
把它们全部综合起来我们可以使用我们学习过的这些函数从一个文件中读取数据并同时写到另一个文件中去,如表C所示。
总结Java的输入/输出机制为从不同的数据源读取和写入字符增加了一套简单而标准化的API。你对一种数据源使用Java流的经验能够让你容易的使用其它由Java提供的数据源类型。
在我们下一篇文章中,我们将会开始学习Java平台的联网和远程通讯架构。我们将会把我们对Java流的讨论扩展到这些环境并演示如何打开远程数据源,并象操作本地数据源,比方文件一样,写入数据和读取数据

Java IO学习笔记(1) 转载

最近在看lucene的原代码,里面有好多Java 的I/O操作,现在顺带复习一下,网上找到一个东东很好,
于是转载过来http://blog.csdn.net/yangxp_82/archive/2005/09/13/479306.aspx

java IO最关键的四个父类:InputStream、OutputStream、Reader、Writer。它们都是public abstract class。
InputSream和OutputStream对于数据的传送是以“byte”为单位的,而Reader和Writer对于数据的传送是以“character”为单位的。所以我们看到java.io包中的类大体上可以分为两大类,一类是以byte处理为主的Stream类,它们都是以XXXStream方式命名的;一类是以character处理为主的Reader/Writer类,它们都是以XXXReader或XXXWriter的方式命名的。
InputStream类方法简介:
InputStream是输入字节数据用的类,所以InputStream类提供了3种重载的read方法(具体方法参见API)。
如果我们要知道这个流中还有多少个byte的数据可以读取时可以调用available方法,注意的是如果InputStream对象调用这个方法的话,它只会返回0,这个方法必须由继承InputStream类的子类对象调用才有用,另外它会抛出IOException异常,必须对此异常进行处理。
如果我们想跳过一些字节来读取的话可以调用skip方法来跳过一些字节来读取。skip方法所需要的参数是long型的,指出要跳过的字节数。
流的处理是单向的,如果想重新读取已经读过的数据,我们必须进行一些处理。有些InputStream是不支持重新读取的(也就是不允许重新定位读取指针),这样我们在进行重新读取前最好先调用markSupported方法来检查一下这个InputStream对象是否支持重定位指针,如果通过,那么我们就可以先使用mark方法来指定指针的位置,然后调用reset方法来让指针指到你要求得位置。(注意的是reset方法可能抛出IOException异常)。
还有就是我们在使用完后,必须对我们打开的流进行关闭(close)。
OutputStream方法的介绍:
OutputStream提供了3个write方法来做数据的输出,这个是和InputStream是相对应的。
还有一个常用的清除缓冲区的方法就是flush。
最好就是close方法
Reader方法的介绍
Reader是输入字符数据用的,它所提供的方法跟InputStream基本一样。不过Reader类没有提供available方法,取而代之的是ready方法。
Writer方法的介绍
Writer类有5个write方法,具体可以查看API。
学习完上面的四个最最基本的四个抽象类之后,我们就来学习Java的节点类,这个对于理解使用IO来说是至关重要的,下面就用一个表格来简单说明,若要详细了解请查看API。
文件(File)
FileInputStream
FileOutputStream
FileReader
FileWriter

内存(数组)
ByteArrayInputStream
ByteArrayOutputStream
CharArrayReader
CharArrayWriter

内存(字符串)

StringReader
StringWriter

管道(Pipe)
PipeInputStream
PipeOutputStream
PipeReader
PipeWriter


下面就是一些必须学习的类(java.io.File)
这个类对文件的操作是至关重要的,对于它的学习必须深入,它不是一仅仅是我们概念中的文件,而且包括目录。详细细节请查看API。
RandomAccessFile对于IO系统来说也是很重要的,它与我们前面介绍的四个抽象类没有关系,它是直接继承自Object类,用于对文件进行随机读取操作。
下面给出一个文件操作的例子:
/**
* 学生类
* @author Sunny
* @version 1.0
*/
import java.io.*;
public class Student implements Serializable{
private String name;
private String id;
private int age;

/**
* 构造函数
* @param name
* @param id
* @param age
*/
public Student(String name, String id, int age) {
setName(name);
setId(id);
setAge(age);
}
/**
*
* @return int
*/
public int getAge() {
return age;
}
/**
*
* @param age
*/
public void setAge(int age) {
if(age>0 && age <100)
this.age = age;
else
this.age = 10;
}
/**
*
* @return String
*/
public String getId() {
return id;
}
/**
*
* @param id
*/
public void setId(String id) {
this.id = id;
}
/**
*
* @return String
*/
public String getName() {
return name;
}
/**
*
* @param name
*/
public void setName(String name) {
this.name = name;
}
}




/**
* 随即存取Student类
* @author Sunny
* @version 1.0
*/
import java.io.RandomAccessFile;
import java.io.IOException;
public final class RandomAccessStudent extends Student {
//name域所占的字节数
private static final int NAME_SIZE = 30;
//id域所占的字节数
private static final int ID_SIZE = 30;
//该对象所占的字节数
public static final int SISE = NAME_SIZE + ID_SIZE + 4;
/**
* 构造函数
* @param name
* @param id
* @param age
*/
public RandomAccessStudent(String name, String id, int age) {
super(name, id, age);
}
/**
* 从随即文件读取一个Student类
* @param file
* @throws IOException
*/
public void read(RandomAccessFile file) throws IOException {
setName(readName(file));
setId(readId(file));
setAge(file.readInt());
}
//从随即文件中读取学生姓名
private String readName(RandomAccessFile file) throws IOException {
return readString(file, NAME_SIZE);
}
//从随即文件中读取学生ID
private String readId(RandomAccessFile file) throws IOException {
return readString(file, ID_SIZE);
}
//从随即文件中读取size字节长度的字符串
private String readString(RandomAccessFile file, int size) throws IOException {
char [] temp = new char[15];
for(int i = 0; i temp[i] = file.readChar();

return new String(temp).replace('\0', ' ');
}
/**
* 把对象写入随即文件
* @param file
* @throws IOException
*/
public void write(RandomAccessFile file) throws IOException {
writeName(file);
writeId(file);
file.writeInt(getAge());
}
//把name写入随即文件
private void writeName(RandomAccessFile file) throws IOException {
writeString(file, getName());
}
//把id写入随即文件
private void writeId(RandomAccessFile file) throws IOException {
writeString(file, getId());
}
//把给定的字符串写入随即文件
private void writeString(RandomAccessFile file, String content) throws IOException {
StringBuffer buffer = null;

if(content != null)
buffer = new StringBuffer(content);
else
buffer = new StringBuffer(15);

buffer.setLength(15);
file.writeChars(buffer.toString());
}
}




/**
* 测试随即文件的读取
* @author Sunny
* @version 1.0
*/
import java.io.*;
public class RandomAccessFileTest {
/**
* @param args
*/
public static void main(String[] args) throws IOException, FileNotFoundException {
File file = new File("random.dat");
if(file.exists())
file.createNewFile();
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");

RandomAccessStudent yang = new RandomAccessStudent("Sunny", "123456", 23);
RandomAccessStudent jin = new RandomAccessStudent("JJJJJ", "12345678", 24);

yang.write(randomAccessFile);
jin.write(randomAccessFile);

randomAccessFile.close();

RandomAccessFile read = new RandomAccessFile(file, "rw");

jin.read(read);
System.out.println(jin.getAge());

read.close();
}
}
上面仅仅是基本的IO简介,更多的知识就是去查看API来完善,还有在JDK1.4中又有java.nio.*这个包,它又是一种新的机制,如果有时间将介绍它的基本机制。

2007年2月19日星期一

Lucene Resource

在应用中加入全文检索功能——基于Java的全文索引引擎Lucene简介: http://www.chedong.com/tech/lucene.html
Apache Lucene:http://lucene.apache.org/java/docs/index.html
Java开源全文检索:http://www.open-open.com/32.htm
水木BBS上搜索引擎的论坛: http://www.newsmth.org/bbsdoc.php?board=SearchEngineTech

最近在看一本书叫做Ajax+Lucene构建搜索引擎,好像写的满好的,可以学到不少东东.

2007年2月15日星期四

新开的博客

寒假最近无事,于是开始玩玩Blog,下学期实验室也可能有个Blog 搜索的项目.这是我的有关于专注于CS技术的博客,现在的主题是搜索引擎的设计顺带Java技术的讨论,现在刚刚起步.想在这里和大家一起讨论一下Lucene和Java技术^_^现在刚开张的博客,比较简陋,以后会慢慢填料的.之前用过MSN spaces,感觉限制太多,虽然好用但是看不到一点技术细节,这也符合MS的一贯风格.最近开始喜欢玩玩Linux和Javascript,喜欢DIY的感觉.大家多捧捧场拉,多点击广告和下载FireFox,开了2天,好像帐户上显示有10美分拉-_-