Java文件处理与远程方法调用(RMI)
立即解锁
发布时间: 2025-08-17 02:29:09 阅读量: 1 订阅数: 5 

# Java 文件处理与远程方法调用(RMI)
## 1. Java 文件处理练习
### 1.1 读取姓氏和工资号文件
首先,使用文本编辑器或文字处理器创建一个文本文件,其中包含一系列姓氏和工资号(各至少五个),示例如下:
```plaintext
Smith
123456
Jones
987654
Jenkins
555555
```
然后编写一个 Java 程序,使用 `while` 循环从上述文本文件中读取值,并将它们显示在一个带有 “Surname” 和 “Payroll No.” 标题的表格中。
### 1.2 从标准输入读取
复制上述程序,重命名类,并修改相应的行,使程序从标准输入流接受输入(即使用围绕标准输入流 `System.in` 的 `Scanner`)。然后使用重定向将工资文本文件中的值输入到程序中(像之前一样显示内容)。
### 1.3 创建串行文本文件
编写一个简短的程序,创建一个仅包含两三个自选姓名的串行文本文件。编译并运行程序后,使用 MS - DOS 命令 `type`(或您平台的等效命令)显示文件内容,例如:
```plaintext
type names.txt
```
### 1.4 创建随机访问文件
使用文本编辑器或文字处理器创建一个文本文件,其中包含一系列五个姓氏和考试成绩,每个项目占一行,示例如下:
```plaintext
Smith
47
Jones
63
```
通过扩展以下代码,创建一个名为 `results.dat` 的随机访问文件,从标准输入流接受输入(通过 `Scanner` 对象),并从上述文本文件重定向输入。每个记录应包含学生姓氏和考试成绩。当所有记录都写入后,将文件指针重新定位到文件开头,然后依次读取每个记录,并将其内容显示在屏幕上。
```java
import java.io.*;
import java.util.*;
public class FileResults
{
private static final long REC_SIZE = 34;
private static final int SURNAME_SIZE = 15;
private static String surname;
private static int mark;
public static void main(String[] args)
throws IOException
{
/**********************************************
*** SUPPLY CODE FOR main! ***
**********************************************/
}
public static void writeString(
RandomAccessFile file, String text,
int fixedSize) throws IOException
{
int size = text.length();
if (size<=fixedSize)
{
file.writeChars(text);
for (int i=size; i<fixedSize; i++)
file.writeChar(' ');
}
else
file.writeChars(text.substring(
0,fixedSize));
}
public static String readString(
RandomAccessFile file, int fixedSize)
throws IOException
{
String value = "";
for (int i=0; i<fixedSize; i++)
value+=file.readChar();
return value;
}
}
```
### 1.5 读写 `Result` 对象
利用以下 `Result` 类,重复上述程序,这次读写 `Result` 类的对象。在显示读取的姓名和成绩时,必须使用 `Result` 类的方法。再次将初始输入重定向为来自您的文本文件。
```java
class Result implements Serializable
{
private String surname;
private int mark;
public Result(String name, int score)
{
surname = name;
mark = score;
}
public String getName()
{
return surname;
}
public void setName(String name)
{
surname = name;
}
public int getMark()
{
return mark;
}
public void setMark(int score)
{
if ((score>=0) && (score<=100))
mark = score;
}
}
```
### 1.6 创建 GUI 程序保存对象
使用相关类创建一个名为 `ChooseSaveFile.java` 的简单基于 GUI 的程序,该程序没有组件,但在 `main` 方法中创建自身的一个实例,并包含通常的窗口关闭代码(也在 `main` 方法中)。在类的构造函数中,声明并初始化一个包含三个 `Personnel` 对象的数组(如之前程序中所示),并使用 `ObjectOutputStream` 将数组中的对象写入文件。文件的名称和位置应由用户通过 `JFileChooser` 对象选择。
### 1.7 读取保存的对象
复制上述程序,将其重命名为 `ReadFile.java`,并修改代码以使用 `JFileChooser` 对象选择要读取的文件。使用 `JFileChooser` 对象从上述创建的文件中读取数据,并让程序使用 `Personnel` 类的 `getSurname` 方法显示所有保存了详细信息的员工的姓氏。
## 2. 远程方法调用(RMI)
### 2.1 RMI 概述
在分布式环境中,通常希望能够在远程对象上调用方法。RMI(Remote Method Invocation)提供了一种与平台无关的方式来实现这一点。在 RMI 下,显式编程流和套接字所需的网络细节消失了,对象位于远程这一事实对 Java 程序员几乎是透明的。一旦获得了对远程对象的引用,就可以像调用本地对象的方法一样调用该对象的方法。
### 2.2 基本 RMI 过程
RMI 的基本过程如下:
1. 服务器程序控制远程对象,将一个接口注册到命名服务中,使客户端程序可以访问该接口。接口包含服务器希望公开的对象方法的签名。
2. 客户端程序使用相同的命名服务以存根(stub)的形式获取对该接口的引用。存根实际上是远程对象的本地代理。
3. 在远程系统上,有另一个代理称为骨架(skeleton)。当客户端程序调用远程对象的方法时,看起来是直接在对象上调用该方法,但实际上是在存根中调用了等效的方法。存根将调用和任何参数转发到远程机器上的骨架。
4. 只有基本类型和实现了 `Serializable` 接口的引用类型可以用作参数(这些参数的序列化称为编组)。
5. 骨架接收到字节流后,将其转换回原始的方法调用和关联的参数(参数的反序列化称为解组)。最后,骨架在服务器上调用方法的实现。
以下是 RMI 调用方法的流程图:
```mermaid
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([客户端程序]):::startend -->|调用方法| B(存根):::process
B -->|转发调用和参数| C(骨架):::process
C -->|调用方法实现| D([服务器对象]):::startend
D -->|返回结果| C
C -->|返回结果| B
B -->|返回结果| A
```
### 2.3 实现细节
实现 RMI 客户端 - 服务器应用程序使用的包有 `java.rmi`、`java.rmi.server` 和 `java.rmi.registry`,但通常只需要显式使用前两个。基本步骤如下:
1. **创建接口**:接口应导入 `java.rmi` 包,并必须扩展 `Remote` 接口。接口定义必须指定要向客户端公开的方法的签名,该方法必须声明抛出 `RemoteException`。示例代码如下:
```java
import java.rmi.*;
public interface Hello extends Remote
{
public String getGreeting() throws RemoteException;
}
```
2. **定义实现类**:实现文件应导入 `java.rmi` 和 `java.rmi.server` 包。实现类必须扩展 `RemoteObject` 或其一个子类,通常扩展 `UnicastRemoteObject`。实现类必须实现接口,并为接口方法提供可执行的主体。还必须提供一个构造函数,该构造函数必须声明抛出 `RemoteException`。示例代码如下:
```java
import java.rmi.*;
import java.rmi.server.*;
public class HelloImpl extends UnicastRemoteObject
implements Hello
{
public HelloImpl() throws RemoteException
{
//No action needed here.
}
public String getGreeting() throws RemoteException
{
return ("Hello there!");
}
}
```
3. **创建服务器进程**:服务器创建实现类的对象,并使用 `Naming` 类的 `rebind` 方法将它们注册到命名服务(注册表)中。`rebind` 方法接受两个参数:一个包含远程对象名称的 URL 字符串和对远程对象的引用。示例代码如下:
```java
import java.rmi.*;
public class HelloServer
{
private static final String HOST = "localhost";
public static void main(String[] args)
throws Exception
{
//Create a reference to an
//implementation object...
HelloImpl temp = new HelloImpl();
//Create the string URL holding the
//object's name...
String rmiObjectName = "rmi://" + HOST + "/Hello";
//(Could omit host name here, since 'localhost'
//would be assumed by default.)
//'Bind' the object reference to the name...
Naming.rebind(rmiObjectName,temp);
//Display a message so
```
0
0
复制全文
相关推荐










